retrofit-axios-ts
TypeScript icon, indicating that this package has built-in type declarations

1.0.9 • Public • Published

retrofit-axios-ts

Thanks to nullcc for providing us with the codebase from ts-retrofit

The main difference between this version and the original ts-retrofit version is:

  • Support for rejected request functions on interceptors
  • AbortSignal decorator which allow setting signal for the request by sending it as parameter
  • DownloadProgress and UploadProgress decorators which will allow setting callbacks for handling progress

A declarative and axios based retrofit implementation for JavaScript and TypeScript.

Install

$ npm i retrofit-axios-ts

Quick Overview

Here is a typical service definition and usage:

import {
  GET,
  POST,
  PUT,
  PATCH,
  DELETE,
  BasePath,
  Header,
  Path,
  Body,
  BaseService,
  ServiceBuilder,
  Response,
} from "retrofit-axios-ts";

interface User {
  id?: number;
  name: string;
  email: string;
}

@BasePath("/api/v1")
class UserService extends BaseService {
  @GET("/users")
  async getUsers(
    @Header("Authorization") authorization: string,
  ): Promise<Response<Array<User>>> {
    return <Response<Array<User>>>{};
  }

  @GET("/users/{userId}")
  async getUser(
    @Header("Authorization") authorization: string,
    @Path("userId") userId: number,
  ): Promise<Response<User>> {
    return <Response<User>>{};
  }

  @POST("/users")
  async createUser(
    @Header("Authorization") authorization: string,
    @Body user: User,
  ): Promise<Response> {
    return <Response>{};
  }

  @PUT("/users/{userId}")
  async updateUser(
    @Header("Authorization") authorization: string,
    @Path("userId") userId: number,
    @Body user: User,
  ): Promise<Response> {
    return <Response>{};
  }

  @PATCH("/users/{userId}")
  async patchUser(
    @Header("Authorization") authorization: string,
    @Path("userId") userId: number,
    @Body user: Partial<User>,
  ): Promise<Response> {
    return <Response>{};
  }

  @DELETE("/users/{userId}")
  async deleteUser(
    @Header("Authorization") authorization: string,
    @Path("userId") userId: number,
  ): Promise<Response> {
    return <Response>{};
  }
}

(async () => {
  const authorization = "foobar";
  const userService = new ServiceBuilder()
    .setEndpoint("https://www.your-host.com")
    .build(UserService);
  const response = await userService.getUsers(authorization);
  // Now you can get response data from response.data
})();

You can see test file to get more examples.

ServiceBuilder

Example:

import { AxiosRequestConfig } from "axios";
import {
  ServiceBuilder,
  RequestInterceptors,
  ResponseInterceptors
} from "retrofit-axios-ts";

@BasePath("/api/v1")
class ItemService extends BaseService {
  @GET("/items")
  async getItems(): Promise<Response<Array<Item>>> { return <Response<Array<Item>>> {} };
}

const requestInterceptors: RequestInterceptors = {
  fulfilled: (config) => {
    console.log("Before sending request to server.");
    return config;
  },
  rejected: (e) => {
      console.log("Request interceptor error.");
      return Promise.reject(e);
  },
};

const responseInterceptors: ResponseInterceptors = {
  fulfilled: (config) => {
    console.log("After receiving response from server.");
    return config;
  },
  rejected: (e) => {
    console.log("Response interceptor error.");
    return Promise.reject(e)
  },
};

(async () => {
  const itemService = new ServiceBuilder()
	.setEndpoint(${ENDPOINT})
    .setStandalone(true)
    .setRequestInterceptors(requestInterceptors)
    .setResponseInterceptors(responseInterceptors)
    .build(ItemService);
  const response: any = await itemService.getVersion();
  console.log(response.data);
})();

// outputs:
// Before sending request to server.
// After receiving response from server.
// <response data>

Log

You can set log callback to print some information after request finished (ok/error):

@BasePath("")
export class HealthService extends BaseService {
  @GET("/ping")
  @ResponseStatus(200)
  async ping(): Promise<Response> {
    return <Response>{};
  }
}
const myLogCallback = (config: RequestConfig, response: Response) => {
  const log = `[${config.method}] ${config.url} ${response.status}`;
  console.log(log); // [GET] http://localhost:12345/ping 200
};
const service = new ServiceBuilder()
  .setEndpoint("http://localhost:12345")
  .setLogCallback(myLogCallback)
  .build(HealthService);

// or use this
service.setLogCallback(myLogCallback);
const response = await service.ping();

Decorators

BasePath

  • Position: Class

