Automagically create API clients/wrappers in JavaScript. This is a great alternative for when client libraries don't already exist, and they can't be easily generated from a swagger API. How does it work? ES6 proxies!
let repos = await github.users('octocat').repos.get()
// GET https://api.github.com/users/octocat/repos
The library wraps an API, returning an object that builds the target URL with each property and invocation. It performs the request when an HTTP method is invoked. Properties reserved for HTTP methods include: get, post, put, patch, delete, head, and options.
The library also comes with some sane defaults for JSON APIs. Two options are set to true by default: json and returnBody. JSON response bodies are parsed, and the response body itself is returned instead of the response object. In the example below, we also make use of the camelCase option, which creates a camelCase client for a snake_case JSON API.
let swaddle = require('swaddle')
let github = swaddle('https://api.github.com', {camelCase: true})
// GET https://api.github.com/users/octocat
let user = await github.users.get('octocat')
user.publicRepos // instead of user.public_repos
// Without async/await
github.users.get('octocat').then((user) => {
// ...
})
// GET https://api.github.com/users/octocat/repos
let repos = await github.users('octocat').get()
// GET https://api.github.com/repos/octocat/Spoon-Knife/stargazers
let stargazers = await github.repos('octocat', 'Spoon-Knife').stargazers.get()
// GET https://api.github.com/search/repositories?q=tetris
let results = await github.search.repositories.get('?q=tetris')
// Identical operations, both perform
// GET https://api.example.com/users/octocat
await github.users('octocat').get()
await github.users().get('octocat')
The library is compatible with a range of HTTP request clients,
including:
got
,
request
,
request-promise
,
whatwg-fetch
, and
node-fetch
.
None are installed as a dependency, giving you the freedom to pick your
favorite. Unless provided, it will default to trying to require got
,
request-promise
, request
, or the browser's fetch
, in that order.
let swaddle = require('swaddle')
let request = require('request')
let github = swaddle('https://api.github.com', {
fn: request // Use `request` to perform requests
})
github.users('octocat').repos.get((err, repos) => {
// GET https://api.github.com/users/octocat/repos
// request uses callbacks instead of promises
})
npm install --save swaddle
npm install got # optional
Options are passed to the underlying request library in two ways. The first, is during initialization:
let client = swaddle('https://api.example.com', {
headers: {
Authorization: 'Basic ' + Buffer.from('User:Pass').toString('base64')
}
})
Any options set during initialization will be stored and inherited by all requests to that API, unless otherwise overwritten. That is, in the following request, both basic auth and the custom header would be set:
client.search.get('?q=foo', {
headers: {'x-custom-header': 'value'}
}).then((res) => {
// ...
})
All options are passed through to the underlying request function, except for those reserved by swaddle.
Creates aliases for the supplied HTTP methods. Default: none
let swaddle = require('swaddle')
let client = swaddle('https://api.example.com', {
aliases: {create: 'post', destroy: 'delete'}
})
client.threads.create({body: {subject: 'hi'}}).then((res) => {
// POST https://api.example.com/threads
// body: '{"subject": "hi"}'
})
The request function to use. Unless provided, it will default to requiring
got
, request-promise
, request
, or the browser's fetch
, in that order.
let swaddle = require('swaddle')
let request = require('request-promise')
let client = swaddle('https://api.example.com', {
fn: request
})
Returns the response body instead of response object. Default: true
let swaddle = require('swaddle')
let client = swaddle('https://api.example.com')
client.users.get().then((res) => {
// Don't need to access res.body
})
client = swaddle('https://api.example.com', {returnBody: false})
client.users.get().then((err) => {
// Need to access res.body
})
Any literal or object passed to post, put, or patch, is set as the request body. Thus no additional headers or options can be set at the time of the request. Combined with aliases, it can prevent an otherwise leaky HTTP abstraction. Default: false
let swaddle = require('swaddle')
let client = swaddle('https://api.example.com', {
aliases: {create: 'post'},
sendAsBody: true
})
// Don't need to write:
// client.messages.post({body: 'foo'})
client.messages.create('foo').then((res) => {
// POST https://api.example.com/messages
// body: "foo"
})
Parses the JSON response. This is built into some libraries, but not all (e.g. fetch). Default: true
let swaddle = require('swaddle')
let client = swaddle('https://api.example.com')
client.users.get().then((res) => {
// res.body has been parsed
})
client = swaddle('https://api.example.com', {json: false})
client.users.get().then((res) => {
// res.body is a string response
})
Creates a camelCase client for a snake_case JSON API. Only available when both returnBody and json are set to true. Camel case properties are appended as snake case to the resulting url. Arguments passed during function invocation are unaffected. Any objects request or response body are recursively formatted. Default: false
let client = swaddle('https://api.example.com')
client.jobStatuses.get((err, res) => {
// GET http://api/job_statuses
})
client.fooBar('bazQux').get().then((res) => {
// GET http://api/foo_bar/bazQux
})
client.users(1).get().then((res) => {
// If the original response body was '{"is_admin": false}', then res is
// {isAdmin: false}
})
client.users.post({
body: {isAdmin: false, name: 'Foo Bar'}
}).then((res) => {
// POST http://api/users
// body: '{"is_admin": false, "name": "Foo Bar"}'
})
Allows you to specify an extension to be appended to any requests, required by some APIs. Default: empty
let swaddle = require('swaddle')
let client = swaddle('https://api.example.com', {
extension: 'json'
})
client.users(1).get().then((res) => {
// https://api.example.com/users/1.json
})
client.search.get('?q=foo').then((res) => {
// https://api.example.com/search.json?q=foo
})
Whitelists properties that can be accessed. Required when polyfilling Proxy support for older browsers. Note that the exception is thrown during the property access, and not during request execution. Accepts arrays of strings for top level resources, or objects with nested objects and arrays for listing sub-resources. Default: empty
// Single top level resource, /user
var client = swaddle('https://api.example.com', {
whitelist: ['users']
});
client.users().get().then((res) => {
// success
});
client.search
// Error: search not listed in swaddle's whitelist
// Can provide a combination of objects & arrays for sub-resources
// Example supports: /users, /tickets, /tickets/replies, /tickets/related
client = swaddle(BASE_URL, {
whitelist: {
users: [],
tickets: ['replies', 'related'],
}
})
client.tickets(1).replies.get().then((replies) => {
// success
})
The module has been tested and is compatible with the following module versions:
package | version |
---|---|
got |
^7 |
request |
^2.81.0 |
request-promise |
^4.2.0 |
whatwg-fetch |
^2.03 |
node-fetch |
^1.6.3 |
The library makes use of Proxies, which means it works with Node 6.4+, Chrome 49+, FF 18+, Opera 36+, Safari 10+, and Edge. For older versions of Node and browsers such as IE9+ and Safari 6+, two things are required:
- Installing a polyfill like
proxy-polyfill
- Enumerating available properties via
whitelist
This is because polyfills require that properties you want to proxy be known at creation time. In a browser with fetch, an example would then be:
var github = swaddle('https://api.github.com', {
whitelist: {users: ['repos']}
});
// Default to using fetch in the browser
github.users('octocat').repos.get().then((repos) => {
// repos
});
github.search
// Error: search not listed in swaddle's whitelist
For browsers, it's assumed that you're using browserify, webpack, or similar, to load the module with your build.