An Axios Based Package and Promise based HTTP client for the browser and node.js.
Axios is an awesome library, and provides you with great features, however, there are some missing features that is needed in most of our real world projects:
For demonstration purpose only, we may use React syntax for illustration when dealing with forms.
- Mongez Http
- Why not using axios directly instead?
- Table of contents
- Installation
- Initializing Configurations
- Basic Usage
- Restful Endpoint
- Aborting Requests
- Acceptable Http Data
- Form and FormData to Json Converter
- Setting Authorization Header
- Converting Put requests to Post requests
- Http Configurations List
- HTTP Events
- Change Log
- TODO
yarn add @mongez/http
Or
npm i @mognez/http
Let's start with our first step, defining http configuration.
import { setHttpConfigurations } from '@mongez/http';
setHttpConfigurations({
baseUrl: 'https://sitename.com/api',
});From this step we can now use our relative paths to our base url we set in our configurations.
We'll go later with the rest of our configurations, now let's start using it.
// src/services/auth.ts
import endpoint from '@mongez/http';
export function login(data: object) {
return endpoint.post('/login', data);
}
// in some component base file
// some-component.ts
const onSubmit = e => {
const data = {
email: 'hassanzohdy@gmail.com',
password: '123456789',
};
login(data).then(response => {
// response is done
}).catch(error => {
// some error in the response
});
};In some situations, such as Admin Dashboard, there would be pages that implements CRUD Operations, thankfully, this can be done easily with RestfulEndpoint class, which you provide the route of the CRUD requests, and it handles all Restful API.
// src/services/users-service.ts
import { RestfulEndpoint } from '@mongez/http';
class UsersService extends RestfulEndpoint {
/**
* {@inheritDoc}
*/
public route: string = '/users';
}
const usersService: UsersService = new UsersService();
export default usersService;From this point we can now use our usersService object to list get create update delete patch or publish
To get a list of records, we can use list method which is defined by default in RestfulEndpoint class.
// src/index.ts
import usersService from './services/users-service';
// list users without any params sent
// request: GET /users
usersService.list().then(response => {
//
});We may also send params as a query string to the request as well
// src/index.ts
import usersService from './services/users-service';
// request: GET /users?paginate=true&itemsPerPage=15
const params: object = {
paginate: true,
itemsPerPage: 15,
};
usersService.list(paramsList).then(response => {
//
});To get a single record, use get method.
// src/index.ts
import usersService from './services/users-service';
// get user information
const userId: number = 1;
// request: GET /users/1
usersService.get(userId).then(response => {
//
});
// get user with additional params sent with the request
// request: GET /users/1?active=true
usersService.get(userId, {
active: true
}).then(response => {
//
});We may also send additional params with the single record as a query string.
// src/index.ts
import usersService from './services/users-service';
// get user information
const userId: number = 1;
const params: object = {
active: true
};
// get user with additional params sent with the request
// request: GET /users/1?active=true
usersService.get(userId, params).then(response => {
//
});Creating a new record can be done from the endpoint service using create method.
Check acceptable types of data at Acceptable Http Data Section.
// src/index.ts
import usersService from './services/users-service';
const data: object = {
email: 'hassanzohdy@gmail.com',
password: '123456789',
confirmPassword: '123456789',
};
// POST /users
usersService.create(data).then(response => {
// user request is created successfully.
});Updating an existing record is also can be done using update method.
Check acceptable types of data at Acceptable Http Data Section.
// src/index.ts
import usersService from './services/users-service';
const data: object = {
email: 'hassanzohdy@gmail.com',
password: '123456789',
confirmPassword: '123456789',
};
const id: number = 1;
// PUT /users/1
usersService.update(id, data).then(response => {
// user resource is updated successfully.
});Creating a small updates on records can be done use patch method.
// src/index.ts
import usersService from './services/users-service';
const data: object = {
published: true
};
const id: number = 1;
// PATCH /users/1
usersService.patch(id, data).then(response => {
// user resource is patched successfully.
});A smaller method that allow you to publish/un-publish records using publish method.
// src/index.ts
import usersService from './services/users-service';
const isPublished: boolean = true;
const id: number = 1;
// PATCH /users/1
// request payload: { published: true }
usersService.publish(id, isPublished).then(response => {
// user resource is patched successfully.
});You may change the published key to another key by passing your desired key in the third argument.
// src/index.ts
import usersService from './services/users-service';
const isActivated: boolean = true;
const id: number = 1;
// PATCH /users/1
// request payload: { activated: true }
usersService.publish(id, isActivated, 'activated').then(response => {
// user resource is patched successfully.
});Our final method in the Restful API concept is to delete a resource/record.
// src/index.ts
import usersService from './services/users-service';
const id: number = 1;
// DELETE /users/1
usersService.delete(id).then(response => {
// user resource is patched successfully.
});In some cases we may need to create custom methods that can be used later in our project.
// src/services/users-service.ts
import { RestfulEndpoint } from '@mongez/http';
class UsersService extends RestfulEndpoint {
/**
* {@inheritDoc}
*/
public route: string = '/users';
/**
* Get active members only
*/
public listActive() {
return this.endpoint.get(this.path('/active'));
}
}
const usersService: UsersService = new UsersService();
export default usersService;In the previous example, we created a new method listActive which calls endpoint instance this.endpoint and pass to it a path method, this method concatenate the given argument with the basic route to generate another route, in the previous example the final route will be /users/active.
All of the previous methods list get create update delete patch or publish their last argument accepts Axios Configurations that can be Request Config.
Another good feature of @mongez/http is that you can cancel or abort your last request easily using lastRequest function.
import endpoint, { lastRequest } from '@mognez/http';
endpoint.get('/user').then(response => {
// it nevers go here
});
// from some other point
lastRequest().abort();If you're making multiple requests, cache the last request function in a variable as calling it always returns last fired request.
import endpoint, { lastRequest } from '@mognez/http';
endpoint.get('/user').then(response => {
// it nevers go here
});
const usersRequest = lastRequest();
endpoint.get('/posts').then(response => {
// it nevers go here
});
usersRequest.abort();
const postsRequest = lastRequest();
postsRequest.abort();For POST PUT requests, there are three acceptable formats of data:
object: which will send the request as json.HTMLFormElementwhich accepts an instance of HTMLFormElement and request data will be sent as form data.FormDatawhich accepts an instance of FormData and request data will be sent as form data.stringwhich will be sent as a string.
Let's see an example for each format.
In the next example, we'll see how to use an example of sending post request using plain object.
If data is sent as plain object, then a request header
"Content-Type": "Application/json"will be added to headers by default.
import endpoint from '@mognez/http';
const data: object = {
email: 'hassanzohdy@gmail.com',
password: '123456789',
}
endpoint.post('/login', data).then(response => {
//
});In the next example, we'll see how to use an example of sending post request using form element.
// Form.tsx
import React from 'react';
import endpoint from '@mognez/http';
export default function MyForm() {
const submitForm = e => {
e.preventDefault();
const formElement: HTMLFormElement = e.target;
endpoint.post('/login', formElement).then(response => {
//
});
}
return (
<form onSubmit={submitForm}>
<input name="email" type="email" />
<input name="password" type="password" />
</form>
)
}In the next example, we'll see how to use an example of sending post request using form data.
// Form.tsx
import React from 'react';
import endpoint from '@mognez/http';
export default function MyForm() {
const submitForm = e => {
e.preventDefault();
const formElement: HTMLFormElement = e.target;
const formData = new FormData(formElement);
endpoint.post('/login', formData).then(response => {
//
});
}
return (
<form onSubmit={submitForm}>
<input name="email" type="email" />
<input name="password" type="password" />
</form>
)
}Sometimes your api accepts only json data, but you may work with form elements or form data as well for storing form information, you may set an option to auto convert any form element or form data to json automatically in every request, just set formDataToJSON option to true in http configurations list.
import { setHttpConfigurations } from '@mongez/http';
setHttpConfigurations({
baseUrl: 'https://sitename.com/api',
formDataToJSON: true,
});You may also set your serializer method to convert the form data elements to objects.
import { setHttpConfigurations } from '@mongez/http';
setHttpConfigurations({
baseUrl: 'https://sitename.com/api',
formDataToJSON: true,
formDataToJSONSerializer: (formData: FormData): object => {
// convert it into an object
return {};
},
});If your backend api requires Authorization header in every request, You may set Authorization header from configurations either as a string or as a callback,
import { setHttpConfigurations } from '@mongez/http';
setHttpConfigurations({
baseUrl: 'https://sitename.com/api',
setAuthorizationHeader: 'key some-api-key'
});You can set it as a callback so it gets a bearer token for example
import user from './src/some-user';
import { setHttpConfigurations } from '@mongez/http';
setHttpConfigurations({
baseUrl: 'https://sitename.com/api',
setAuthorizationHeader: () => {
if (user.isLoggedIn()) {
return `Bearer ${user.accessToken()}`;
}
return `key some-api-key`;
}
});Why? because PUT requests won't allow sending files whereas post requests do it, so in some backend frameworks like Laravel has a nice workaround that allows you to send a post request and it handles it as put request.
If your backend allows something like this, you may wish to set putToPost option to true.
import { setHttpConfigurations } from '@mongez/http';
setHttpConfigurations({
baseUrl: 'https://sitename.com/api',
putToPost: true,
});This will convert any put request to post request with _method key added to the request payload with value PUT.
import endpoint, { setHttpConfigurations } from '@mongez/http';
setHttpConfigurations({
baseUrl: 'https://sitename.com/api',
putToPost: true,
});
// The request will be:
// POST /users/1
// Request Payload: {email: some-email@gmail.com, _method: PUT}
endpoint.put('/users/1', {
email: 'some-email@gmail.com',
});You may also override the _method key to other key if you would like in your http configurations.
import { setHttpConfigurations } from '@mongez/http';
setHttpConfigurations({
baseUrl: 'https://sitename.com/api',
putToPost: true,
putMethodKey: '_other_put_key'
});
// The request will be:
// POST /users/1
// Request Payload: {email: some-email@gmail.com, _other_put_key: PUT}
endpoint.put('/users/1', {
email: 'some-email@gmail.com',
});The following snippet defines all available configurations to the package.
type HttpConfigurations = {
/**
* Base Url Request
*/
baseUrl?: string;
/**
* If set to true, all PUT requests will be transformed to POST requests with _method = PUT value will be appended.
*
* @default false
*/
putToPost?: boolean;
/**
* Defines the put key that will be added to post requests.
* Works only if `putToPost` is set to true and you send a `put` request
* The send value is `PUT`
*
* @default _method
*/
putMethodKey?: string;
/**
* Set other axios setup configurations
*/
axiosConfig?: AxiosRequestConfig;
/**
* If set to true, any data that is sent as HTMLFormElement or FormData will be converted into object json format.
*
* @default false
*/
formDataToJSON?: boolean;
/**
* A serializer function that accepts FormData element
* and returns an object to be transformed into JSON
*/
formDataToJSONSerializer?: (formData: FormData) => object;
/**
* Set authorization header
*
* Useful when using Key and Bearer Tokens
*/
setAuthorizationHeader?: string | (() => string);
};Mongez Http is shipped with event driven approach so you may manipulate requests before sending it or after response is sent either on success, fail or on both.
Before sending any request:
import { AxiosRequestConfig } from "axios";
import { endpointEvents } from '@mongez/http';
import { EventSubscription } from "@mongez/events";
// This is triggered before sending any request
endpointEvents.beforeSending((requestConfig:AxiosRequestConfig): EventSubscription => {
// do something
});On success request:
import { AxiosResponse } from "axios";
import { endpointEvents } from '@mongez/http';
import { EventSubscription } from "@mongez/events";
// This is triggered on success request
endpointEvents.onSuccess((response: AxiosResponse): EventSubscription => {
// do something
});On Failure request:
import { AxiosResponse } from "axios";
import { endpointEvents } from '@mongez/http';
import { EventSubscription } from "@mongez/events";
// This is triggered on failure request
endpointEvents.onError((response: AxiosResponse): EventSubscription => {
// do something
});On request response either success or failure:
import { AxiosResponse } from "axios";
import { endpointEvents } from '@mongez/http';
import { EventSubscription } from "@mongez/events";
// This is triggered on response return either on success or on failure
endpointEvents.onResponse((response: AxiosResponse): EventSubscription => {
// do something
});- 1.0.21 (31 Jan 2022)
- Fixed lastRequest incorrect Cancel Token Clone
- Added
LastRequestas return type tolastRequest()function
- Add Unit Tests
- Handle Nodejs Http Requests.
- Adding events on
RestfulEndpointi.eonListingonCreatingand so on.