rapid js - An ORM-like Interface For Your Frontend Requests.

Getting Started

If you encounter any bugs, please report them on the github page.

What is rapid?

rapid.js is a fluent framework for rapidly building API wrappers, reusable base models, and interacting with APIs. Every project I built that required basic or extensive API requests seemed to repeat the same process: decide on a framework, download and configure it, and manually write my API calls time and time again. If I wanted to reuse any of those calls around different parts of the app, I'd have to continually extend or rewrite them. And if the routes changed I'd have to update them everywhere and it just became messy. I got tired of it. So, I wrote rapid.

rapid makes building API wrappers, reusable base models, and interacting with APIs super easy and well, rapid. There's almost no configuration required to get started but it's extremely configurable to fit any API.

Installation

npm i rapid.js --save

Usage

Out of the box rapid offers basic CRUD methods to make your requests: .create(), .find(), .update(), .destroy(). Imagine we have a blog post model that we want to perform these methods on. Normally, you'd need to define these endpoints one by one but with rapid they're built for you.

import Rapid from 'rapid.js';

var post = new Rapid({ modelName: 'post' });

post.find(1).then(function (response) {
    // GET => /api/post/1
});

post.create({ title: 'Rapidd is awesome!' }).then(...) // POST => /api/post/create

post.update(23, { title: 'Rapid* is awesome!' }).then(...) // POST => /api/post/23/update

post.destroy(1).then(...) // POST => /api/post/1/destroy

While this may seem quite trivial, rapid actually cuts out a large amount of time and repeating yourself. Without rapid, making these same requests can be repetitive. Take the below example that uses only a framework such as Axios alone (the backbone of rapid):

import axios from 'axios';

axios.get('/api/post/1').then(...)
axios.post('/api/post/create', { data: { title: 'Rapidd is awesome!' } }).then(...)
axios.post('/api/post/update', { data: { title: 'Rapid* is awesome!' } }).then(...)
axios.post('/api/post/1/destroy').then(...)

The above example will work just fine for basic requests. But what if all your requests share a common baseURL or API_KEY? And what if you have a dozen similar models that ultimately make the same basic CRUD routes? This is where rapid comes in. You can define these once and use them among multiple rapid models without having to repeat yourself.

See Also: find(), create(), update(), destroy()

Additional Methods

In addition to simple CRUD rapid has a few other helper methods: .id(), .all(), .findBy().

// perform requests on a model with a certain id
post.id(45).get('meta').then(...) // GET => /api/posts/45/meta
post.id(55).withParams({ background: 'blue' }).post('meta').then(...) // POST => /api/posts/45/meta

Rapid takes a primaryKey attribute in its config. If you were to provide one, .id() will also account for that.

var post = new Rapid({ modelName: 'Post', primaryKey: 'id' });

post.id(45).get('meta').then(...) // GET => /api/posts/id/45/meta
post.id(55).withParams({ background: 'blue' }).post('meta').then(...) // POST => /api/posts/id/45/meta

Lastly, .all() and .findBy() can be used to make simple requests to either find a model or collection by a key/value pair or to find all of a collection.

// find a model by a key
post.findBy('category', 'featured').then(...) // GET => /api/post/category/featured

// find a collection by a key
post.collection.findBy('category', 'featured').then(...) // GET => /api/posts/category/featured

// request all of a collection
post.withParams({ tag: 'awesome', limit: 20 }).all().then(...) // GET => /api/posts?tag=awesome&limit=20

See Also: id(), findBy(), all()

Requests

In addition to the above methods, you can make basic get(), post(), put(), patch(), head(), delete() requests. Each method takes the same parameter(s).

var gallery = new Rapid({ modelName: 'Gallery' });

gallery.get('tags').then(function (response) {
    // GET => /api/gallery/tags
})

gallery.id(45).get('photos/page/1').then(...)
    // GET => /api/gallery/45/photos/page/1