BasePath decorator declares the path prefix of a service.

// The common path of ItemService is ${ENDPOINT}/api/v1
@BasePath("/api/v1")
class ItemService extends BaseService {}

HTTP Method Decorators

All HTTP method decorators have an optional second parameter with type HttpMethodOptions:

export interface HttpMethodOptions {
  ignoreBasePath?: boolean;
}

GET

  • Position: Method

GET decorator declares that what it decorated use HTTP GET method to request server.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // GET ${ENDPOINT}/api/v1/items
  @GET("/items")
  async getItems(): Promise<Response<Array<Item>>> {
    return <Response<Array<Item>>>{};
  }

  // GET ${ENDPOINT}/items
  @GET("/items", { ignoreBasePath: true })
  async getItemsWithoutBasePath(): Promise<Response<Array<Item>>> {
    return <Response<Array<Item>>>{};
  }
}

POST

  • Position: Method

POST decorator declares that what it decorated use HTTP POST method to request server.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // POST ${ENDPOINT}/api/v1/items
  @POST("/items")
  async createItem(@Body item: Item): Promise<Response> {
    return <Response>{};
  }
}

PUT

  • Position: Method

PUT decorator declares that what it decorated use HTTP PUT method to request server.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // PUT ${ENDPOINT}/api/v1/items/{itemId}
  @PUT("/items/{itemId}")
  async updateItem(
    @Path("itemId") itemId: number,
    @Body item: Item,
  ): Promise<Response> {
    return <Response>{};
  }
}

PATCH

  • Position: Method

PATCH decorator declares that what it decorated use HTTP PATCH method to request server.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // PATCH ${ENDPOINT}/api/v1/items/{itemId}
  @PATCH("/items/{itemId}")
  async patchItem(
    @Path("itemId") itemId: number,
    @Body item: Partial<Item>,
  ): Promise<Response> {
    return <Response>{};
  }
}

DELETE

  • Position: Method

DELETE decorator declares that what it decorated use HTTP DELETE method to request server.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // DELETE ${ENDPOINT}/api/v1/items/{itemId}
  @DELETE("/items/{itemId}")
  async deleteItem(@Path("itemId") itemId: number): Promise<Response> {
    return <Response>{};
  }
}

HEAD

  • Position: Method

HEAD decorator declares that what it decorated use HTTP HEAD method to request server.

@BasePath("/api/v1")
class FileService extends BaseService {
  // HEAD ${ENDPOINT}/api/v1/files/{fileId}
  @HEAD("/files/{fileId}")
  async getFileMetaInfo(@Path("fileId") fileId: number): Promise<Response> {
    return <Response>{};
  }
}

OPTIONS

  • Position: Method

OPTIONS decorator declares that what it decorated use HTTP OPTIONS method to request server.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // OPTIONS ${ENDPOINT}/api/v1/items/{itemId}
  @OPTIONS("/items/{itemId}")
  async getFileMetaInfo(@Path("itemId") itemId: number): Promise<Response> {
    return <Response>{};
  }
}

Headers

  • Position: Method

Headers decorator declares that what static HTTP headers should be added to request.

@BasePath("")
export class AuthService extends BaseService {
  @POST("/oauth/token")
  @Headers({
    "Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
    Accept: "application/json",
  })
  async auth(@Body body: OAuth): Promise<Response<Token>> {
    return <Response<Token>>{};
  }
}

Header

  • Position: Method Parameter

Header decorator parameterizes the header in HTTP request. Client can provide a value to one header.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // GET ${ENDPOINT}/api/v1/items
  async getItems(
    @Header("Authorization") authorization: string,
  ): Promise<Response<Array<Item>>> {
    return <Response<Array<Item>>>{};
  }
}

HeaderMap

  • Position: Method Parameter

HeaderMap decorator parameterizes the headers in HTTP request. Client can provide values to multi headers.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // GET ${ENDPOINT}/api/v1/items
  async getItems(@HeaderMap headers: any): Promise<Response<Array<Item>>> {
    return <Response<Array<Item>>>{};
  }
}

Path

  • Position: Method Parameter

Path decorator parameterizes the part of path in HTTP request.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // GET ${ENDPOINT}/api/v1/items/{itemId}
  @GET("/items/{itemId}")
  async getItem(@Path("itemId") itemId: number): Promise<Response<Item>> {
    return <Response<Item>>{};
  }
}

Body

  • Position: Method Parameter

Body decorator parameterizes the body in HTTP request.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // POST ${ENDPOINT}/api/v1/items
  @POST("/items")
  async createItem(@Body item: Item): Promise<Response> {
    return <Response>{};
  }
}

