README
VezaJS
Promise based HTTP RESTful API resources modeler for the browser.
Translations
Introduction
One of the main features of a RESTful API, acording to RESTful API Strategy, is that it's resources may be nested: "That is, the URIs may reflect that one resource is nested within another like in this made-up example: http://greatvalley.edu/example-app/courses/2305/sections/2465 (where section '2465' is a nested resource under course 2305)".
This is a good feature that tells us how may be a resource model for consumtion, because as we can see, "courses" and "sections" are static parts, in the mean time that "2305" and "2465" are dynamic parts of the resource.
Besides it's important to mention that any RESTful API should response different, depending on the HTTP method used (POST, GET, PATCH, etc...), and may or may not need params to send, for example in order to filter, order or create new data inside our API database.
VezaJS is a JavaScript based library which main aim is to define all your models only once, in order that you could use them all over your frontend app.
Starting
Pre-requisites
- node 10+
- npm 6+
Installation
Install VezaJS through npm
$ npm install --save vezajs
Import VezaJS inside your app:
import { VezaJS } from "vezajs";
Usage
Initializating VezaJS
In order to explain how to use VezaJS, let's define some fake resources for an API that we want to model:
- Our API is under the link "https://www.your-api.com/".
- We have three resources on our API:
- "https://www.your-api.com/user/$user_id", which is defined to interact with all (or one) existent users.
- "https://www.your-api.com/user/$user_id/contact/$contact_id", which is defined to interact with all (or one) contacts nested to a defined user.
- "https://www.your-api.com/user/$user_id/contact/$contact_id/phone/$phone_id", which is defined to interact with all (or one) phones of a contact nested to a defined user.
So let's code:
VezaJS({
name: "yourApiModeler",
token: {
name: "accessToken",
value: "asodug2312pu312pu3_asodq231"
},
url: "https://www.your-api.com/"
});
Let's take a look into previous code. First, we must pass all VezaJS params:
param | description | required | example |
---|---|---|---|
name | The name of our model creator | yes | "yourApiModeler" |
token | VezaJS can handle with an Authorization token if your API is protected | no | { name: "accessToken", value: "asodug2312pu312pu3_asodq231" } |
token.name | The name of the token that will be appended to your model's URL | yes (if token is defined) | "accessToken" |
token.value | The value of the token that will be appended to your model's URL | yes (if token is defined) | "asodug2312pu312pu3_asodq231" |
url | The link where your API stands. This will be used to prepend all your models | yes | "https://www.your-api.com/" |
Using VezaJS for model definition
It's important to know that VezaJS is a Promise, so, continuing with our example, you could use it like:
let user = null,
userContact = null,
userContactPhone = null;
VezaJS({
name: "yourApiModeler",
token: {
name: "accessToken",
value: "asodug2312pu312pu3_asodq231"
},
url: "https://www.your-api.com/"
}).then(modelers => {
user = modelers.yourApiModeler.setModel("user");
userContact = modelers.yourApiModeler.setModel([ "user", "contact" ]);
userContactPhone = modelers.yourApiModeler.setModel([ "user", "contact", "phone" ]);
}).catch(err => console.log(err));
Let's take a look into previous code. First, we initialize VezaJS, next the "then" method for the Promise pass a variable (we defined it as "modelers"). Then, this "modelers" variable is used to define all our models, by calling our previous modeler called "yourApiModeler". Every API modeler has the following methods:
name | description | Initializator params |
---|---|---|
setModel | method that allows you to define all your API models, that receive the "static" part of your API resource | array OR string |
getToken | method that returns the token of your modeler configuration | none |
Requesting with your models
Once we've defined all our models, it's important to know that right now VezaJS has support for four HTTP methods:
- GET
- POST
- PATCH
- DELETE
GET (VezaJS's get method)
...
user = modelers.yourApiModeler.setModel("user");
user.get({}).then(data => console.log(data)).catch(err => console.log(err));
user.get({
delimiters: 10,
responseType: "blob"
}).then(data => console.log(data)).catch(err => console.log(err));
user.get({
params: {
"order": "age",
"name": "Ort"
}
}).then(data => console.log(data)).catch(err => console.log(err));
...
Once we've defined all our models, we can start to deliver all our needed requests. On previous example, we've made three GET requests:
- The first one is receiving an empty Object, that means we are making a GET request to "https://www.your-api.com/user?accessToken=asodug2312pu312pu3_asodq231".
- The second is receiving an Object with delimiters = 10, and responseType = "blob", that means we are making a GET request to "https://www.your-api.com/user/10?accessToken=asodug2312pu312pu3_asodq231", and we want to receive our responseType as a blob.
- The third is receiving an Object with some params that means we are making a GET request to "https://www.your-api.com/user?order=age&name=Ort&accessToken=asodug2312pu312pu3_asodq231".
Let's see some other examples:
...
userContactPhone = modelers.yourApiModeler.setModel([ "user", "contact", "phone" ]);
userContactPhone.get({
delimiters: [ 1, 500 ]
params: {
"page": "7",
"perPage": "35"
}
}).then(data => console.log(data)).catch(err => console.log(err));
...
On previous request we are sending delimiters and params to "userContactPhone" model, that means we are making a GET request to "https://www.your-api.com/user/1/contact/500/phone?page=7&perPage=35&accessToken=asodug2312pu312pu3_asodq231".
So let's talk about GET method features:
feature | description | default | supporting typeof |
---|---|---|---|
delimiters | Refers to the "dynamic" part to your API resource | undefined | array OR integer OR string |
params | Refers to the query params appended to the API resource | undefined | object |
responseType | responseType supported for JavaScript requests | "json" | string |
POST (VezaJS's post method)
...
userContact = modelers.yourApiModeler.setModel([ "user", "contact" ]);
userContact.post({
delimiters: [ 12 ],
requestJson: true,
params: {
"address": "Saint street 177",
"active": false,
"first_name": "Roberto",
"last_name": "Magallanez"
}
}).then(data => console.log(data)).catch(err => console.log(err));
...
On previous request we are sending delimiters and params to "userContact" model, that means we are making a POST request to "https://www.your-api.com/user/12/contact?accessToken=asodug2312pu312pu3_asodq231". In this case, the params are used as the POST body, and the requestJson node implies that we want to send it as an "application/json" content.
So let's talk about POST method features:
feature | description | default | supporting typeof |
---|---|---|---|
delimiters | Refers to the "dynamic" part to your API resource | undefined | array OR integer OR string |
params | Refers to the body params of the request | undefined | object |
responseType | responseType supported for JavaScript requests | "json" | string |
requestJson | TRUE for "application/json"; FALSE for "application/x-www-form-urlencoded" | false | boolean |
PATCH (VezaJS's patch method)
...
userContact = modelers.yourApiModeler.setModel([ "user", "contact" ]);
userContact.patch({
delimiters: [ 12, 210 ],
params: {
"active": true
}
}).then(data => console.log(data)).catch(err => console.log(err));
...
On previous request we are sending delimiters and params to "userContact" model, that means we are making a PATCH request to "https://www.your-api.com/user/12/contact/210?accessToken=asodug2312pu312pu3_asodq231". In this case, the params are used as the PATCH body, and the requestJson node is not defined, this implies that we want to send it as an "application/x-www-form-urlencoded" content.
So let's talk about PATCH method features:
feature | description | default | supporting typeof |
---|---|---|---|
delimiters | Refers to the "dynamic" part to your API resource | undefined | array OR integer OR string |
params | Refers to the body params of the request | undefined | object |
responseType | responseType supported for JavaScript requests | "json" | string |
requestJson | TRUE for "application/json"; FALSE for "application/x-www-form-urlencoded" | false | boolean |
DELETE (VezaJS's remove method)
...
userContact = modelers.yourApiModeler.setModel([ "user", "contact" ]);
userContact.remove({
delimiters: [ 12, 210 ]
}).then(data => console.log(data)).catch(err => console.log(err));
...
On previous request we are sending delimiters to "userContact" model, that means we are making a DELETE request to "https://www.your-api.com/user/12/contact/210?accessToken=asodug2312pu312pu3_asodq231".
So let's talk about DELETE method features:
feature | description | default | supporting typeof |
---|---|---|---|
delimiters | Refers to the "dynamic" part to your API resource | undefined | array OR integer OR string |
params | Refers to the body params of the request | undefined | object |
responseType | responseType supported for JavaScript requests | "json" | string |
requestJson | TRUE for "application/json"; FALSE for "application/x-www-form-urlencoded" | false | boolean |
Data response definition
After we make a request, we'll receive our data defined through the following nodes (it's format will depend on the "responseType" param):
node | description | type of data |
---|---|---|
headers | Headers of the response | Object |
status | Request status | number |
statusText | Request status as text | string |
getHeader | Method to request an specific header (needs an string argument) | Function |
data | All data related to response | Object |
dataType | Response type | string |
url | Response url | string |
Support for multiple modelers
You can define one or more modelers in VezaJS, for example when you want to consume n number of API's with diferent URL's. Let's see an example:
let user = null,
userContact = null;
let store = null,
storeElement = null;
VezaJS([
{
name: "yourApiUserModeler",
token: {
name: "accessToken",
value: "asodug2312pu312pu3_asodq231"
},
url: "https://www.your-api-user.com/"
},
{
name: "yourApiStoreModeler",
url: "https://www.your-api-store.com/"
}
]).then(modelers => {
user = modelers.yourApiUserModeler.setModel("user");
userContact = modelers.yourApiUserModeler.setModel([ "user", "contact" ]);
store = modelers.yourApiStoreModeler.setModel("store");
storeElement = modelers.yourApiStoreModeler.setModel([ "store", "element" ]);
}).catch(err => console.log(err));
And all the previous features are available in every modeler and model defined in the last example. In this case, the "yourApiUserModeler" modeler is going to work under token Authorization, meanwhile the "yourApiStoreModeler" modeler is for public usage.
Versioning
For further information, read more about this on semver.
Authors
- Marcos Jesús Chávez V - onca-vega
License
MIT license.