// the same result can be achieved by comma separating parameters
gallery.id(45).get('photos', 'page', 1).then(...)
    // GET => /api/gallery/45/photos/page/1

// GET request to the collection route
gallery.collection.get('recent')
    // GET => /api/galleries/recent

// using .post
gallery.id(34).post().then(...)
    // POST => /api/gallery/34

See Also: get(), post(), put(), patch(), head(), delete()

Parameters

With rapid, passing parameters is super easy for every request by using the .withParams() and .withParam().

// pass multiple parameters
post.collection.withParams({ limit: 20 }).findBy('category', 'featured').then(...)
    // GET => /api/posts/category/featured?limit=20

// or just a single parameter
post.collection.withParam('status', 'published').findBy('user', 'self').then(...)
     // GET => /api/posts/user/self?status=published

See Also: withParams(), withParam()

Routes

Many developers generally write their APIs with the concept of a `model` and a `collection`. Take the example a Photo `model`. You can make API requests to a single Photo /api/photo/1 but also maybe you want to request a `collection` of Photos /api/photos/tag/nature. Rapid is designed at its core to handle both of these scenarios by simply calling .model or .collection prior to a request.


var photo = new Rapid({ modelName: 'photo' });

// by default, the route will be model
photo.findBy('tag', 'featured'); // GET => /api/photo/tag/featured

// call the collection route
photo.collection.findBy('tag', 'featured'); // GET => /api/photos/tag/featured

Rapid also takes advantage of pluralize and will automatically generate a collection route based off a camel case modelName


var photoGallery = new Rapid({ modelName: 'PhotoGallery' });

photoGallery.findBy('tag', 'featured'); // GET => /api/photo-gallery/tag/featured

// call the collection route
photoGallery.collection.findBy('tag', 'featured'); // GET => /api/photo-galleries/tag/featured

You can change the defaultRoute and override the pluralizing as well as have complete customization of your routes through the configuration.

See Also: defaultRoute, routes

Custom Routes

Though rapid works its magic and makes your requests super simple with almost no configuration, you may find that it's not enough for places where you have a whole load of routes. This is where Custom Routes save the day!

Custom routes allow you define a list of routes containing a name, type of request, and of course, a url. It can either make a request for you, or just generate the path. It's up to you! Nonetheless, rapid helps!

The first step is really to define your routes like below:

const customRoutes = [
    {
        name: 'web_get_user_preferences',
        type: 'get',
        url: '/user/preferences',
    },

    {
        name: 'web_save_user_preferences',
        type: 'post',
        url: '/user/{id}/save/preferences'
    }
];

Next, initialize your routes and set a baseURL.

import customRoutes from './custom-routes';

const router = new Rapid({ customRoutes, baseURL: '/api' });

That's it! Now you can make a request or simply generate a url to pass to your own http service.

router.route('web_get_user_preferences').then((response) => {}); 
// GET => /api/user/preferences

router.route('web_save_user_preferences', { id: 12 }, /* { request data } */).then((response) => {}); 
// POST => /api/user/12/save/preferences

Below is an example of using your own http service:

import http from 'some-http-service';

const customRoutes = [
    {
        name: 'web_login',
        url: '/login'
    },

    {
        name: 'api_save_user_preferences',
        url: '/user/{id}/save/preferences'
    }
];

const rapid = new Rapid({ customRoutes, baseURL: '' });

rapid.generate('web_login')
// returns '/login'

// use your own service
http.post(rapid.generate('api_save_user_preferences', { id: 1 }), { data }).then()...

See Also: baseURL, generate, route

Axios

Under the hood rapid takes advantage of the promised-based framework axios. To better understand any api configuration have a look at their documentation. Though it would defeat the purpose of rapid can still access and use axios directly via this.api.

const photo = new Rapid({ modelName: 'photo' });

photo.api.get('/api/photos/1');

See Also: apiConfig

Extending Rapid

Base Models