QueryArrayFormat

  • Position: Method

QueryArrayFormat decorator declares that what kind of array format should be used in query.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // getItemsWithQueryArrayFormatIndices(["food", "book", "pet"])
  // GET ${ENDPOINT}/api/v1/items?categories[0]=food&categories[1]=book&categories[2]=pet
  @GET("/items")
  @QueryArrayFormat("indices")
  async getItemsWithQueryArrayFormatIndices(
    @Query("categories") categories: string[],
  ): Promise<Response<Array<Item>>> {
    return <Response<Array<Item>>>{};
  }

  // getItemsWithQueryArrayFormatBrackets(["food", "book", "pet"])
  // GET ${ENDPOINT}/api/v1/items?categories[]=food&categories[]=book&categories[]=pet
  @GET("/items")
  @QueryArrayFormat("brackets")
  async getItemsWithQueryArrayFormatBrackets(
    @Query("categories") categories: string[],
  ): Promise<Response<Array<Item>>> {
    return <Response<Array<Item>>>{};
  }

  // getItemsWithQueryArrayFormatRepeat(["food", "book", "pet"])
  // GET ${ENDPOINT}/api/v1/items?categories=food&categories=book&categories=pet
  @GET("/items")
  @QueryArrayFormat("repeat")
  async getItemsWithQueryArrayFormatRepeat(
    @Query("categories") categories: string[],
  ): Promise<Response<Array<Item>>> {
    return <Response<Array<Item>>>{};
  }

  // getItemsWithQueryArrayFormatComma(["food", "book", "pet"])
  // GET ${ENDPOINT}/api/v1/items?categories=food,book,pet
  @GET("/items")
  @QueryArrayFormat("comma")
  async getItemsWithQueryArrayFormatComma(
    @Query("categories") categories: string[],
  ): Promise<Response<Array<Item>>> {
    return <Response<Array<Item>>>{};
  }
}

Queries

  • Position: Method

Queries decorator declares that what static queries should be added to request.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // GET ${ENDPOINT}/api/v1/items?size=20
  @GET("/items")
  @Queries({
    size: 20,
  })
  async getItems(): Promise<Response<Array<Item>>> {
    return <Response<Array<Item>>>{};
  }
}

Query

  • Position: Method Parameter

Query decorator parameterizes the query in HTTP request. Client can provide a value to one query parameter.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // GET ${ENDPOINT}/api/v1/items?size=20
  @GET("/items")
  async getItems(@Query("size") size: number): Promise<Response<Array<Item>>> {
    return <Response<Array<Item>>>{};
  }
}

QueryMap

  • Position: Method Parameter

QueryMap decorator parameterizes the queries in HTTP request. Client can provide values to multi queries.

@BasePath("")
class SearchService extends BaseService {
  // GET ${ENDPOINT}/search?a=foo&b=bar
  @GET("/search")
  async search(@QueryMap query: SearchQuery): Promise<Response<SearchResult>> {
    return <Response<SearchResult>>{};
  }
}

FormUrlEncoded

  • Position: Method

FormUrlEncoded declares that the content type is application/x-www-form-urlencoded;charset=utf-8 in HTTP request.

@BasePath("")
export class AuthService extends BaseService {
  @POST("/oauth/token")
  @FormUrlEncoded
  async auth(@Body body: OAuth): Promise<Response<Token>> {
    return <Response<Token>>{};
  }
}

Field

  • Position: Method Parameter

Field decorator parameterizes the field in HTTP request. It only takes effect when method is decorated by @FormUrlEncoded.

@BasePath("")
export class AuthService extends BaseService {
  @POST("/oauth/token")
  @FormUrlEncoded
  async auth(
    @Field("username") username: string,
    @Field("password") password: string,
  ): Promise<Response<Token>> {
    return <Response<Token>>{};
  }
}

FieldMap

  • Position: Method Parameter

FieldMap decorator parameterizes the field in HTTP request. It only takes effect when method is decorated by @FormUrlEncoded.

@BasePath("")
export class AuthService extends BaseService {
  @POST("/oauth/token")
  @FormUrlEncoded
  async auth(@FieldMap fields: OAuth): Promise<Response<Token>> {
    return <Response<Token>>{};
  }
}

Multipart

  • Position: Method

Multipart decorator declares that the content type is multipart/form-data in HTTP request.

@BasePath("/api/v1")
export class FileService extends BaseService {
  @POST("/upload")
  @Multipart
  async upload(
    @Part("bucket") bucket: PartDescriptor<string>,
    @Part("file") file: PartDescriptor<Buffer>,
  ): Promise<Response> {
    return <Response>{};
  }
}

