@keeex/sdk-helper
v2.3.2
Published
Shared code for SDK libraries
Downloads
15
Readme
@keeex/sdk-helper
General description
Shared code to build SDK libraries.
Features:
- Simplified raw HTTP calls
- Authentication
- Handling of input values transformations into either JSON or FormData
- Handling of file inputs
- Handling of generic pagination values
- Handling of URI arguments and query arguments
- Handling of file replies
- Grabing useful data from complex reply
- Progress callback
- Concurrent request limitation
- Separate request queues
- Input/output filtering
Usage
Setting up a SDK using this library is done by providing settings describing how the API is accessed, as well as individual descriptions for all API calls. These individual descriptions are used to create functions that can be used to call the API directly.
Short example:
import SdkBase from "@keeex/sdk-helper/lib/sdk.js";
import {
toAPI as dateToAPI,
fromAPI as dateFromAPI,
} from "@keeex/sdk-helper/lib/filters/date";
const routeFilter = {
toAPI: {lastKnownDate: dateToAPI},
fromAPI: {newDate: dateFromAPI},
};
export default class Sdk extends SdkBase {
public retrieveDate;
constructor(config) {
super(
{baseURL: config.uri},
{},
{type: "autocookie"},
);
this.retrieveDate = this.directApiCall<{lastKnownDate: Date}, {newDate: Date}}({
method: "post",
route: "/api/v1/date/retrieve",
authenticated: false,
filters: routeFilter,
replyDataPath: "",
});
}
}
const sdk = new Sdk({uri: "https://invalid.invalid"});
const result = await sdk.retrieveDate({lastKnownDate: new Date()});
console.log("Reply:", result.newDate);
The above example create an SDK that exposes only one function called
retrieveDate
.
This function takes as input an object with all the inputs (in this case there
is only one property: lastKnownDate
).
It then returns the full reply from the server with one property: newDate
.
The filter automatically convert a Date
object into its ISO8601 string
representation before the call, and converts the reply back from an ISO8601
string representation to a Date
object.
An alternative to directApiCall()
named createApiCall()
exists; it will return an object
exposing the raw reply body as well as the HTTP status code alongside the filtered data.
Pagination
Instead of directApiCall()
it is possible to call paginatedApiCall()
.
In that case the input accepts extra PaginationInput
fields, and the reply will follow the
PaginatedResponse
interface.
Authentication
This library handles two types of authentication: HTTP-header based and cookie
based.
The third argument of the Sdk
class constructor defines the authorization
scheme to use.
If not provided, no authorization is handled.
If provided, routes that are defined with the authenticated
property to true
requires the user to previously be authenticated.
To indicate to an Sdk
instance that authentication completed, call the
setAuthToken()
method with a suitable value.
undefined
or any other false-y value indicates no authentication.
Cookie-based authentication
This mode is basically a passthrough.
Cookies are handled by the browser.
To use this method of authentication, pass a config object with the single
property type
set to autocookie
.
HTTP-header based authentication
This mode allows the caller to provide a value passed as an HTTP header.
In this case setAuthToken())
expects a non-empty string argument to indicate
authentication.
To use this method, pass a config object with the following properties:
type
: must beheader
headerName
: name of the header to use. Defaults toAuthorization
valueTemplate
: a template for the value of the header; the word%token%
will be replaced by the provided token. Defaults toBearer %token%
Defining API routes
To create a function that implements an API route, the directApiCall()
method
must be called.
It takes a single parameter which define the behavior of the route.
It is an object with the following properties (all properties are optional
except for route
):
route
: path to the API route relative to the base URLqueue
: request queue to use. Defaults to a default queue.method
: HTTP method. Defaults to GET.authenticated
: true to restrict this call when non authenticatedqueryParams
: list of "input" properties to pass as query argumentsbodyParams
: list of "input" properties to pass in the bodyfileParams
: list of "input" properties that are expected to be filesaxiosOptions
: custom axios optionspaginated
: true to handle special pagination "input" values (deprecated, see Pagination)replyDataPath
: JSON path in the reply where the useful output is locatedfilters
: filters to apply to input arguments and output values
The function returned by this call accepts a single parameter which is an "input" object. This "input" object's properties will then be parsed accordingly to the API specification.
URI arguments
It is possible to use some part of the "input" as URI arguments.
To do so, sections of the route
must start with a :
character.
For example, a route defined by /api/v1/item/:id
will grab the id
property
from the "input" object and put it in the URI before the request is performed.
Query arguments
All properties names passed into queryParams
will be appended to the route
using ?key=value
accordingly.
Body arguments
All properties names passed into bodyParams
will be put in either a JSON
object sent as the body for the request, or into a multipart/form-data
,
depending on the presence of files or not in that request.
File arguments
If fileParams
is present, the body will be a multipart/form-data
body and
treat the properties names in fileParams
as files to be appended to it.
The file who's properties names are in fileParams
are required unless the
properties names are prefixed with ?
.
Getting JSON path from reply
A minor feature is the ability to directly return a specific value from the
reply.
A "JSON" path can be specified (properties names separated with a .
).
Once a request complete, this path will be used and the value located in the
given property will be returned.
This path is specified in the replyDataPath
property of an API route
definition.
This library have three behavior regarding this:
undefined
: do not return anything- empty: return everything
- a path: return only the value pointed by the path
File replies
If a route returns a binary blob (a file) a special replyDataPath
value should
be provided to handle it.
The value can be either <stream>
or <arraybuffer>
.
In both case the reply will be returned as-is from axios
.
Progress callback
Functions returned by directApiCall()
accepts a second parameter: a function
that will be called regularly during the upload/download process.
This functions takes two arguments: the first is the progress percentage, the
second is a boolean set to true if we're in the upload phase.
Queue control
The default setting of this library is to not allow more than two concurrent
requests on a single queue.
However, to allow for long operations to coexist with short requests, it is
possible to specify which "queue" is used by an API call.
By putting a queue name on the queue
property of an API call description, it
can use a separate queue.
There is no restriction to the number of queues; keep in mind however that running too many concurrent requests can results in dropped replies in some circumstances.
If no queue name is provided a default queue is used.
Data filtering
This library have a built-in option to filter/transform data before sending them to the API, and when receiving a reply.
At its core, a filter is a function that takes a value of one type and returns
(using a promise) the converted value.
The filters
property in API route definitions is an object that have two
properties:
toAPI
fromAPI
Each of these properties is an object whose keys represent the keys to filter and values are filter functions.
A special case exists, for API calls that returns a single value and not an
object.
In that case, a special property named <root>
can be set on the filters list
to be applied to the reply value itself and not on its properties.
If this property is present, no other properties will be handled.
Built-in filters
A list of built-in filters is provided in the lib/filters
directory:
binary
: conversion from/to buffers and hex/base64date
: conversion from/toDate
objects and ISO8601 string representationsfixed
: conversion from/to "fixed" decimal numbers, with fixed number of decimalsnullstring
: unify empty string andnull
values to/fromnull
Utility filters
To be able to handle complex objects, special utility filters are available. With them it is possible to filter data behind arrays and properties.
array
: apply a filter to all values of an arrayprops
: apply various filters to the properties of an object