Quite often, you may need want to have a base model that has common attributes such as a baseURL. With rapid, base models are effortless. The example below would allow for the same baseURL and API_KEY.

// Base.js
import Rapid from 'rapid.js';

class Base extends Rapid {
    boot () {
        this.baseURL = 'https://myapp.com/api';
        this.config.globalParameters = { key: 'MY_API_KEY' }
    }
}

export default Base;

And then just import your base model.

import Base from './Base';

var photo   = new Base({ modelName: 'Photo' }););
var gallery = new Base({ modelName: 'Gallery' });
var tag     = new Base({ modelName: 'Tag' });

photo.find(1)
    // GET => https://myapp.com/api/photo/1?key=MY_API_KEY

tag.collection.findBy('color', 'red')
    // GET => https://myapp.com/api/tags/color/red?key=MY_API_KEY

gallery.id(23).get('tags', 'nature')
    // GET => https://myapp.com/api/gallery/23/tag/nature?key=MY_API_KEY

When using the boot() method, you can override any of the normal config. However, when changing the baseURL, modelName, routeDelimeter, or caseSensitive variables, you must use the setters rather than referencing the config itself. This is because the routes need to be regenerated after those config variables are changed.

class Base extends Rapid {
    boot () {
        this.baseURL        = 'https://myapp.com/api';
        this.modelName      = 'SomeModel';
        this.routeDelimeter = '-';
        this.caseSensitive  = true;

        // any other config can be referenced like this
        this.config.globalParameters = { key: 'MY_API_KEY' }
    }
}

The Rapid Auth Model

Rapid offers a simple auth model that provides some basic auth routes out of the box. You can make new Auth model that will take all the same config as a rapid model in addition to the following auth options:

auth: {
    routes: {
        login    : 'login',   // a route to login a user
        logout   : 'logout',  // a route to logout a user
        auth     : 'auth',    // a route to check for auth
        register : 'register' // a route to check for auth
    },

    methods: {
        login    : 'post', // the method to use for login
        logout   : 'post', // the method to use for logout
        auth     : 'get',   // the method to use for auth
        register : 'post'  // the method to use for auth
    },

    modelPrefix: false // whether or not to prefix the model name in the requests
}

With only a modelName passed, you can get the following routes:

import { Auth } from 'rapid.js';

var user = new Auth({ modelName: 'User' });

user.login({ username: 'user', password: 'password' }).then(...) // config.auth.methods.login => /api/login
user.logout().then(...) // config.auth.methods.logout => /api/logout
user.check().then(...) // config.auth.methods.auth => /api/auth
user.register({ name: 'rapid', email: 'user@email.com', password: 'password' }).then(...) // config.auth.methods.register => /api/register

// all regular methods are still available too
user.find(1).then(...) // GET => /api/user/1

Like a basic rapid model, you can customize the auth routes and methods to fit your API like so:

var user = new Auth({
    modelName: 'User',
    auth: {
        routes: {
            auth: 'authenticate',
            register: 'sign-up'
        },
        modelPrefix: true
    }
});

user.login({ username: 'user', password: 'password' }).then(...) // config.auth.methods.login => /api/user/login
user.logout().then(...) // config.auth.methods.logout => /api/user/logoout
user.check().then(...) // config.auth.methods.auth => /api/user/authenticate
user.register({ name: 'rapid', email: 'user@email.com', password: 'password' }).then(...) // config.auth.methods.register => /api/user/sign-up

Making an API Wrapper

Rapid allows for you to create a wrapper for your endpoints, rapidly. When extending rapid, you can override any of the config in the boot() method. Take the example endpoints below:

  • https://mysite.com/api/gallery/tagsearch/{xml|json}
  • https://mysite.com/api/gallery/categorysearch/{xml|json}
  • https://mysite.com/api/gallery/{id}/{xml|json}
  • https://mysite.com/api/gallery/{id}/{tags|categories}/{xml|json}

