apion
v1.0.0
Published
Light and flexible API client creation library.
Downloads
2
Readme
apion
JavaScript API client generator
Usage
Install the package apion
using npm
, yarn
or your preferred package manager. For example:
npm install apion
Import in your code:
import apion from 'apion';
// or import * as apion from 'apion'
import { json } from 'apion/helpers';
const apion = require('apion');
const { json } = require('apion/helpers');
Examples
import apion from 'apion';
import { json } from 'apion/helpers';
const apiConfg = apion.config()
.use(json)
.url('https://example.com/api');
const profile = apion.action('profile', id => api => api.query(`id=${id}`));
const auth = apion.group('auth', token => ({ token }))
.path('auth')
.headers((prev, { token }) => ({ ...prev, Authorization: token }))
.nest(profile);
const login = apion.action('login', (user, password) =>
api => api.body({ user, password })
)
.post();
const root = apion.group('root')
.use(apiConfig)
.nest(auth)
.nest(login);
const client = root.build();
// implementation
const { body: { token } } = await client.login('[email protected]', '123456');
/*
method: 'POST'
url: 'https://example.com/api/login'
headers: { 'content-type': 'application/json' }
body: '{"email":"[email protected]","password":"123456"}'
*/
const { body: profile } = await cient.auth(token).profile('abc123');
/*
method: 'GET'
url: 'https://example.com/api/auth/profile?id=abc123'
headers: { 'content-type': 'application/json', authorization: <token> }
body: -
*/
API
Methods exposed on apion
.
apion.config([name])
Create a ConfigBuilder
with an optional name
name
String: Sets the name of the configuration for reference in debugging.
import apion from 'apion';
const myConfig = apion.config('my_config')
.url('https://example.com/api')
.headers({ 'my-header': 'some value' });
const isRunning = apion.action('isRunning')
.use(myConfig)
.path('_health')
.build();
await isRunning();
/*
method: 'GET'
url: 'https://example.com/api/_health'
headers: { 'my-header': 'some value' }
body: -
*/
apion.group(name, [constructor])
Create a GroupBuilder
with a name
and an optional constructor
for dynamically setting context for nested builders
name
String: Sets the name of the group which by default is used as the name of the property added when nesting under another group or action.constructor
Function: A callback used to dynamically set the context for nested builders.
import apion from 'apion';
import { json } from 'apion/helpers';
const login = apion
.action('login', (email, password) => api => api.body({ email, password }))
.post();
const publicClient = apion.group('public')
.use(json)
.url('https://example.com/api/public')
.nest(login)
.build();
await publicClient.login('[email protected]', '123456');
/*
method: 'POST'
url: 'https://example.com/api/public/login'
headers: { 'content-type': 'application/json' }
body: '{"email":"[email protected]","password":"123456"}'
*/
constructor
Used to dynamically set properties in the context for nested builders.
const profile = apion.action('profile')
.path('profile');
const authClient = apion.group('auth', token => ({ token }))
.url('https://example.com/api/admin')
.headers((prev, { token }) => ({ ...prev, Authorization: token }))
.nest(profile)
.build();
await authClient('XXX-000-AAA').profile();
/*
method: 'GET'
url: 'https://example.com/api/admin/profile'
headers: { authorization: 'XXX-000-AAA' }
body: -
*/
It can also be used to set more complex request properies by returning a callback which receives the containing GroupBuilder
.
const profile = apion.action('profile')
.path('profile');
const userClient = apion.group('user', (user, password) =>
api => api.path(user).headers({ Authorization: password })
)
.url('https://example.com/api/admin/user')
.nest(profile)
.build();
await userClient('greg123', '456789').profile();
/*
method: 'GET'
url: 'https://example.com/api/admin/user/greg123/profile'
headers: { authorization: '456789' }
body: -
*/
apion.action(name, [constructor | requestBuilder])
name
String: Sets the name of the action which by default is used as the name of the property added when nesting under another group or action.constructor
Function: A callback used to dynamically set the context for nested builders.requestBuilder
RequestBuilder: An instance of aRequestBuilder
used to inject a simple builder pattern when constructing complex request bodies.
requestBuilder
Automatically injects a builder to be used for creating requests.
import apion from 'apion';
import { json } from 'apion/helpers';
const requestBuilder = apion.builder()
.with('range', (start, end) => ({ start, end }))
.with('interval')
.with('timezone');
const getTimeseries = apion.action('timeseries', requestBuilder)
.use(json)
.url('https://example.com/api/timeseries')
.post();
await getTimeseries((req) =>
req.range(10, 200)
.interval(25)
.timezone('UTC')
);
/*
method: 'POST'
url: 'https://example.com/api/timeseries'
headers: { 'content-type': 'application/json' }
body: '{"start":10,"end":200,"interval":25,"timezone":"UTC"}'
*/
apion.builder([formatter])
Create a RequestBuilder
with an optional formatter
formatter
Function: Sets a formatting callback to construct the final request body.
import apion from 'apion'
const searchRequestBuilder = apion.builder()
.with('query')
.with('attributes', (...attributes) => ({ attributes }))
.with('range', (start, end) => ({ range: { start, end } }));
/*
creates request bodies of the form:
{
query: any,
attibutes: any[],
range: { start: any, end: any }
}
*/
formatter
Used to format the generated request body.
import apion from 'apion'
const searchRequestBuilder =
apion.builder((payload) => ({ type: 'search', payload }))
.with('query')
.with('pageSize')
.with('sort', (attribute, order) => ({ sort: { attribute, order } }));
/*
creates request bodies of the form:
{
type: 'search',
payload: {
query: any,
pageSize: any,
sort: { attribute: any, order: any }
}
}
*/
HTTPBuilder
The base class
for ConfigBuilder
, GroupBuilder
and ActionBuilder
. Contains utility methods for managing request properties.
url(url | transform)
url
String: An full URL to set for the request, overrides the existing url.transform
Function: A callback to transform the previous value to the next value.
import apion from 'apion';
apion.config()
.url('https://example.com');
transform
A callback which is passed the previous value and the context object and should return the next value.
import apion from 'apion';
apion.config()
.ctx({ path: 'some/path' })
.url('https://example.com')
.url((prev, ctx) => `${prev}/${ctx.path}`);
port(port | transform)
port
Number: A port to set for the request, overrides the existing port.transform
Function: A callback to transform the previous value to the next value. (see transform)
import apion from 'apion';
apion.config().port(8080);
query(query | transform)
query
String: A query to set for the request, overrides the existing query.transform
Function: A callback to transform the previous value to the next value. (see transform)
import apion from 'apion';
apion.config().query('x=y&a=10');
path(path | transform)
path
String: A path to set for the request, overrides the existing path. If the path starts with a forward slash (/
) then the whole path will be replaced, otherwise it will be added to the existing path.transform
Function: A callback to transform the previous value to the next value. (see transform)
import apion from 'apion';
apion.config()
.url('https://example.com/api')
.path('my/path'); // 'https://example.com/api/my/path'
apion.config()
.url('https://example.com/api')
.path('/my/path'); // 'https://example.com/my/path'
method(method)
method
String: A method to set for the request, overrides the exting method.
apion.config()
.url('https://example.com/api')
.method('POST');
apion
also exports its ownMethod
object for easy use
import { Method } from 'apion';
apion.config()
.url('https://example.com/api')
.method(Method.POST);
get()
Sets the request method to GET
.
post()
Sets the request method to POST
.
patch()
Sets the request method to PATCH
.
put()
Sets the request method to PUT
.
delete()
Sets the request method to DELETE
.
headers(headers | transform)
headers
Object: A headers to set for the request, overrides the existing headers.transform
Function: A callback to transform the previous value to the next value. (see transform)
import apion from 'apion';
apion.config().headers({ 'content-type': 'application/json' });
body(body | transform)
body
Object: A body to set for the request, overrides the existing body.transform
Function: A callback to transform the previous value to the next value. (see transform)
import apion from 'apion';
apion.config().body('[email protected]:123456');
formatter(formatter)
Add a callback to transform the request body before sending it.
formatter
Function: A callback to transform the request body before sending it.
import apion from 'aption';
apion.config()
.formatter(body =>
typeof body === 'string' ? body : JSON.stringify(body)
);
parser(parser)
Add a callback to transform the response body after receiving it.
parser
Function: A callback to transform the response body after receiving it.
import apion from 'aption';
apion.config()
.parser(body =>
typeof body === 'string' ? JSON.parse(body) : body
);
ConfigBuilder
Used to construct re-usable updates to context and request properties. Inherits all methods from HTTPBuilder
.
ctx(obj)
Update the context by merging in a new object (uses the same logic as Object.assign()
).
obj
Object: An object that will be merged with the existing context.
import apion from 'apion';
apion.config().ctx({ id: 123 });
use(builder | createBuilder)
Add the configuration from the provided builder
or the result of the createBuilder
function to the builder instance.
builder
ConfigBuilder: Configuration from this builder will be inherited by the builder instance.createBuilder
Function: A function which accepts the context object and should return an instance of aConfigBuilder
import apion from 'apion';
const config = apion.config()
.url('https://example.com');
apion.action('isRunning')
.use(config);
createBuilder
Used to have full control over dynamically setting request properties based on the context object.
import apion from 'apion';
apion.action('login', (user) => ({ user }))
.use(({ user }) =>
user === 'admin'
? apion.config().path('admin').headers({ Authorization: 'skip' })
: apion.config().path(`user/${user}`)
)
.url('https://example.com/api');
inherit(builder)
Like use()
except that configuration transformations are pushed to the top of the builder's inheritance chain.
import apion from 'apion';
const config = apion.config()
.url('https://example.com');
apion.action('isRunning')
.use(apion.config().path('api'))
.inherit(config);
pipe(transform)
A utility method to help apply re-usable chained methods to a builder instance.
import apion from 'apion';
const configure = api => api
.url('https://example.com/api')
.headers({ 'my-header': 'some value' });
// hard to chain
const test = configure(apion.action('test'));
// easy to chain
const test = apion.action('test').pipe(configure);
extend()
Clone a builder instance in order to create an extended version of it.
import apion from 'apion';
const config = apion.config()
.url('https://example.com');
const extended = config.extend()
.path('api');
GroupBuilder
Used to construct groups of nested builders. Inherits all methods from ConfigBuilder
.
ctor(constructor)
Override or set the builder's constructor
to be used to provide dynamic context properties.
constructor
Function: A callback used to dynamically set the context for nested builders (see constructor).
import apion from 'apion';
apion.group('auth')
.ctor(token => ({ token }));
nest([name], builder)
Add a nested builder to a GroupBuilder
or ActionBuilder
.
name
String: A name to override the name on the builder.builder
GroupBuilder | ActionBuilder: A builder to be nested under this builder instance. If no name is provided, the name provided when constructing the builder will be used.
build([fetch])
Build an API client with this builder as the root node.
fetch
Function: A replacement for thefetch
instance used under the hood when making requests (defaults tocross-fetch
).
ActionBuilder
Used to construct action builders for sending requests over the network. Inherits all methods from GroupBuilder
.
ctor(constructor | requestBuilder)
Override or set the builder's constructor
to be used to provide dynamic context properties.
constructor
Function: A callback used to dynamically set the context for nested builders (see constructor).requestBuilder
RequestBuilder: An instance of aRequestBuilder
used to inject a simple builder pattern when constructing complex request bodies (see requestBuilder).
Helpers
JSON
import apion from 'apion';
import { json } from 'apion/helpers';
// JSON.stringify() request body
// JSON.parse() response body
// set 'Content-Type: application/json' header
apion.config().use(json);