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

    3.1.1 • Public • Published

    pretend

    npm GitHub license build codecov renovate badge

    A decorator based http webservice client build with typescript (inspired bei feign).

    Features

    • Handle REST based webservices
    • Configure a decoder (defaults to JSON)
    • Generic request/response interceptor chain
    • Basic authentication
    • Request parameters (currently on GET requests)
    • Custom headers per method

    Usage

    Installation

    Install as npm package:

    npm install pretend --save

    Note: To work on node.js (server-side) the fetch must be polyfilled. This could easy be done importing isomorphic-fetch.

    API

    class Test {
    
      @Headers('Accept: application/json')
      @Get('/path/{id}', true)
      public async get(id: string, parameters: any) {}
    
      @Post('/path')
      public async post(body: any) {}
    
      @Post('/path')
      public async post(@FormData('name') blob: any) {}
    
      @Put('/path')
      public async put() {}
    
      @Delete('/path/:id')
      public async delete(id: string) {}
    
    }
    
    async function call() {
      const client = Pretend
                      .builder()
                      .target(Test, 'http://host:port/');
      const result = await client.get('some-id', {'name': 'value'});
    }
    
    // Executes a GET request to 'http://host:port/path/some-id?name=value'
    call();

    Decoders, basicAuthentication and requestInterceptors are all special forms of the more generic interceptors which could be chained per request/response.

    // Configure a text based decoder
    const client = Pretend.builder()
      .decoder(Pretend.TextDecoder)
      .target(Test, 'http://host:port/');
    // Configure basic authentication
    const client = Pretend.builder()
      .basicAuthentication('user', 'pass')
      .target(Test, 'http://host:port/');
    // Configure a request interceptor
    const client = Pretend.builder()
      .requestInterceptor((request) => {
        request.options.headers['X-Custom-Header'] = 'value';
        return request;
      })
      .target(Test, 'http://host:port/');

    Interceptors

    Multiple interceptors could be added to each builder. The order of interceptor calls will result in a chain of calls like illistrated below:

    // Configure a request interceptor
    const client = Pretend.builder()
      .interceptor(async (chain, request) => {
        console.log('interceptor 1: request');
        const response = await chain(request);
        console.log('interceptor 1: response');
        return response;
      })
      .interceptor(async (chain, request) => {
        console.log('interceptor 2: request');
        const response = await chain(request);
        console.log('interceptor 2: response');
        return response;
      })
      .target(Test, 'http://host:port/');
                 +---------------+    +---------------+
    Request ---> |               | -> |               |
                 | Interceptor 1 |    | Interceptor 2 | -> HTTP REST call
    Response <-- |               | <- |               |
                 +---------------+    +---------------+
    

    This leads to the following console output:

    interceptor 1: request
    interceptor 2: request
    interceptor 2: response
    interceptor 1: response
    

    Data Mappers

    DataMappers could be used to map response structures to TypeScript classes. This is done using the @ResponseType decorator.

    class User {
      public name: string;
    
      constuctor(data: { name: string }) {
        this.name = data.name;
      }
    }
    
    class API {
      @Get('/path/{id}')
      @ResponseType(User)
      public async loadUser(id: string): Promise<User> {
        /*
         * `/path/{id}` returns a JSON like this from the server:
         *
         *  {
         *    name: 'some string'
         *  }
         */
      }
    }
    
    const client = Pretend.builder().target(API, 'http://host:port/');
    const result: User = await client.loadUser(1);

    There is a second parameter to the @ResponseType decorator which is a transform function. The input is the server response, the output need to match the class constructor parameters.

    Note: The constructor parameters are always an array!

    class User {
      public get name(): string {
        return this.data.name;
      }
    
      constuctor(private data: { name: string }) {}
    }
    
    class API {
      @Get('/path/{id}')
      @ResponseType(User, (data) => [
        { name: `${data.firstname} ${data.lastname}` }
      ])
      public async loadUser(id: string): Promise<User> {
        /*
         * `/path/{id}` returns a JSON like this from the server:
         *
         *  {
         *    firstname: 'John',
         *    lastname: 'Doe'
         *  }
         */
      }
    }
    
    const client = Pretend.builder().target(API, 'http://host:port/');
    const result: User = await client.loadUser(1);

    Future ideas / Roadmap

    • Named parameters

    Keywords

    none

    Install

    npm i pretend

    DownloadsWeekly Downloads

    69

    Version

    3.1.1

    License

    MIT

    Unpacked Size

    134 kB

    Total Files

    17

    Last publish

    Collaborators

    • knisterpeter