kitsu

A simple, lightweight & framework agnostic JSON:API client using Axios

Usage no npm install needed!

<script type="module">
  import kitsu from 'https://cdn.skypack.dev/kitsu';
</script>

README

Kitsu

npm npm deps bundlephobia types

checks coverage maintainability repoDependants

contributors sponsor

A simple, lightweight & framework agnostic JSON:API client using Axios

Migration guide for v10 & previous major releases

Features

  • JSON-API 1.0 compliant
  • Automatically links relationships to data
  • Works in Node & browsers
  • Uses the Promise API

Node / Browser Support

Package Package
Size*
ESM Size† Node Chrome Firefox Safari Edge
kitsu ≤ 8.7 kb ≤ 8.6 KB 12+ 72+ 78+ 12.1+ 86+

* Including all dependencies & minified with brotli † EcmaScript Modules package size*

Response Comparison

Object from a GET Response by a JSON:API Server
{
  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:
{
  data: {
    id: '1'
    type: 'articles'
    title: 'JSON API paints my bikeshed'
    author: {
      data: {
        id: '42'
        type: 'people'
        name: 'John'
      }
    }
  }
}

Install

Yarn / NPM

yarn add kitsu
npm install kitsu
import Kitsu from 'kitsu'      // ES Modules & Babel
const Kitsu = require('kitsu') // CommonJS & Browserify

Quick Start

// Kitsu.io'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.io's API, their API docs lists all available resources with their attributes & relationships

Contributing

See CONTRIBUTING

Releases

See CHANGELOG

License

All code released under MIT

API

Table of Contents

Kitsu

packages/kitsu/src/index.js:31-513

Creates a new kitsu instance

Parameters

  • options Object? Options (optional, default {})

    • options.baseURL string Set the API endpoint (optional, default https://kitsu.io/api/edge)
    • options.headers Object? Additional headers to send with the requests
    • 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)

Examples

Using with Kitsu.io's API

const api = new Kitsu()

Using another API server

const api = new Kitsu({
  baseURL: 'https://api.example.org/2'
})

Setting headers

const api = new Kitsu({
  headers: {
    'User-Agent': 'MyApp/1.0.0 (github.com/username/repo)',
    Authorization: 'Bearer 1234567890'
  }
})

plural

packages/kitsu/src/index.js:53-54

If pluralization is enabled (default, see Kitsu constructor docs) then pluralization rules can be added

Examples

Adding an uncountable pluralization rule

api.plural.plural('paper') //=> 'papers'
api.plural.addUncountableRule('paper')
api.plural.plural('paper') //=> 'paper'

headers

packages/kitsu/src/index.js:68-68

Get the current headers or add additional headers

Examples

Get all headers

api.headers

Get a single header's value

api.headers['User-Agent']

Add or update a header's value

api.headers['Authorization'] = 'Bearer 1234567890'

Returns Object All the current headers

interceptors

packages/kitsu/src/index.js:113-113

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

// 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

// 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

const myInterceptor = api.interceptors.request.use(function () {...})
api.interceptors.request.eject(myInterceptor)

get

packages/kitsu/src/index.js:210-238

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/:relationship

  • config Object? Additional configuration (optional, default {})

    • config.headers Object? Additional headers to send with the request

    • config.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 Fieldsets

      • config.params.filter Object? Filter dataset by attribute values - JSON:API Filtering

      • config.params.include string? Include relationship data - JSON:API Includes

      • config.params.sort string? Sort dataset by one or more comma separated attributes (prepend - for descending order) - JSON:API Sorting

      • config.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.io, max is 20 except on libraryEntries which has a max of 500
        • config.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.io
        • config.params.page.size number? Number of resources to return in request (Page-based and cursor-based) - Note: Not supported on Kitsu.io
        • config.params.page.before string? Get the previous page of resources (Cursor-based) - Note: Not Supported on Kitsu.io
        • config.params.page.after string? Get the next page of resources (Cursor-based) - Note: Not Supported on Kitsu.io
Examples

Getting a resource with JSON:API parameters

api.get('users', {
  params: {
    fields: {
      users: 'name,birthday'
    },
    filter: {
      name: 'wopian'
    }
  }
})

Getting a collection of resources with their relationships

api.get('anime', {
  params: {
    include: 'categories'
  }
})

Getting a single resource by ID (method one)

api.get('anime/2', {
  params: {
    include: 'categories'
  }
})

Getting a single resource by ID (method two)

api.get('anime', {
  params: {
    include: 'categories',
    filter: { id: '2' }
 }
})

Getting a resource's relationship data only

api.get('anime/2/categories')

Getting a resource with nested JSON:API filters (not supported by Kitsu.io's API)

// resource?filter[x][y]=value
api.get('resource', {
  params: {
    filter: {
      x: {
        y: 'value'
      }
    }
  }
}

Handling errors (async/await)

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)

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 Object JSON-parsed response

patch

packages/kitsu/src/index.js:273-300

Update a resource (alias update)

Parameters
Examples

Update a resource

api.update('posts', {
  id: '1',
  content: 'Goodbye World'
})

Update a resource with relationships

api.update('posts', {
  content: 'Hello World',
  uploads: {
    id: '167585',
    type: 'uploads'
  }
})

Clear to-one relationships from a resource

api.update('posts/1/relationships/uploads', null)

Clear to-many relationships from a resource

api.update('posts/1/relationships/uploads', [])

Update multiple resources (API must support the Bulk Extension)

api.update('posts', [
  { id: '1', content: 'Hello World' },
  { id: '2', content: 'Another post' }
])

Returns (Object | Array<Object>) JSON-parsed response

post

packages/kitsu/src/index.js:330-355

Create a new resource (alias create)

Parameters
Examples

Create a post on a user's profile feed

api.create('posts', {
  content: 'Hello World',
  targetUser: {
    id: '42603',
    type: 'users'
  },
  user: {
    id: '42603',
    type: 'users'
  }
})

Create multiple resources (API must support the Bulk Extension)

api.create('posts', [
  { content: 'Hello World' },
  { content: 'Another post' }
])

Returns (Object | Array<Object>) JSON-parsed response

delete

packages/kitsu/src/index.js:372-405

Remove a resource (alias remove)

Parameters
Examples

Remove a single resource

api.delete('posts', 123)

Remove multiple resources (API must support the Bulk Extension)

api.delete('posts', [ 1, 2 ])

Returns (Object | Array<Object>) JSON-parsed response

self

packages/kitsu/src/index.js:428-437

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 documentation
    • config.headers Object? Additional headers to send with the request
Examples

Get the authenticated user's resource

api.self()

Using JSON:API parameters

api.self({
  params: {
    fields: {
      users: 'name,birthday'
    }
  }
})

Returns Object JSON-parsed response

request

packages/kitsu/src/index.js:491-512

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 https://github.com/wopian/kitsu/issues/415 for details.

Parameters
  • config Object? Request configuration

    • config.body (Object | Array<Object>)? Data to send in the request
    • config.method string? Request method - GET, PATCH, POST or DELETE (defaults to GET, case-insensitive)
    • config.params Object? JSON:API request queries. See #get for documentation
    • config.type string The resource type
    • config.url string The URL path of the resource
    • config.headers Object? Additional headers to send with the request
Examples

Raw GET request

api.request({
  url: 'anime/1/mappings',
  type: 'mappings',
  params: { filter: { externalSite: 'aozora' } }
})

Raw PATCH request

api.request({
  method: 'PATCH',
  url: 'anime',
  type: 'anime',
  body: { id: '1', subtype: 'tv' }
})

Raw POST request

api.request({
  method: 'PATCH',
  url: 'anime',
  type: 'anime',
  body: { subtype: 'tv' }
})

Raw DELETE request

api.request({
  method: 'DELETE',
  url: 'anime/1',
  type: 'anime',
  body: { id: '1' }
})

Bulk Extension support (PATCH, POST & DELETE)

api.request({
  method: 'PATCH',
  url: 'anime',
  type: 'anime',
  body: [
    { id: '1', subtype: 'tv' }
    { id: '2', subtype: 'ona' }
  ]
})

Returns Object JSON-parsed response