The class below demonstrates just how effortlessly you can write a wrapper for the above endpoints.

import Rapid from 'rapid.js';

class GalleryWrapper extends Rapid {
    boot () {
        this.baseURL = 'https://mysite.com/api';
        this.modelName = 'Gallery';
    }

    tagSearch (query) {
        return this.append('tagsearch').withParam('query', query);
    }

    categorySearch (query) {
        return this.append('categorysearch').withParam('query', query);
    }

    taxonomy (taxonomy) {
        return this.append(taxonomy);
    }

    json () {
        return this.append('json');
    }

    xml () {
        return this.append('xml');
    }
}

export default new GalleryWrapper({
    globalParameters: {
      key: 'YOUR_API_KEY'
    }
});

Now you can easily interact with the API like this:

import GalleryWrapper from './wrappers/GalleryWrapper';

GalleryWrapper.tagSearch('orange').json().get().then(...);
    // GET => https://mysite.com/api/gallery/tagsearch/json?query=orange&key=YOUR_API_KEY

GalleryWrapper.categorySearch('nature').xml().get().then(...);
    // GET => https://mysite.com/api/gallery/categorysearch/xml?query=nature&key=YOUR_API_KEY

GalleryWrapper.id(45).taxonomy('tags').json().get().then(...);
    // GET => https://mysite.com/api/gallery/45/tags/json?key=YOUR_API_KEY

GalleryWrapper.id(45).taxonomy('categories').xml().get().then(...);
    // GET => https://mysite.com/api/gallery/45/categories/xml?key=YOUR_API_KEY

In theory, this would work to build a wrapper around any public API as well.

See Also: url(), prepend(), append()

Config Builder

Methods

find(id)

Makes a GET Request on the model route for a given id.
Arguments:

id {int}

Returns: Promise
Example:
const post = new Rapid({ modelName: 'post' });

post.find(1).then(function (response) {
    // GET => /api/post/1
});

If you want to include the primaryKey value in the url, you can set it in your config like so:

const post = new Rapid({ modelName: 'post', primaryKey: 'id' });

post.find(1) // GET => /api/post/id/1

findBy(key, value)

Makes a GET Request on the model route for a key/value pair.
Arguments:

key {string} - The key to search by in the url. /api/post/`key`/value

value {string|int} - The value to search by in the url. /api/post/key/`value`

Returns: Promise
Example:
const post = new Rapid({ modelName: 'post' });

post.findBy('category', 'featured').then(function (response) {
    // GET => /api/post/category/featured
});

post.collection.findBy('category', 'featured').then(function (response) {
    // GET => /api/posts/category/featured
});

all()

Makes a GET Request on the collection route.
Returns: Promise
Example:
const post = new Rapid({ modelName: 'post' });

post.all().then(function (response) {
    // GET => /api/posts
});

post.withParams({ category: 'featured', limit: 20 }).all().then(function (response) {
    // GET => /api/posts?category=featured&limit=20
});

update(id|data, data)

Makes a config.methods.update Request.
Arguments:

id|data {int|array|object} - The id to be passed to the update request or the data to be passed to the update request.

data {array|object} - The data to be passed to the update request.

Returns: Promise
Example:

var post = new Rapid({ modelName: 'Post' });

post.update(1, { title: 'An updated title' }).then(...) // config.methods.update => /api/post/1/[config.suffixes.update]

// alternatively you can send over only data if you'd prefer
post.update({ id: 1, title: 'An updated title' }).then(...) // config.methods.update => /api/post/[config.suffixes.update]

save()

Alias of update().
Returns: Promise

destroy(id)

Makes a config.methods.destroy Request to the config.suffixes.destroy route. If you wanted to send a request to a route that would destroy/delete your model, this would be how.
Arguments:

id {int} - The id to be passed to the destroy url. In other words, the id of the model you'd like the destroy. /api/photo/`1`/destroy

Returns: Promise
Example:
const photo = new Rapid({ modelName: 'Photo' });

