A simple, lightweight & framework agnostic JSON:API client using Axios
npm install kitsuA simple, lightweight & framework agnostic JSON:API client using Axios
Migration guide for v11 & previous major releases
#
* JSON-API 1.0 compliant
* Automatically links relationships to data
* Works in Node & browsers
* Uses the [Promise] API
| Package | Package
Size\* | ESM Size | Node† | Chrome† | Firefox† | Safari† | Edge† |
| ------: | :-----------------: | :--------: | :---: | :------: | :------: | :-----: | :----: |
| kitsu | ≤ 17.72 kb | ≤ 17.46 KB | 18+ | 116+ | 118+ | 17.1+ | 134+ |
\* Including all dependencies & minified with brotli
† Guaranteed supported versions. Older versions may still work or might require polyfills
Object from a GET Response by a JSON:API Server
``json5`
{
data: {
id: '1'
type: 'articles'
attributes: {
title: 'JSON API paints my bikeshed'
}
relationships: {
author: {
data: {
id: '42'
type: 'people'
}
}
}
}
included: [
{
id: '42'
type: 'people'
attributes: {
name: 'John'
}
}
]
}
Object from a GET Response with kitsu:
`json5`
{
data: {
id: '1'
type: 'articles'
title: 'JSON API paints my bikeshed'
author: {
data: {
id: '42'
type: 'people'
name: 'John'
}
}
}
}
`bash`
yarn add kitsu
npm install kitsu
`js`
import Kitsu from "kitsu"; // ES Modules & Babel
const Kitsu = require("kitsu"); // CommonJS & Browserify
`javascript
// kitsu.app's API
const api = new Kitsu()
// Other JSON:API servers
const api = new Kitsu({
baseURL: 'https://api.example/2'
})
// Using with async/await
const res = await api.get('anime')
// Using with Promises
api.get('anime')
.then(res => { ... })
.catch(err => { ... })
// Fetching resources (get/fetch)
api.fetch('anime')
api.fetch('anime', { params: { filter: { id: 1 } } })
api.fetch('anime/1/episodes')
api.fetch('anime/1/relationships/episodes')
// Creating resources (post/create)
api.create('post', {
content: 'some content'
})
// Updating resources (patch/update)
api.update('post', {
id: '1',
content: 'new content'
})
// Deleting resources (delete/remove)
api.remove('post', 1)
// JSON:API parameters
api.get('users', {
params: {
include: 'followers,waifu.character',
fields: {
users: 'slug,followers,waifu'
},
filter: {
slug: 'wopian'
},
sort: '-id',
page: {
limit: 5,
offset: 0
}
}
})
`
[More Examples]
If you're working with [kitsu.app]'s API, their [API docs][kitsu.app api docs] lists all available resources with their attributes & relationships
See [CONTRIBUTING]
See [CHANGELOG]
All code released under [MIT]
[kitsu.app]: https://kitsu.app
[json:api]: http://jsonapi.org
[promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises
[more examples]: https://github.com/wopian/kitsu/tree/master/packages/kitsu/example
[kitsu.app api docs]: https://kitsu.docs.apiary.io
[migration guide]: https://github.com/wopian/kitsu/blob/master/packages/kitsu/MIGRATING.md
[changelog]: https://github.com/wopian/kitsu/blob/master/packages/kitsu/CHANGELOG.md
[contributing]: https://github.com/wopian/kitsu/blob/master/CONTRIBUTING.md
[mit]: https://github.com/wopian/kitsu/blob/master/LICENSE.md
#### Table of Contents
* Kitsu
* Parameters
* Examples
* plural
* Examples
* headers
* Examples
* interceptors
* Examples
* get
* Parameters
* Examples
* patch
* Parameters
* Examples
* post
* Parameters
* Examples
* delete
* Parameters
* Examples
* self
* Parameters
* Examples
* request
* Parameters
* Examples
packages/kitsu/src/index.js:39-577
Creates a new kitsu instance
#### Parameters
* options Object? Options (optional, default {})
* options.baseURL string Set the API endpoint (optional, default 'https://kitsu.app/api/edge')options.headers
* Object? Additional headers to send with the requestsoptions.query
* ("traditional" | "modern" | Function) Query serializer function to use. This will impact the way keys are serialized when passing arrays as query parameters. 'modern' is recommended for new projects. (optional, default traditional)options.camelCaseTypes
* boolean If enabled, type will be converted to camelCase from kebab-casae or snake\_case (optional, default true)options.resourceCase
* ("kebab" | "snake" | "none") Case to convert camelCase to. kebab - /library-entries; snake - /library\_entries; none-/libraryEntries\ (optional, default kebab)
* options.pluralize boolean If enabled, /user will become /users in the URL request and type will be pluralized in POST, PATCH and DELETE requests (optional, default true)
* options.timeout number Set the request timeout in milliseconds (optional, default 30000)
* options.axiosOptions Object? Additional options for the axios instance (see axios/axios#request-config for details)
* options.hoistData boolean If enabled, the contents of the data property will be hoisted to the parent. This provides a flatter response object, but removes access to links and meta properties. It will transform:``js`
{ data: { id: '1', type: 'people', coworkers: data: [ { id: '2', type: 'people' } ] } }
into the following:`js`
{ id: '1', type: 'people', coworkers: [ { id: '2', type: 'people' } ] }
(optional, default false)
#### Examples
Using with kitsu.app's API
`javascript`
const api = new Kitsu()
Using another API server
`javascript`
const api = new Kitsu({
baseURL: 'https://api.example.org/2'
})
Setting headers
`javascript`
const api = new Kitsu({
headers: {
'User-Agent': 'MyApp/1.0.0 (github.com/username/repo)',
Authorization: 'Bearer 1234567890'
}
})
#### plural
packages/kitsu/src/index.js:66-67
* See:
* See: Kitsu constructor options for disabling pluralization
If pluralization is enabled (default, see Kitsu constructor docs) then pluralization rules can be added
##### Examples
Adding an uncountable pluralization rule
`javascript`
api.plural.plural('paper') //=> 'papers'
api.plural.addUncountableRule('paper')
api.plural.plural('paper') //=> 'paper'
#### headers
packages/kitsu/src/index.js:81-81
Get the current headers or add additional headers
##### Examples
Get all headers
`javascript`
api.headers
Get a single header's value
`javascript`
api.headers['User-Agent']
Add or update a header's value
`javascript`
api.headers['Authorization'] = 'Bearer 1234567890'
Returns Object All the current headers
#### interceptors
packages/kitsu/src/index.js:130-130
* See:
Axios Interceptors (alias of axios.interceptors)
You can intercept responses before they are handled by get, post, patch and delete and before requests are sent to the API server.
##### Examples
Request Interceptor
`javascript`
// Add a request interceptor
api.interceptors.request.use(config => {
// Do something before request is sent
return config
}, error => {
// Do something with the request error
return Promise.reject(error)
})
Response Interceptor
`javascript`
// Add a response interceptor
api.interceptors.response.use(response => {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response
}, error => {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error)
})
Removing Interceptors
`javascript`
const myInterceptor = api.interceptors.request.use(function () {...})
api.interceptors.request.eject(myInterceptor)
#### get
packages/kitsu/src/index.js:228-263
Fetch resources (alias fetch)
##### Parameters
* model string Resource to fetch data from. Expected formats are :resource, :resource/:id, :resource/:id/:relationship or :resource/:id/relationships/:relationshipconfig
* Object? Additional configuration (optional, default {})
* config.headers Object? Additional headers to send with the requestconfig.params
* Object? JSON:API request queries. JSON:API query parameters not listed are supported
* config.params.fields Object? Return a sparse fieldset with only the included attributes/relationships - JSON:API Sparse Fieldsetsconfig.params.filter
* Object? Filter dataset by attribute values - JSON:API Filteringconfig.params.include
* string? Include relationship data - JSON:API Includesconfig.params.sort
* string? Sort dataset by one or more comma separated attributes (prepend - for descending order) - JSON:API Sortingconfig.params.page
* Object? JSON:API Pagination. All pagination strategies are supported, even if they are not listed below.
* config.params.page.limit number? Number of resources to return in request (Offset-based) - Note: For kitsu.app, max is 20 except on libraryEntries which has a max of 500config.params.page.offset
* number? Number of resources to offset the dataset by (Offset-based)config.params.page.number
* number? Page of resources to return in request (Page-based) - Note: Not supported on kitsu.appconfig.params.page.size
* number? Number of resources to return in request (Page-based and cursor-based) - Note: Not supported on kitsu.appconfig.params.page.before
* string? Get the previous page of resources (Cursor-based) - Note: Not Supported on kitsu.appconfig.params.page.after
* string? Get the next page of resources (Cursor-based) - Note: Not Supported on kitsu.appconfig.axiosOptions
* Object? Additional options for the axios instance (see axios/axios#request-config for details)
##### Examples
Getting a resource with JSON:API parameters
`javascript`
api.get('users', {
params: {
fields: {
users: 'name,birthday'
},
filter: {
name: 'wopian'
}
}
})
Getting a collection of resources with their relationships
`javascript`
api.get('anime', {
params: {
include: 'categories'
}
})
Getting a single resource by ID (method one)
`javascript`
api.get('anime/2', {
params: {
include: 'categories'
}
})
Getting a single resource by ID (method two)
`javascript`
api.get('anime', {
params: {
include: 'categories',
filter: { id: '2' }
}
})
Getting a resource's relationship data only
`javascript`
api.get('anime/2/categories')
Getting a resource with nested JSON:API filters (not supported by kitsu.app's API)
`javascript`
// resource?filter[x][y]=value
api.get('resource', {
params: {
filter: {
x: {
y: 'value'
}
}
}
})
Handling errors (async/await)
`javascript`
try {
const { data } = await api.get('anime')
} catch (err) {
// Array of JSON:API errors: http://jsonapi.org/format/#error-objects
if (err.errors) err.errors.forEach(error => { ... })
// Error type (Error, TypeError etc.)
err.name
// Error message
err.message
// Axios request parameters
err.config
// Axios response parameters
err.response
}
Handling errors (Promises)
`javascript`
api.get('anime')
.then(({ data }) => { ... })
.catch(err => {
// Array of JSON:API errors: http://jsonapi.org/format/#error-objects
if (err.errors) err.errors.forEach(error => { ... })
// Error type (Error, TypeError etc.)
err.name
// Error message
err.message
// Axios request parameters
err.config
// Axios response parameters
err.response
})
Returns Promise<Object> JSON-parsed response
#### patch
packages/kitsu/src/index.js:299-333
Update a resource (alias update)
##### Parameters
* model string Resource to update data in. Expected formats are :resource, :resource/:id, :resource/:id/:relationship or :resource/:id/relationships/:relationshipbody
* (Object | Array<Object>) Data to send in the requestconfig
* Object? Additional configuration (optional, default {})
* config.params Object? JSON:API request queries. See #get for documentationconfig.headers
* Object? Additional headers to send with the requestconfig.axiosOptions
* Object? Additional options for the axios instance (see axios/axios#request-config for details)
##### Examples
Update a resource
`javascript`
api.update('posts', {
id: '1',
content: 'Goodbye World'
})
Update a resource with relationships
`javascript`
api.update('posts', {
content: 'Hello World',
uploads: {
id: '167585',
type: 'uploads'
}
})
Clear to-one relationships from a resource
`javascript`
api.update('posts/1/relationships/uploads', null)
Clear to-many relationships from a resource
`javascript`
api.update('posts/1/relationships/uploads', [])
Update multiple resources (API must support the Bulk Extension)
`javascript`
api.update('posts', [
{ id: '1', content: 'Hello World' },
{ id: '2', content: 'Another post' }
])
Returns Promise<(Object | Array<Object>)> JSON-parsed response
#### post
packages/kitsu/src/index.js:368-400
Create a new resource (alias create)
##### Parameters
* model string Resource to create. Expected formats are :resource, :resource/:id, :resource/:id/:relationship or :resource/:id/relationships/:relationshipbody
* (Object | Array<Object>) Data to send in the requestconfig
* Object? Additional configuration (optional, default {})
* config.params Object? JSON:API request queries. See #get for documentationconfig.headers
* Object? Additional headers to send with the requestconfig.axiosOptions
* Object? Additional options for the axios instance (see axios/axios#request-config for details)
##### Examples
Create a post on a user's profile feed
`javascript`
api.create('posts', {
content: 'Hello World',
targetUser: {
data: {
id: '42603',
type: 'users'
}
},
user: {
data: {
id: '42603',
type: 'users'
}
}
})
Create multiple resources (API must support the Bulk Extension)
`javascript`
api.create('posts', [
{ content: 'Hello World' },
{ content: 'Another post' }
])
Returns Promise<(Object | Array<Object>)> JSON-parsed response
#### delete
packages/kitsu/src/index.js:420-460
Remove a resource (alias remove)
##### Parameters
* model string Resource to remove. Expected formats are :resource, :resource/:id/:relationship or :resource/:id/relationships/:relationshipid
* (string | number | Array<number>) Resource ID to remove. Pass an array of IDs to delete multiple resources (Bulk Extension)config
* Object? Additional configuration (optional, default {})
* config.params Object? JSON:API request queries. See #get for documentationconfig.headers
* Object? Additional headers to send with the requestconfig.axiosOptions
* Object? Additional options for the axios instance (see axios/axios#request-config for details)
##### Examples
Remove one or more relationships from a resource
`javascript`
api.delete('posts/1/relationships/uploads', [456, 789])
Remove a single resource
`javascript`
api.delete('posts', 123)
Remove multiple resources (API must support the Bulk Extension)
`javascript`
api.delete('posts', [ 1, 2 ])
Returns Promise<(Object | Array<Object>)> JSON-parsed response
#### self
packages/kitsu/src/index.js:484-493
Get the authenticated user's data
Note Requires the JSON:API server to support filter[self]=true
##### Parameters
* config Object? Additional configuration (optional, default {})
* config.params Object? JSON:API request queries. See #get for documentationconfig.headers
* Object? Additional headers to send with the requestconfig.axiosOptions
* Object? Additional options for the axios instance (see axios/axios#request-config for details)
##### Examples
Get the authenticated user's resource
`javascript`
api.self()
Using JSON:API parameters
`javascript`
api.self({
params: {
fields: {
users: 'name,birthday'
}
}
})
Returns Promise<Object> JSON-parsed response
#### request
packages/kitsu/src/index.js:548-576
Send arbitrary requests
Note Planned changes to the get, patch, post and delete methods in a future major release may make this method redundent. See
##### Parameters
* config Object Request configuration
* config.body (Object | Array<Object>)? Data to send in the requestconfig.method
* string? Request method - GET, PATCH, POST or DELETE (defaults to GET, case-insensitive)config.params
* Object? JSON:API request queries. See #get for documentationconfig.type
* string The resource typeconfig.url
* string The URL path of the resourceconfig.headers
* Object? Additional headers to send with the requestconfig.axiosOptions
* Object? Additional options for the axios instance (see axios/axios#request-config for details)
##### Examples
Raw GET request
`javascript`
api.request({
url: 'anime/1/mappings',
type: 'mappings',
params: { filter: { externalSite: 'aozora' } }
})
Raw PATCH request
`javascript`
api.request({
method: 'PATCH',
url: 'anime',
type: 'anime',
body: { id: '1', subtype: 'tv' }
})
Raw POST request
`javascript`
api.request({
method: 'PATCH',
url: 'anime',
type: 'anime',
body: { subtype: 'tv' }
})
Raw DELETE request
`javascript`
api.request({
method: 'DELETE',
url: 'anime/1',
type: 'anime',
body: { id: '1' }
})
Bulk Extension support (PATCH, POST & DELETE)
`javascript``
api.request({
method: 'PATCH',
url: 'anime',
type: 'anime',
body: [
{ id: '1', subtype: 'tv' }
{ id: '2', subtype: 'ona' }
]
})