types-to-fetchers

2.3.0 • Public • Published

types-to-fetchers

NPM version Tests

Automatically creates fetchers from declarative descriptions of APIs and types. Based on axios.

Installation

Install it with yarn:

yarn add types-to-fetchers

Or with npm:

npm install types-to-fetchers

Usage

Use types that describe your API. You can use e.g. fastify-extract-definitions to automatically generate them.

Write or extract types:

interface Error {
  code: number;
  error: string;
}

interface API {
  '/': {
    GET: {
      Reply: {
        version: string;
        mode: 'production' | 'development';
      };
    };
  };
  '/foo/:bar': {
    GET: {
      Params: { bar: string };
      Reply: string;
    };
    POST: {
      Params: { bar: string };
      Body: { baz: string };
      Reply: Error | string;
    };
  };
}

Make fetchers:

const api = makeApi<API, Error>(
  {
    '/': ['GET'],
    '/foo/:bar': ['GET', 'POST'],
  },
  { baseURL: 'https://my-api.example.com/' }
);

Use it:

// POST `{ baz: 'def' }` to `/foo/abc`
const reply = await api['/foo/:bar'].POST({
  Params: { bar: 'abc' },
  Body: { baz: 'def' },
});

console.log(reply); // Error | string

Abort request

const abortController = new AbortController();

const reply = await api['/foo/:bar'].POST({
  Params: { bar: 'abc' },
  Body: { baz: 'def' },
  Axios: { signal: abortController.signal },
});

// ...

abortController.abort();

Handle File Progress

const reply = await api['/foo/:bar'].POST({
  Params: { bar: 'abc' },
  Body: { baz: 'def' },
  Axios: {
    onUploadProgress: (progressEvent) => {
      const percentCompleted = Math.round(
        (progressEvent.loaded * 100) / progressEvent.total
      );
      console.log(`Upload progress: ${percentCompleted}%`);
    },
    onDownloadProgress: (progressEvent) => {
      const percentCompleted = Math.round(
        (progressEvent.loaded * 100) / progressEvent.total
      );
      console.log(`Download progress: ${percentCompleted}%`);
    },
  },
});

Effects

You can use a callback to apply some effect to each request. For example, we will use the createEffect from the effector library.

Note: the callback fires at the time of generation, not at the time of the call.

Write custom output types (if necessary) and make fetchers:

import { Effect, createEffect } from 'effector';
import { Payload, makeApi } from 'types-to-fetchers';

type Reply<PayloadRecord extends Payload> = Exclude<
  PayloadRecord['Reply'],
  Error
>;

type Methods<MethodsRecord extends object> = {
  [Method in keyof MethodsRecord]: Effect<
    Omit<MethodsRecord[Method], 'Reply'> & AxiosOptions,
    Reply<MethodsRecord[Method]>
  >;
};

type Endpoints<EndpointsRecord extends object> = {
  [Endpoint in keyof EndpointsRecord]: Methods<EndpointsRecord[Endpoint]>;
};

type Output = Endpoints<API>;

const api = makeApi<API, Error, Output>(
  {
    '/': ['GET'],
    '/foo/:bar': ['GET', 'POST'],
  },
  {
    baseURL: 'https://my-api.example.com/',
    effect: (action) => createEffect(action),
  }
);

Use it:

import { createStore } from 'effector';

type State = {
  version: string | null;
};

const initialState: State = {
  version: null,
};

const $app = createStore<State>(initialState).on(
  api['/'].GET.doneData,
  (state, payload): State => ({
    ...state,
    version: payload.version,
  })
);
import React, { useEffect } from 'react';

const ComponentName: React.FC = () => {
  useEffect(() => {
    const abortController = new AbortController();

    api['/'].GET({ Axios: { signal: abortController.signal } });

    return () => abortController.abort();
  }, []);

  return <>...</>;
};

License

MIT

Package Sidebar

Install

npm i types-to-fetchers

Weekly Downloads

381

Version

2.3.0

License

MIT

Unpacked Size

10.8 kB

Total Files

5

Last publish

Collaborators

  • neruchev