if(confirm("Are you sure you wanna delete this photo?")) {
    photo.destroy(1234).then(...) => // config.methods.destroy => /api/photo/1234/[config.suffixes.destroy]
}

restore(id)

Makes a config.methods.restore Request to the config.suffixes.restore route. If you wanted to send a request to a route that would restore your model, this would be how.
Arguments:

id {int} - The id to be passed to the restore url. In other words, the id of the model you'd like the restore. /api/photo/`1`/restore

Returns: Promise

create(data)

Makes a config.methods.create Request.
Arguments:

data {array|object} - The data to be passed to the create request.

Returns: Promise
Example:

var photoGallery = new Rapid({ modelName: 'PhotoGallery' });

photoGallery.create({ title: 'An Awesome Gallery!' }).then(...)
    // config.methods.create => /api/photo-galleries/[config.suffixes.create]

route(name, routeParams, requestParams)

Makes a request to the route with a given name and request type.
Arguments:

name {string} - The name of the route to send the request to.

routeParams {object} - Any interpolated params in the request string. (e.g. `/api/user/{id}`.

requestParams {object} - Any params/data sent over with the request.

Returns: Promise
Example:

const customRoutes = [
    {
        name: 'web_get_user_preferences',
        type: 'get',
        url: '/user/preferences',
    },

    {
        name: 'web_save_user_preferences',
        type: 'post',
        url: '/user/{id}/save/preferences'
    }
];

const router = new Rapid({ customRoutes, baseURL: '/api' });

This method allows you to make requests to routes simply by calling it by name. You can define the name, type, and url and rapid will do the rest. The below example fires a get and post request to the given routes.


router.route('web_get_user_preferences').then((response) => {}); 
// GET => /api/user/preferences

router.route('web_save_user_preferences', { id: 12 }, /* { request data } */).then((response) => {}); 
// POST => /api/user/12/save/preferences

generate(name, routeParams)

Generates the route for the given route name including any interpolated variables passed.
Arguments:

name {string} - The name of the route to send the request to.

routeParams {object} - Any interpolated params in the request string. (e.g. `/api/user/{id}`.

Returns: string
Example:

import http from 'some-http-service';

const customRoutes = [
    {
        name: 'web_login',
        url: '/login'
    },

    {
        name: 'web_user_profile',
        url: '/user/profile/{username}'
    },

    {
        name: 'api_save_user_preferences',
        url: '/user/{id}/save/preferences'
    },
];

const rapid = new Rapid({ customRoutes, baseURL: '' });

rapid.generate('web_login')
// returns '/login'

// use your own service
http.post(rapid.generate('api_save_user_preferences'), { id: 1 }).then()...

Similar to route, generate, well, generates a url based off a given name passed. However, it won't actually make the request for you. This is useful when using your own http service or appending urls to links. Below is an example of using it with something like Vue.


    <template>
        <div class="nav-component">
            <a :href="router.generate('web_login')">Login</a>
            <a :href="router.generate('web_user_profile', { username: 'drew' })">Profile</a>
        </div>
    </template>

    <!-- renders to -->

    <div class="nav-component">
        <a href="/login">Login</a>
        <a href="/user/profile/drew">Profile</a>
    </div>

id(id)

Prefixes an id on the request.
Arguments:

id {int} - The id to be passed to the request.

Returns: rapid instance
Example:

var post = new Rapid({ modelName: 'Post' });

post.id(45).get('meta').then(...); // GET => /api/post/45/meta

If you set a primaryKey in your config you it will also prefix that.


var post = new Rapid({ modelName: 'Post', primaryKey: 'id' });

post.id(45).get('meta').then(...); // GET => /api/post/id/45/meta

url(urlParams, prepend, overwrite)

Builds the url for the request. Useful when extending rapid.
Arguments:

urlParams {string|array} - The parameters to set in the url.

prepend {boolean} - Whether or not to prepend | Default: false

overwrite {boolean} - Whether or not to overwrite any other urlParams | Default: false

Returns: rapid instance
Example:

class Gallery extends Rapid {
    boot () {
        this.modelName = 'Gallery';
    }

    slug (slug) {
        return this.url(slug, true);
    }

    json () {
        return this.url('json');
    }

    findBySlugOnly (name) {
        return this.url(name, false, true);
    }
}

var gallery = new Gallery();

gallery.slug('nature-album').json().get();
    // GET => /api/nature-album/json

gallery.json().slug('nature-album').get();
    // GET => /api/nature-album/json

gallery.json().slug('nature-album').findBySlugOnly('new-slug').get();
    // GET => /api/new-slug

Because slug() has prepend set to true, the order does not matter. It will always be prepended to the url and both examples produce the same result. findBySlugOnly() overwrites the entire url because overwrite set to true.

append(urlParams)

Appends a string or array to the url for the request. This is the equivalent to this.url('something', true). Useful when extending rapid.
Arguments:

urlParams {string|array} - The parameters to set in the url.

Returns: rapid instance

prepend(urlParams)

Prepends a string or array to the url for the request. Appends a string or array to the url for the request. This is the equivalent to this.url('something'). Useful when extending rapid.
Arguments:

urlParams {string|array} - The parameters to set in the url.

Returns: rapid instance

get(...urlParams)

Make a GET request.
Arguments:

...urlParams {string} - A single string or comma delimeted values to build the request url

Returns: promise
Example:
const photo = new Rapid({ modelName: 'Photo' });

photo.get().then(function (response) {
    // GET => /api/photo
});

photo.get('tags').then(...) // GET => /api/photo/tags

photo.collection.get('tag', 'hiking', 'recent').then(...) // GET => /api/photos/tag/hiking/recent

photo.collection.get('tag', 'hiking', 'recent', 'page', 2).then(...) // GET => /api/photos/tag/hiking/recent/page/2

post(...urlParams)

Make a POST request.
Arguments:

...urlParams {string} - A single string or comma delimeted values to build the request url

Returns: promise
Example:
const gallery = new Rapid({ modelName: 'Gallery' });

gallery.id(23).withParams({ title: 'Appalachian Trail' }).post().then(function (response) {
    // POST => /api/gallery/23
});

gallery.withParams({ title: 'My Thru-Hike Photos' }).post('slug', 'appalachian-trail').then(...)
    // POST => /api/gallery/slug/appalachian-trail

put(...urlParams)

Make a PUT request.
Arguments:

...urlParams {string} - A single string or comma delimeted values to build the request url

Returns: promise
Example:
const tag = new Rapid({ modelName: 'Tag' });

tag.id(45).withParam('name', 'hiking').put().then(function (response) {
    // PUT => /api/tag/45
});

patch(...urlParams)

Make a PATCH request.
Arguments:

...urlParams {string} - A single string or comma delimeted values to build the request url

Returns: promise
Example:
const category = new Rapid({ modelName: 'Category' });

category.id(45).withParam('name', 'featured').patch().then(function (response) {
    // PATCH => /api/tag/45
});

head(...urlParams)

Make a HEAD request.
Arguments:

...urlParams {string} - A single string or comma delimeted values to build the request url

Returns: promise

delete(...urlParams)

Make a DELETE request.
Arguments:

...urlParams {string} - A single string or comma delimeted values to build the request url

Returns: promise
Example:
const category = new Rapid({ modelName: 'Category' });

category.id(56).delete().then(function (response) {
    // DELETE => /api/tag/56
});

withParams(params)

Send a set of params with the request.
Arguments:

params {object} - The params to be sent over

Returns: rapid instance
Example:
const gallery = new Rapid({ modelName: 'Gallery' });

gallery.collection.withParams({ page: 1, order: 'asc' }).get('tags').then(...)
    // GET => /api/galleries/tags?page=1&order=asc

// withParams can be chained and used with all CRUD methods
gallery.withParams({ title: 'My Thru-Hike Photos' }).update().then(...)
    // config.methods.update => /api/gallery/slug/appalachian-trail

withParam(key, value)

Send a single param with the request.
Arguments:

key {string} - The key/name of the parameter

value {string|object|array} - The value of the parameter

Returns: rapid instance
Example:
const gallery = new Rapid({ modelName: 'Gallery' });

gallery.collection.withParam('page', 1).get('tags').then(...)
    // GET => /api/galleries/tags?page=1

gallery.withParam('title', 'My Thru-Hike Photos').update().then(...)
    // config.methods.update => /api/gallery/slug/appalachian-trail

withOptions(options)

Send a set of options with the request.
Arguments:

options {object} - The options to be sent over

Returns: rapid instance
Example:

See Axios for more info on the options that may be passed.

const gallery = new Rapid({ modelName: 'Gallery' });

gallery.collection.withOptions({ maxRedirects: 5, maxContentLength: 2000 }).get('tags').then(...)
    // GET => /api/galleries/tags

withOption(key, value)

Send a single option with the request.
Arguments:

key {string} - The key/name of the option

value {string|object|array} - The value of the option

Returns: rapid instance
Example:

See Axios for more info on the options that may be passed.

const gallery = new Rapid({ modelName: 'Gallery' });

gallery.collection.withOption('maxRedirects', 5).get('tags').then(...)
    // GET => /api/galleries/tags

withData(data)

Send over both params and headers in one method.
Arguments:

data {object} - The data (params, headers) to be sent over

Returns: rapid instance
Example:

In the example below, using data() allows both params and options to be sent in the same method. See Axios for more info on the options that may be passed.

const gallery = new Rapid({ modelName: 'Gallery' });

gallery.id(23).withData(params: { title: 'Appalachian Trail' }, options: { responseType: 'json' }).post().then(function (response) {
    // POST => /api/gallery/23
});

Configuration

afterRequest

Type: function
A method that fires each time after a request is made. Note: this is an event that is fired after each request and not how you would retrieve the data from each individual request.
Default:

afterRequest (response) {

}

Example:
Imagine that every request you make returns a field called `message` along with some other data like so:
{
    "message": "Settings saved!",
    "success": true,
    "someData": {}
}
The following config would alert a message with that response on each request.
const settings = new Rapid({
    modelName: 'settings',
    afterRequest (response) {
        alert(response.data.message);
    }
});

settings.save({}).then((response) =>
    // afterRequest would fire an alert("Settings Saved!")
    // and you can still do whatever you want with the rest of the data
});

allowedRequestTypes

Type: array
If you only want to allow certain request types, you can do so here.
Default: ['get', 'post', 'put', 'patch', 'head', 'delete']

apiConfig

Type: object
Rapid takes advantage of the awesome framework, axios. This is any configuration that you'd like to pass to `axios`.
Default: {}
Example:
const fish = new Rapid({
    modelName: 'fish',
    apiConfig: {

    }
})
You can also access axios config by doing the following:
window.axios = axios;
window.axios.defaults.headers.common = {
    'X-Requested-With': 'XMLHttpRequest',
};

baseURL

Type: string
The base url for your api.
Default: 'api'
Example:

beforeRequest

Type: function
A method to fire before each request is sent.
Default:

beforeRequest (type, url) {

}

caseSensitive

Type: boolean
If for some reason you need to keep your urls case sensitive you can do so by setting this to true.
Default: false
Example:
By default, routes would be:
myModel.find(1) // => GET /api/my-model/1
myModel.all() // => GET /api/my-models
Notice below that the urls will have case sensitive model and collection routes.
const myModel = new Rapid({
    modelName: 'MyModel',
    caseSensitive: true
});

myModel.find(1) // => GET /api/MyModel/1
myModel.all() // => GET /api/MyModels

customRoutes

Type: array
An array of custom routes to be passed to rapid.
Default: []

debug

Type: boolean
If set to true, this will enable the debugger and all requests will be logged in the console and not actually made. See debugging for more info.
Default: false

defaultRoute

Type: string
There are two routes generated by default: `model` and `collection`. By default `model` is set.
Default: model
Example:
If you were to call a non route-specific method such as .findBy() it would use the `model` route.
const post = new Rapid({
    modelName: 'post'
});

post.findBy('key', 'value') // => GET /api/post/key/value
post.collection.findBy('key', 'value') // => GET /api/posts/key/value
Setting the default route to collection would set collection to the default route instead:
const post = new Rapid({
    modelName: 'post',
    defaultRoute: 'collection'
});

post.findBy('key', 'value') // => GET /api/posts/key/value
post.model.findBy('key', 'value') // => GET /api/post/key/value

extension

Type: string
An extension to be appended to every request.
Default: ''
Example:
const issues = new Rapid({
    modelName: 'issues',
    extension: 'json'
});

issues.get() // => /api/issues.json
issues.find(123) // => /api/issues/123.json

globalParameters

Type: object
Global parameters to be sent with every request such as an API_KEY.
Default: {}

methods

Type: object
The request methods to be used for create(), update(), and destroy(). If you want to override any of them, you can here.
Default:

{
    create  : 'post',
    update  : 'post',
    destroy : 'post',
    restore : 'post'
}

modelName

Type: string
The model name for the rapid model. This will determine the routes for both models and collections. The collection route will be generated as the plural version of this. For instance if you put `gallery` the collection route would become `galleries`. Using camel case will result in a delimited route as defined in `routeDelimeter`
Default: ''
Example:
const gallery = new Rapid({
    modelName: 'gallery'
});

gallery.findBy('tag', 'featured') // => /api/posts/gallery/tag/featured
gallery.collection.findBy('tag', 'featured') // => /api/posts/galleries/tag/featured

// using a camel case name
const gallery = new Rapid({
    modelName: 'PhotoGallery'
});

gallery.findBy('tag', 'featured') // => /api/posts/photo-gallery/tag/featured
gallery.collection.findBy('tag', 'featured') // => /api/posts/photo-galleries/tag/featured

onError

Type: function
The API request returns a promise. All errors thrown from the request's Promise.catch() method will be passed into this method.
Default:

onError (error) {

}

primaryKey

Type: string
The primary key to be used in the url.
Default: ''
Example:
Without using a primaryKey requests would look like:
post.find(1) // => GET /api/post/1
post.update(123) // => POST /api/post/123/update
post.destroy(987) // => POST /api/post/987/destroy
With the following config you'll notice the primaryKey `id` is included in the urls
const post = new Rapid({
    modelName: 'post',
    primaryKey: 'id',
});

post.find(1) // => GET /api/post/id/1
post.update(123, {}) // => POST /api/post/id/123/update
post.destroy(987) // => POST /api/post/id/987/destroy

routeDelimeter

Type: string
The delimeter for route model/collection names.
Default: -

routes

Type: object
By default, rapid will generate routes based off the modelName config attribute. If you want to override one or the other, you can do so here.
Default:

{
    model      : '',
    collection : ''
}

suffixes

Type: object
The suffixes for the create(), update(), and destroy() methods. If you want to override any of them, you can here.
Default:

{
    create  : 'create',
    update  : 'update',
    destroy : 'destroy',
    restore : 'restore'
}

Example:
const fruit = new Rapid({
    modelName: 'fruit',
    {
        create  : 'new',
        update  : 'save',
        destroy : 'delete',
    }
});

fruit.create({}) // => /api/fruit/new
fruit.update(1, {}) // => /api/fruit/1/save
fruit.destroy(1) // => /api/fruit/1/delete

trailingSlash

Type: boolean
Whether or not to append a trailing slash to API urls.
Default: false