fetch-builder

1.1.15 • Public • Published

Fetch builder

Lightweight and extremely customizable alternative to superagent, request, axios, frisbee.

RequestOptions builder toolkit for whatwg-fetch. Easily create or extend custom fetcher options.

Features:

  • Immutable
  • Customizable and extendable options
  • Placeholders in urls, custom params serializer and placeholder mapper
  • Headers merging
  • Composable postProcess handler

Fetcher

// @flow
import 'isomorphic-fetch'
import querystring from 'querystring'
import {
    Loader,
    checkStatus,
    Fetcher,
    createSerializeParams
} from 'fetch-builder'
import type {FetcherRec} from 'fetch-builder'
 
// Fetcher with some defaults
const baseFetcher: Fetcher<any, any= new Fetcher({
    baseUrl: '/api',
    headers: {
        'Accept-Language': 'ru'
    },
    method: 'GET',
    // throws HttpError if fetch status not in range 200-300
    postProcess: checkStatus,
    serializeParams: createSerializeParams(querystring.stringify)
})
 
// Get json from response
const jsonFetcher: Fetcher<any, any= baseFetcher.copy({
    // composed with baseFetcher.postProcess
    postProcess: (response: Promise<Response>) => response.then(r => r.json())
})
 
type User = {
    id: string;
    name: string;
}
 
// fetch user
const userPromise: Promise<User= jsonFetcher.fetch({
    url: '/user/1',
})
// GET /api/user/1
 
// Or create custom user fetcher with placeholder as id
const userFetcher: Fetcher<User, {id: string, q: string}= jsonFetcher.copy({
    url: '/user/:id',
})
 
userFetcher.fetch({
    params: {
        id: '1',
        q: '2'
    }
})
// GET /api/user/1?q=2
 
type Session = {
    isLogged: boolean;
}
 
const sessionFetcher: Fetcher<Session, void= jsonFetcher.copy({
    url: '/session'
})
 
sessionFetcher.fetch()
// GET /api/session
 
const delSessionFetcher: Fetcher<Session, void= sessionFetcher.copy({
    method: 'DELETE'
})
 
delSessionFetcher.fetch()
// DELETE /api/session
 
 
// Set default credentials
const authUserFetcher: Fetcher<User, {id: string}= userFetcher.copy({
    headers: {
        'Auth': 'Token bla-bla'
    }
})
 
authUserFetcher.fetch({
    params: {
        id: '1'
    }
})
/*
GET /api/user/1
headers: {
    'Accept-Language': 'ru',
    'Auth': 'Token bla-bla'
}
*/
 
authUserFetcher.fetch({
    method: 'POST',
    body: {
        id: '1',
        name: 'test'
    },
    params: {
        id: '1'
    }
})
/*
POST /api/user/1
body: {id: 1, name: 'test'}
headers: {
    'Accept-Language': 'ru',
    'Auth': 'Token bla-bla'
}
*/

Loader

Loader is cached wrapper around Fetcher.

// @flow
 
import {Loader} from 'fetch-builder'
 
// ...
const loader = new Loader(sessionFetcher)
 
loader.fetch().then(...)
 
// Calls Fetcher once, fetch result is cached:
loader.fetch().then(...)
 
// Reset loader
loader.reset()

Repository

Repository caches Loaders by key. Key - is string, builded from sorted FetcherRec.params values.

// @flow
 
import {Repository} from 'fetch-builder'
 
// ...
const repository = new Repository(authUserFetcher)
 
// New fetch:
repository.fetch({
    params: {
        id: '1'
    }
}).then(...)
 
// params.id is changed: new fetch:
repository.fetch({
    params: {
        id: '2'
    }
}).then(...)
 
// From cache:
repository.fetch({
    params: {
        id: '1'
    }
}).then(...)
 
// From cache:
repository.fetch({
    params: {
        id: '2'
    }
}).then(...)
 
// Reset user 1:
repository.reset({
    params: {
        id: '1'
    }
})
 
// Reset all
repository.reset()

Custom cache key getter:

