
Research
2025 Report: Destructive Malware in Open Source Packages
Destructive malware is rising across open source registries, using delays and kill switches to wipe code, break builds, and disrupt CI/CD.
A simple, lightweight & framework agnostic JSON:API client using Axios
Migration guide for v11 & previous major releases
| 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
{
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'
}
}
]
}
{
data: {
id: '1'
type: 'articles'
title: 'JSON API paints my bikeshed'
author: {
data: {
id: '42'
type: 'people'
name: 'John'
}
}
}
}
yarn add kitsu
npm install kitsu
import Kitsu from "kitsu"; // ES Modules & Babel
const Kitsu = require("kitsu"); // CommonJS & Browserify
// 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
}
}
})
If you're working with kitsu.app's API, their API docs lists all available resources with their attributes & relationships
See CONTRIBUTING
See CHANGELOG
All code released under MIT
packages/kitsu/src/index.js:39-577
Creates a new kitsu instance
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)Using with kitsu.app'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'
}
})
packages/kitsu/src/index.js:66-67
If pluralization is enabled (default, see Kitsu constructor docs) then pluralization rules can be added
Adding an uncountable pluralization rule
api.plural.plural('paper') //=> 'papers'
api.plural.addUncountableRule('paper')
api.plural.plural('paper') //=> 'paper'
packages/kitsu/src/index.js:81-81
Get the current headers or add additional headers
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
packages/kitsu/src/index.js:130-130
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.
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)
packages/kitsu/src/index.js:228-263
Fetch resources (alias fetch)
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.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)
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.app'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 Promise<Object> JSON-parsed response
packages/kitsu/src/index.js:299-333
Update a resource (alias update)
model string Resource to update data in. Expected formats are :resource, :resource/:id, :resource/:id/:relationship or :resource/:id/relationships/:relationship
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)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 Promise<(Object | Array<Object>)> JSON-parsed response
packages/kitsu/src/index.js:368-400
Create a new resource (alias create)
model string Resource to create. Expected formats are :resource, :resource/:id, :resource/:id/:relationship or :resource/:id/relationships/:relationship
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)Create a post on a user's profile feed
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)
api.create('posts', [
{ content: 'Hello World' },
{ content: 'Another post' }
])
Returns Promise<(Object | Array<Object>)> JSON-parsed response
packages/kitsu/src/index.js:420-460
Remove a resource (alias remove)
model string Resource to remove. Expected formats are :resource, :resource/:id/:relationship or :resource/:id/relationships/:relationship
id (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)Remove one or more relationships from a resource
api.delete('posts/1/relationships/uploads', [456, 789])
Remove a single resource
api.delete('posts', 123)
Remove multiple resources (API must support the Bulk Extension)
api.delete('posts', [ 1, 2 ])
Returns Promise<(Object | Array<Object>)> JSON-parsed response
packages/kitsu/src/index.js:484-493
Get the authenticated user's data
Note Requires the JSON:API server to support filter[self]=true
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)Get the authenticated user's resource
api.self()
Using JSON:API parameters
api.self({
params: {
fields: {
users: 'name,birthday'
}
}
})
Returns Promise<Object> JSON-parsed response
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 https://github.com/wopian/kitsu/issues/415 for details.
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)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' }
]
})
FAQs
A simple, lightweight & framework agnostic JSON:API client using Axios
The npm package kitsu receives a total of 559 weekly downloads. As such, kitsu popularity was classified as not popular.
We found that kitsu demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
Destructive malware is rising across open source registries, using delays and kill switches to wipe code, break builds, and disrupt CI/CD.

Security News
Socket CTO Ahmad Nassri shares practical AI coding techniques, tools, and team workflows, plus what still feels noisy and why shipping remains human-led.

Research
/Security News
A five-month operation turned 27 npm packages into durable hosting for browser-run lures that mimic document-sharing portals and Microsoft sign-in, targeting 25 organizations across manufacturing, industrial automation, plastics, and healthcare for credential theft.