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.
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.
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
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
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()
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
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()...
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
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' }
}
}
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
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.
id
{int}
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
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`
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
});
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
});
config.methods.update
Request.
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.
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]
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.
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
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]
}
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.
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
config.methods.create
Request.
data
{array|object}
- The data to be passed to the create request.
var photoGallery = new Rapid({ modelName: 'PhotoGallery' });
photoGallery.create({ title: 'An Awesome Gallery!' }).then(...)
// config.methods.create => /api/photo-galleries/[config.suffixes.create]
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.
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
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}`
.
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
{int}
- The id to be passed to the request.
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
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
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
.
this.url('something', true)
. Useful when extending rapid.
urlParams
{string|array}
- The parameters to set in the url.
this.url('something')
. Useful when extending rapid.
urlParams
{string|array}
- The parameters to set in the url.
...urlParams
{string}
- A single string or comma delimeted values to build the request url
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
...urlParams
{string}
- A single string or comma delimeted values to build the request url
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
...urlParams
{string}
- A single string or comma delimeted values to build the request url
const tag = new Rapid({ modelName: 'Tag' });
tag.id(45).withParam('name', 'hiking').put().then(function (response) {
// PUT => /api/tag/45
});
...urlParams
{string}
- A single string or comma delimeted values to build the request url
const category = new Rapid({ modelName: 'Category' });
category.id(45).withParam('name', 'featured').patch().then(function (response) {
// PATCH => /api/tag/45
});
...urlParams
{string}
- A single string or comma delimeted values to build the request url
...urlParams
{string}
- A single string or comma delimeted values to build the request url
const category = new Rapid({ modelName: 'Category' });
category.id(56).delete().then(function (response) {
// DELETE => /api/tag/56
});
params
{object}
- The params to be sent over
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
key
{string}
- The key/name of the parameter
value
{string|object|array}
- The value of the parameter
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
options
{object}
- The options to be sent over
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
key
{string}
- The key/name of the option
value
{string|object|array}
- The value of the option
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
data
{object}
- The data (params, headers) to be sent over
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
});
function
afterRequest (response) {
}
`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
});
array
['get', 'post', 'put', 'patch', 'head', 'delete']
object
`axios`
.
{}
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',
};
function
beforeRequest (type, url) {
}
boolean
true
.
false
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
boolean
false
string
`model`
and `collection`
. By default `model`
is set.
model
.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
string
''
const issues = new Rapid({
modelName: 'issues',
extension: 'json'
});
issues.get() // => /api/issues.json
issues.find(123) // => /api/issues/123.json
object
{}
object
create()
, update()
, and destroy()
. If you want to override any of them, you can here.
{
create : 'post',
update : 'post',
destroy : 'post',
restore : 'post'
}
string
`gallery`
the collection route would become `galleries`
. Using camel case will result in a delimited route as defined in `routeDelimeter`
''
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
function
Promise.catch()
method will be passed into this method.
onError (error) {
}
string
''
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
object
modelName
config attribute. If you want to override one or the other, you can do so here.
{
model : '',
collection : ''
}
object
create()
, update()
, and destroy()
methods. If you want to override any of them, you can here.
{
create : 'create',
update : 'update',
destroy : 'destroy',
restore : 'restore'
}
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