Nobody Prefers Margarine

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

    1.17.5 • Public • Published

    ts-retrofit

    build status

    Statements Branches Functions Lines
    Statements Branches Functions Lines

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

    Install

    $ npm i ts-retrofit3

    Quick Overview

    Here is a typical service definition and usage:

    import { GET, POST, PUT, PATCH, DELETE, BasePath, Header, Path, Body, BaseService, ServiceBuilder, Response } from "ts-retrofit3";
    
    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,
      ResponseInterceptorFunction,
      RequestInterceptorFunction,
      RequestInterceptor,
      ResponseInterceptor,
    } from "ts-retrofit3";
    
    @BasePath("/api/v1")
    class ItemService extends BaseService {
      @GET("/items")
      async getItems(): Promise<Response<Array<Item>>> { return <Response<Array<Item>>> {} };
    }
    
    const RequestInterceptor: RequestInterceptorFunction = (config) => {
      console.log("Before sending request to server.");
      return config;
    };
    
    const ResponseInterceptor: ResponseInterceptorFunction = (response) => {
      console.log("After receiving response from server.");
      return response;
    };
    
    (async () => {
      const itemService = new ServiceBuilder()
    	.setEndpoint(${ENDPOINT})
        .setStandalone(true)
        .setRequestInterceptors(RequestInterceptor)
        .setResponseInterceptors(ResponseInterceptor)
        .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> {} };
    }

    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>{} };
    }

    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>{} };
    }

    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
    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 })
    GraphQL @GraphQL Declares query for a GraphQL request. Method @GraphQL(gqlQuery, "operationName")
    GraphQLVariables @GraphQLVariables Decorator declares variables for a GraphQL request. Method @GraphQLVariables

    Test

    $ npm test

    Install

    npm i ts-retrofit3

    DownloadsWeekly Downloads

    10

    Version

    1.17.5

    License

    MIT

    Unpacked Size

    79.7 kB

    Total Files

    15

    Last publish

    Collaborators

    • safarishahim