2.3.0 • Published 16 days ago

types-to-fetchers v2.3.0

Weekly downloads
-
License
MIT
Repository
github
Last release
16 days ago

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

2.3.0

16 days ago

2.2.1

2 months ago

2.2.0

3 months ago

2.1.0

9 months ago

2.0.2

9 months ago

2.0.1

10 months ago

2.0.0

10 months ago

1.2.0

10 months ago

1.1.0

10 months ago

1.0.1

11 months ago

1.0.0

11 months ago

0.0.3

11 months ago

0.0.2

11 months ago

0.0.1

11 months ago