Part

  • Position: Method Parameter

Part decorator parameterizes the part in HTTP request. It only takes effect when method is decorated by @Multipart.

@BasePath("/api/v1")
export class FileService extends BaseService {
  @POST("/upload")
  @Multipart
  async upload(
    @Part("bucket") bucket: PartDescriptor<string>,
    @Part("file") file: PartDescriptor<Buffer>,
  ): Promise<Response> {
    return <Response>{};
  }
}

ResponseType

  • Position: Method
  • Options: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'

ResponseType decorator declares response type in axios config.

@BasePath("/api/v1")
export class FileService extends BaseService {
  @GET("/file")
  @ResponseType("stream")
  async getFile(@Path("fileId") fileId: string): Promise<Response> {
    return <Response>{};
  }
}

RequestTransformer

  • Position: Method

RequestTransformer decorator provides a hook to handle request data before sending request to server.

@BasePath(API_PREFIX)
export class TransformerService extends BaseService {
  @POST("/request-transformer")
  @RequestTransformer((data: any, headers?: any) => {
    data.foo = "foo"; // add something to request data
    return JSON.stringify(data);
  })
  async createSomething(@Body body: Something): Promise<Response> {
    return <Response>{};
  }
}

ResponseTransformer

  • Position: Method

ResponseTransformer decorator provides a hook to handle response data after receiving response from server.

@BasePath(API_PREFIX)
export class TransformerService extends BaseService {
  @POST("/request-transformer")
  @RequestTransformer((data: any, headers?: any) => {
    data.foo = "foo"; // add something to response data
    return JSON.stringify(data);
  })
  async createSomething(@Body body: Something): Promise<Response> {
    return <Response>{};
  }
}

Timeout

  • Position: Method

Timeout decorator declares timeout in axios config.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // GET ${ENDPOINT}/api/v1/items
  @GET("/items")
  @Timeout(3000)
  async getItems(): Promise<Response<Array<Item>>> {
    return <Response<Array<Item>>>{};
  }
}

ResponseStatus

  • Position: Method

ResponseStatus decorator declares status code for method, do nothing just a declaration.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // GET ${ENDPOINT}/api/v1/items
  @GET("/items")
  @Timeout(3000)
  async getItems(): Promise<Response<Array<Item>>> {
    return <Response<Array<Item>>>{};
  }
}

Config

  • Position: Method

Config decorator provides a direct way to set config for a request in axios.

@BasePath("/api/v1")
export class ConfigService extends BaseService {
  @GET("/config")
  @Config({
    maxRedirects: 1,
  })
  async getConfig(): Promise<Response> {
    return <Response>{};
  }
}

AbortSignal

  • Position: Method Parameter

AbortSignal decorator provides a direct way to set an abort controller signal for a request in axios.

@BasePath("/api/v1")
export class AbortSignalService extends BaseService {
  @GET("/abort")
  async setAbortSignal(
    @AbortSignal abortSignal: AbortSignal,
  ): Promise<Response> {
    return <Response>{};
  }
}

DownloadProgress

  • Position: Method Parameter

DownloadProgress decorator provides a direct way to set an onDownloadProgress callback for a request in axios.

@BasePath("/api/v1")
export class ProgressService extends BaseService {
  @GET("/download")
  async downloadFile(
    @DownloadProgress
    callback: (axiosProgressEvent: ProgressEvent) => void,
  ): Promise<Response> {
    return <Response>{};
  }
}

UploadProgress

  • Position: Method Parameter

UploadProgress decorator provides a direct way to set an onUploadProgress callback for a request in axios.

@BasePath("/api/v1")
export class ProgressService extends BaseService {
  @POST("/upload")
  @Multipart
  async uploadFile(
    @Part("file") file: PartDescriptor<Buffer>,
    @UploadProgress callback: (axiosProgressEvent: ProgressEvent) => void,
  ): Promise<Response> {
    return <Response>{};
  }
}

GraphQL and GraphQLVariables

  • Position: Method

GraphQL decorator declares query for a GraphQL request.

GraphQLVariables decorator declares variables for a GraphQL request.

const gqlQuery = `query ($name: String!, $owner: String!) {
  viewer {
    name
    location
  }
  repository(name: $name, owner: $owner) {
    stargazerCount
    forkCount
  }
}`;

