@yggdrasilts/axiosfit
v0.10.8
Published
Project inspired in Retrofit.
Downloads
8
Maintainers
Readme
Axiosfit
Axiosfit is a project inspired by Retrofit to create declarative HTTP clients using axios as the http client for browsers and nodejs, all the TypeScript features and RxJS to manage the requests using Reactive programming and all the Observable powers (also, you can use Promises as well).
Table of Contents generated with DocToc
Purpose
This project has been thought to be used inside TypeScript projects to use its incredible features to build frontend and/or backend applications.
Using Axiosfit inside your project, you will be able to organize all your requests as a typical TypeScript class. In that way, all of your application requests can be stored in a unique object and be managed. See our Examples section or our application samples to know more about how to use it.
IMPORTANT: Axiosfit only works for building frontend applications using Angular or backend applications using nodejs with TypeScript. Althought Axiosfit can be used in a typical TypeScript application, we strongly recommend to use NestJS framework to build backend applications.
Install
npm i --save @yggdrasilts/axiosfit
Contributing
If you want to contribute this amazing project, see CONTRIBUTING Guide or/and -> :-)
Documentation
This project use compodoc to generate the full documentation. To see it, executes npm run compodoc
.
Available Decorators
As we all know, to build a request is necessary a URL and, using one of the top TypeScript feature, the TypeScript Decorators, Axiosfit give you some specifical Decorators to create an awesome service to store all the information to form your URL to manage your HTTP requests.
Class Decorators
- @HTTP(endpointPath?: string | AxiosfitConfig, axisofitConfig?: AxiosfitConfig)
- @Interceptors(...interceptors: AxiosfitInterceptor[])
@HTTP is the main Decorator to configure your Axiosfit service and indicates that the class is an Axiosfit instance. Also, it can be configured with the base path of your API server using its endpointPath property and configure more Axiosfit option using the AxiosfitConfig object.
@Interceptors decorator can be use to add interceptors to the requests or responses. These interceptors must implements AxiosfitInterceptor interface and you can add as many as you want separated by comma. You can see the Interceptors section for more information.
Considerations
Angular applications: Due to the uglify process when you build an Angular application with --prod parameters, you need to create a static readonly property called serviceName
inside the class to give it a unique name that works as unique identifier used by Axiosfit. In the Usage section you can see how to use it. You also have more samples inside the samples folder.
Method Decorators
- @GET(endpoint: string)
- @POST(endpoint: string)
- @PUT(endpoint: string)
- @DELETE(endpoint: string)
- @HEAD(endpoint: string)
- @PATCH(endpoint: string)
To request any API server, it is needed to know with method is necessary. For this reason Axiosfit give you Decorators to indicate which method has to be used.
Parameter Decorators
- @Path(paramName: string)
- @Param(paramName: string)
- @ParamMap(paramName: string)
- @Header(headerName: string)
- @HeaderMap(name: string)
- @Body()
Another part is the path and the body of your request and Axiosfit also has these Decorators to configure your service.
Examples of using all of these Decorators are shown in the Examples section or you can find specific samples inside the samples folder.
Configuration
- AxiosfitConfig
- usePromises: Default false. Configure Axiosfit service to return Observable object or a Promise.
- enableAxiosLogger: Default false. Configure Axiosfit service to use the axiosfit logger to print the request and response to the console.
Usage
To build an Axiosfit service a few steps need to be done:
1. Create a service class
A service class needs to be created because it will store all the requests information. The following code shows a simple service:
@HTTP('/simple')
export class SimpleService {
@GET('/service')
public getSimpleService(): Observable<AxiosResponse<string>> {
return null;
}
}
If you want to use Promises instead of Observable:
@HTTP('/simple', { usePromises: true })
export class SimpleService {
@GET('/service')
public getSimpleService(): Promise<AxiosResponse<string>> {
return null;
}
}
1.1 Service class for Angular application uglifying the code to deploy in production
@HTTP('/simple')
export class SimpleService {
private static readonly serviceName = 'SimpleService';
@GET('/service')
public getSimpleService(): Observable<AxiosResponse<string>> {
return null;
}
}
2. Create Axiosfit instance
Once the service class is created, the Axiosfit instance can be built:
const simpleService = new Axiosfit<SimpleService>().baseUrl('http://simpleservice.com').create(SimpleService);
3. Perform an Axiosfit request
After all steps, the service can be managed as a typical class:
simpleService.getSimpleService().subscribe(
(axiosResponse) => console.log(axiosResponse.data),
(axiosError) => console.error(axiosError),
);
4. Using Promises
Axiosfit manage responses using Observables or Promises. The above example shows how to use Observables but, if you prefer use Promises, a minimal change has to be done:
4.1 Modify service class return type
@HTTP('/simple')
export class SimpleService {
@GET('/service')
public getSimpleService(): Promise<AxiosResponse<string>> {
return null;
}
}
Once the change is made, you can use Axiosfit response like a typical Promise:
simpleService
.getSimpleService()
.then((axiosResponse) => console.log(axiosResponse.data))
.catch((axiosError) => console.error(axiosError));
Headers
HTTP headers let the client and the server pass additional information with an HTTP request or response. Axiosfit has various decorators that enabled you to modify these HTTP headers.
- The @Header parameter decorator gives you the option to add some header individually.
@GET(TestRoutes.GET.REQUEST.URL)
public performGetRequestWithHeader(@Header('Authorization') token: string): Observable<AxiosResponse<string>> {
return null;
}
- The @HeaderMap parameter decorator gives you the option to pass a map with various headers.
@GET(TestRoutes.GET.REQUEST.URL)
public performGetRequestWithHeaderMap(@HeaderMap('map') map: IHeadersMap): Observable<AxiosResponse<string>> {
return null;
}
Other features
Interceptors
Interceptors are other axios feature that Axiosfit implements.
There are 2 ways to use interceptors:
- Using the @Interceptors(...interceptors: AxiosfitInterceptor[]) decorator:
With this first way, the interceptor, or a list of interceptors separated by commas, needs to be added as a decorator parameter:
@HTTP('/simple')
@Interceptors(SimpleInterceptor)
export class SimpleService {
@GET('/service')
public getSimpleService(): Promise<AxiosResponse<string>> {
return null;
}
}
In the following sample you can see how to implement it and alse see the differences.
export class SimpleInterceptor implements AxiosfitRequestInterceptor, AxiosfitResponseInterceptor {
onRequest(config: AxiosRequestConfig): AxiosRequestConfig | Promise<AxiosRequestConfig> {
// tslint:disable-next-line: no-string-literal
config.headers['authorization'] = 'Bearer token';
return config;
}
onResponse(response: AxiosResponse<any>): AxiosResponse<any> | Promise<AxiosResponse<any>> {
// tslint:disable-next-line: no-string-literal
const currentData = response.data;
response.data = {
...currentData,
newData: 'new',
};
return response;
}
}
- Add the interceptor when the Axiosfit service is created.
Using this second method, a request and/or response interceptors must be created when the Axiosfit instance is created.
export const simpleService = new Axiosfit<SimpleService>()
.baseUrl('http://simpleservice.com')
.addInterceptor(interceptor)
.create(SimpleService);
Request Interceptor
export class SimpleNewInterceptorRequest implements AxiosfitRequestInterceptor {
onRequest(config: AxiosRequestConfig): AxiosRequestConfig | Promise<AxiosRequestConfig> {
// tslint:disable-next-line: no-string-literal
config.headers['authorization'] = 'Bearer token';
return config;
}
}
Response Interceptor
export class SimpleInterceptorResponse implements AxiosfitResponseInterceptor {
onResponse(response: AxiosResponse<any>): AxiosResponse<any> | Promise<AxiosResponse<any>> {
// tslint:disable-next-line: no-string-literal
const currentData = response.data;
response.data = {
...currentData,
newData: 'new',
};
return response;
}
}
Examples
Create class with the endpoints methods:
- Using Observables:
import {
HTTP,
Header,
HeaderMap,
GET,
DELETE,
HEAD,
POST,
PUT,
PATCH,
Path,
Body,
Observable,
AxiosResponse,
Param,
ParamMap,
IParamMap,
IHeadersMap,
} from '../../../src';
import { TestRoutes } from '../TestRoutes';
@HTTP(TestRoutes.BASE, { enableAxiosLogger: true })
export class TestObservableService {
private static readonly serviceName = 'TestObservableService';
@GET(TestRoutes.GET.REQUEST.URL)
public performGetRequest(): Observable<AxiosResponse<string>> {
return null;
}
@GET(TestRoutes.GET.REQUEST.URL)
public performGetRequestWithHeader(@Header('Authorization') token: string): Observable<AxiosResponse<string>> {
return null;
}
@GET(TestRoutes.GET.REQUEST.URL)
public performGetRequestWithHeaderMap(@HeaderMap('map') map: IHeadersMap): Observable<AxiosResponse<string>> {
return null;
}
@GET(TestRoutes.GET.REQUEST.URL)
public performGetRequestWithParameter(@Param('id') id: string): Observable<AxiosResponse<string>> {
return null;
}
@GET(TestRoutes.GET.REQUEST.URL)
public performGetRequestWithParametersMap(@ParamMap('map') map: IParamMap): Observable<AxiosResponse<string>> {
return null;
}
@GET(TestRoutes.GET.REQUEST.URL)
public performGetRequestWithParameters(
@Param('id1') id1: string,
@Param('id2') id2: string,
@ParamMap('map') map: IParamMap,
): Observable<AxiosResponse<string>> {
return null;
}
@GET(TestRoutes.GET.WITH_REQUEST_INTERCEPTOR.URL)
public performGetRequestAddingReqInterceptor(): Observable<AxiosResponse<string>> {
return null;
}
@GET(TestRoutes.GET.WITH_RESPONSE_INTERCEPTOR.URL)
public performGetRequestAddingResInterceptor(): Observable<AxiosResponse<string>> {
return null;
}
@GET(TestRoutes.GET.WITH_PARAM.URL)
public performGetRequestUsingAPathVariable(@Path(TestRoutes.GET.WITH_PARAM.PARAMS.ID) id: string): Observable<AxiosResponse<string>> {
return null;
}
@GET(TestRoutes.GET.WITH_PARAMS.URL)
public performGetRequestUsingPathVariables(
@Path(TestRoutes.GET.WITH_PARAMS.PARAMS.ID) id: string,
@Path(TestRoutes.GET.WITH_PARAMS.PARAMS.ID2) id2: string,
): Observable<AxiosResponse<string>> {
return null;
}
@DELETE(TestRoutes.DELETE.REQUEST.URL)
public performDeleteRequest(): Observable<AxiosResponse<string>> {
return null;
}
@HEAD(TestRoutes.HEAD.REQUEST.URL)
public performHeadRequest(): Observable<AxiosResponse<string>> {
return null;
}
@POST(TestRoutes.POST.REQUEST.URL)
public performPostRequest(@Body() body: any): Observable<AxiosResponse<any>> {
return null;
}
@PUT(TestRoutes.PUT.REQUEST.URL)
public performPutRequest(@Body() body: any): Observable<AxiosResponse<any>> {
return null;
}
@PATCH(TestRoutes.PATCH.REQUEST.URL)
public performPatchRequest(@Body() body: any): Observable<AxiosResponse<any>> {
return null;
}
}
- Using Promises:
import { HTTP, GET, DELETE, HEAD, POST, PUT, PATCH, Path, Body, AxiosResponse } from '../../src';
import { TestRoutes } from './TestRoutes';
@HTTP(TestRoutes.BASE, { usePromises: true })
export class TestService {
@GET(TestRoutes.GET.REQUEST.URL)
public performGetRequest(): Promise<AxiosResponse<string>> {
return null;
}
@GET(TestRoutes.GET.WITH_REQUEST_INTERCEPTOR.URL)
public performGetRequestAddingReqInterceptor(): Promise<AxiosResponse<string>> {
return null;
}
@GET(TestRoutes.GET.WITH_RESPONSE_INTERCEPTOR.URL)
public performGetRequestAddingResInterceptor(): Promise<AxiosResponse<string>> {
return null;
}
@GET(TestRoutes.GET.WITH_PARAM.URL)
public performGetRequestUsingAPathVariable(@Path(TestRoutes.GET.WITH_PARAM.PARAMS.ID) id: string): Promise<AxiosResponse<string>> {
return null;
}
@GET(TestRoutes.GET.WITH_PARAMS.URL)
public performGetRequestUsingPathVariables(
@Path(TestRoutes.GET.WITH_PARAMS.PARAMS.ID) id: string,
@Path(TestRoutes.GET.WITH_PARAMS.PARAMS.ID2) id2: string,
): Promise<AxiosResponse<string>> {
return null;
}
@DELETE(TestRoutes.DELETE.REQUEST.URL)
public performDeleteRequest(): Promise<AxiosResponse<string>> {
return null;
}
@HEAD(TestRoutes.HEAD.REQUEST.URL)
public performHeadRequest(): Promise<AxiosResponse<string>> {
return null;
}
@POST(TestRoutes.POST.REQUEST.URL)
public performPostRequest(@Body() body: any): Promise<AxiosResponse<any>> {
return null;
}
@PUT(TestRoutes.PUT.REQUEST.URL)
public performPutRequest(@Body() body: any): Promise<AxiosResponse<any>> {
return null;
}
@PATCH(TestRoutes.PATCH.REQUEST.URL)
public performPatchRequest(@Body() body: any): Promise<AxiosResponse<any>> {
return null;
}
}
- Create the
Axiosfit
instance:
import { Axiosfit } from '@yggdrasilts/axiosfit';
const methodsService = new Axiosfit<TestService>().baseUrl(process.env.MOCK_SERVER_URL).create(TestService);
Call methods using observables:
- Using Observables:
import { AxiosResponse, AxiosError } from '@yggdrasilts/axiosfit';
methodsService.performGetRequest().subscribe(
(response: AxiosResponse<string>) => console.log('OK', response.data),
(error: AxiosError<any>) => console.error('KO', error),
);
- Using Promises:
import { AxiosResponse, AxiosError } from '@yggdrasilts/axiosfit';
methodsService
.performGetRequest()
.then((response: AxiosResponse<string>) => console.log('OK', response.data))
.catch((error: AxiosError<any>) => console.error('KO', error));
NOTE: The example code can be seen in the test folder.