// @flow
function myGetKey(rec: FetcherRec<*>): string {
    const params: {[id: string]string} = rec.params || {}
    return Object.keys(params).sort().map((key: string) => params[key]).join('.')
}
 
const repository = new Repository(authUserFetcher, myGetkey)

Interface of Fetcher constructor

 
export type PostProcess<I, O> = (params: I=> O
export type Preprocess<Result, Params>
    = (req: IFetcher<Result, Params>) => Promise<IFetcher<Result, Params>>
 
export type FetcherRec<Params: Object> = {
    /**
     * `baseUrl` will be prepended to `url`.
     *
     * Supported placeholders like `:id`.
     *
     * @example https://some-server.org/
     */
    baseUrl?: ?string;
 
    /**
     * Relative server url.
     *
     * Supported placeholders like `:id`.
     *
     * @example /user/:id
     */
    url?: ?string;
 
    /**
     * Url parameters key-value dict.
     *
     * If exists url placeholder with key, this value replaces url placeholder.
     * If no placeholder found - parameters adds as querystring.
     *
     * @example /user/:id/:some + {id: 1, some: 'test'} = /user/1?some=test
     */
    params?: ?Params;
 
    /**
     * Params serializer function.
     *
     * @example
     ```js
     //@flow
     function serializeParams(url: string, params: ?Object): string {
         const qStr: ?string = params ? querystring.stringify(params) : null
         return url + (qStr ? ('?' + qStr) : '')
     }
     ```
     */
    serializeParams?: ?SerializeParams;
 
    /**
     * Composable postProcess function.
     *
     * @example
     * ```js
     * // @flow
     *
     * function postProcess<Result>(response: Promise<Response>): Promise<Result> {
     *     return response.then(r => r.json)
     * }
     *
     * fetch(fullUrl, options).then(postProcess)
     * ```
     */
    postProcess?: ?PostProcess<*, *>;
 
    /**
     * Preprocess Request options before fetch
     *
     * @example
     * ```js
     * // @flow
     *
     * function preProcess<R, P>(opts: IFetcher<R, P>): Promise<IFetcher<R, P>> {
     *     return Promise.resolve(opts)
     * }
     *
     * preprocess(fetcher).then((f) => fetch(f.fullUrl, f.options).then(f.postProcess))
     * ```
     */
    preProcess?: ?Preprocess<*, *>;
 
    /**
     * Whatwg fetch function, default to global fetch
     */
    fetchFn?: ?FetchFn;
 
    /**
     * Request body.
     *
     * Plain objects will be searilzed to json string.
     */
    body?: ?(Blob | FormData | URLSearchParams | string | Object);
 
    /**
     * Below parameters from RequestOptions
     *
     * @see RequestOptions in https://github.com/facebook/flow/blob/master/lib/bom.js
     */
    cache?: ?CacheType;
    credentials?: ?CredentialsType;
    headers?: ?HeadersInit;
    integrity?: ?string;
    method?: ?MethodType;
    mode?: ?ModeType;
    redirect?: ?RedirectType;
    referrer?: ?string;
    referrerPolicy?: ?ReferrerPolicyType;
}
 
export interface IFetcher<Result, Params: Object> {
    /**
     * Request options.
     */
    optionsRequestOptions;
 
    /**
     * Generated full url from baseUrl, url and params.
     */
    fullUrlstring;
 
    /**
     * Composable fetch.then postProcess function.
     */
    postProcess: (responsePromise<Response>) => Promise<Result>;
 
    /**
     * Create new copy of Fetcher with some options redefined.
     *
     * Headers will be merged with existing headers.
     * postProcess will be composed with existing postProcess.
     */
    copy<R, PObject>(recFetcherRec<P>): IFetcher<R, P>;
 
    /**
     * Fetch data
     *
     */
    fetch(rec?: FetcherRec<*>): Promise<Result>;
}

License

MIT

Package Sidebar

Install

npm i fetch-builder

Weekly Downloads

15

Version

1.1.15

License

MIT

Last publish

Collaborators

  • zerkalica