@BasePath("")
export class GraphQLService extends BaseService {
  @POST("/graphql")
  @GraphQL(gqlQuery, "UserAndRepo")
  async graphql1(@GraphQLVariables variables: any): Promise<Response> {
    return <Response>{};
  }
}

Deprecated

  • Position: Method

Deprecated decorator marks a method is deprecated.

@BasePath("/api/v1")
class ItemService extends BaseService {
  // GET ${ENDPOINT}/api/v1/items
  @GET("/items")
  @Deprecated("This method is deprecated")
  async getItems(): Promise<Response<Array<Item>>> {
    return <Response<Array<Item>>>{};
  }
}

Decorators Summary

Category Name Description Decorator Position Example
HTTP Method @GET GET Method Method @GET("/users")
HTTP Method @POST POST Method Method @POST("/users")
HTTP Method @PUT PUT Method Method @PUT("/users/{userId}")
HTTP Method @PATCH PATCH Method Method @PATCH("/users/{userId}")
HTTP Method @DELETE DELETE Method Method @DELETE("/users/{userId}")
HTTP Method @HEAD HEAD Method Method @HEAD("/users/{userId}")
HTTP Method @OPTIONS OPTIONS Method Method @OPTIONS("/users/{userId}")
Base Path @BasePath Specifying the base path of a series of API endpoints Class @BasePath("/api/v1")
Static Headers @Headers Specifying the static headers of API endpoint Method @Headers({ "content-type": "application/x-www-form-urlencoded", "Accept": "application/json" })
Header Parameter @Header Parameterized header Method Parameter @Header("X-Token")
Header Parameters @HeaderMap Parameterized header Method Parameter @HeaderMap
Path Parameter @Path Specifying parameter in path of API Method Parameter @Path("userId")
Body @Body Specifying body data Method Parameter @Body
Query Array Format @QueryArrayFormat Specifying query array format Method @QueryArrayFormat('repeat')
Static Query @Queries Specifying static query data Method @Queries({ page: 1, size: 20, sort: "createdAt:desc" })
Query Parameter @Query Parameterized query Method Parameter @Query("group")
Query Parameters @QueryMap Parameterized query Method Parameter @QueryMap
Static Headers @FormUrlEncoded Specifying "content-type" to be "application/x-www-form-urlencoded" Method @FormUrlEncoded
Field Parameter @Field Specifying field in method parameter, only takes effect when method has been decorated by @FormUrlEncoded Method Parameter @Field("name")
Field Parameters @FieldMap Specifying field map in method parameter, only takes effect when method has been decorated by @FormUrlEncoded Method Parameter @FieldMap
Static Headers @Multipart Specifying "content-type" to be "multipart/form-data" Method @Multipart
Part Parameters @Part Specifying field map in method parameter, only takes effect when method has been decorated by @Multipart Method Parameter @Part("name")
Response @ResponseType Specifying the response type in axios config Method @ResponseType("stream")
RequestTransformer @RequestTransformer Specifying the request transformer in axios config Method @RequestTransformer((data: any, headers?: any) => { data.foo = 'foo'; return JSON.stringify(data); })
ResponseTransformer @ResponseTransformer Specifying the response transformer in axios config Method @ResponseTransformer((data: any, headers?: any) => { const json = JSON.parse(data); json.foo = 'foo'; return json; })
Timeout @Timeout Specifying the timeout in axios config Method @Timeout(5000)
ResponseStatus @ResponseStatus Declare response status code for method, do nothing just a declaration Method @ResponseStatus(204)
Config @Config A direct way to set config for a request in axios Method @Config({ maxRedirects: 1 })
AbortSignal @AbortSignal Sets an abort signal to the request Method Parameter @AbortSignal abortSignal: AbortSignal
DownloadProgress @DownloadProgress Sets an onDownloadProgress callback to the request Method Parameter @DownloadProgress callback: (axiosProgressEvent: ProgressEvent) => void
UploadProgress @UploadProgress Sets an onUploadProgress callback to the request Method Parameter @UploadProgress callback: (axiosProgressEvent: ProgressEvent) => void
GraphQL @GraphQL Declares query for a GraphQL request. Method @GraphQL(gqlQuery, "operationName")
GraphQLVariables @GraphQLVariables Declares variables for a GraphQL request. Method @GraphQLVariables
Deprecated @Deprecated Marks a method is deprecated Method @Deprecated()
@Deprecated("This method is deprecated")

Test

$ npm test

Package Sidebar

Install

npm i retrofit-axios-ts

Weekly Downloads

20

Version

1.0.9

License

MIT

Unpacked Size

142 kB

Total Files

118

Last publish

Collaborators

  • dev.cepedi