Bare metal TypeScript and JavaScript client for web API implementing JSON:API v1.0.
- Zero dependency
- Type-safe
- Isomorphic
Documentations
- ES6 (ECMAScript 2015)
Using npm:
npm install -s jsonapi-metal-client
Using yarn:
yarn add jsonapi-metal-client
With ES6 modules:
import { HttpAdapters, JsonApi } from 'jsonapi-metal-client';
With CommonJS modules:
const { HttpAdapters, JsonApi } = require('jsonapi-metal-client');
const httpAdapter = new HttpAdapters.FetchHttpAdapter(window.fetch.bind(window));
const client = new JsonApi.Client(httpAdapter);
// Fetch a resource collection.
client.fetch('https://example.com/articles');
client.fetchResource('https://example.com/articles');
client.fetchResourceCollection('https://example.com/articles');
// Fetch an individual resource.
client.fetch('https://example.com/articles/1');
client.fetchResource('https://example.com/articles/1');
client.fetchResourceIndividual('https://example.com/articles/1');
// Fetch relationship data representing a to-one relationship.
client.fetch('https://example.com/articles/1/relationships/author');
client.fetchRelationship('https://example.com/articles/1/relationships/author');
client.fetchRelationshipToOne('https://example.com/articles/1/relationships/author');
// Fetch relationship data representing a to-many relationship.
client.fetch('https://example.com/articles/1/relationships/comments');
client.fetchRelationship('https://example.com/articles/1/relationships/comments');
client.fetchRelationshipToMany('https://example.com/articles/1/relationships/comments');
// Create a resource.
client.createResource(
'https://example.com/comments',
{
data: {
type: 'photos',
attributes: {
title: 'Ember Hamster',
src: 'http://example.com/images/productivity.png'
},
relationships: {
photographer: {
data: { type: 'people', id: '9' }
}
}
}
}
);
// Update a resource.
client.updateResource(
'https://example.com/articles/1',
{
data: {
type: 'articles',
id: '1',
attributes: {
title: 'To TDD or Not'
}
}
}
);
// Delete a resource.
client.deleteResource('https://example.com/photos/1');
// Update a to-one relationship.
client.updateRelationshipToOne(
'https://example.com/articles/1/relationships/author',
{
data: { type: 'people', id: '12' }
}
);
// Add a member to a to-many relationship.
client.createRelationshipToMany(
'https://example.com/articles/1/relationships/comments',
{
data: [
{ type: 'comments', id: '123' }
]
}
);
// Replace all members of a to-many relationship.
client.updateRelationshipToMany(
'https://example.com/articles/1/relationships/tags',
{
data: []
}
);
// Remove members from a to-many relationship.
client.deleteRelationshipToMany(
'https://example.com/articles/1/relationships/comments',
{
data: [
{ type: 'comments', id: '12' },
{ type: 'comments', id: '13' }
]
}
);
HTTP Adapter using the axios.
import axios from 'axios'
const httpAdapter = new HttpAdapters.AxiosHttpAdapter(
axios
);
Using custom instance:
import axios from 'axios'
const instance = axios.create({ /* ... */ });
const httpAdapter = new HttpAdapters.AxiosHttpAdapter(
instance
);
HTTP Adapter using the Fetch API.
const httpAdapter = new HttpAdapters.FetchHttpAdapter(
window.fetch.bind(window)
);
For Node.js you can install cross-fetch, or other implementations.
const fetch = require('cross-fetch');
const httpAdapter = new HttpAdapters.FetchHttpAdapter(
fetch
);
Set a default request init
options that will be merged with all the request options made by the adapter:
const defaultInit = { mode: 'cors' };
const httpAdapter = new HttpAdapters.FetchHttpAdapter(fetch, defaultInit);
client.defaultInit.credentials = 'include';
console.log(client.defaultInit);
// { mode: 'cors', credentials: 'include' }
Set the HTTP adapter.
const client = new JsonApi.Client(httpAdapter);
Set default HTTP headers to apply to each HTTP requests.
const username = 'username';
const password = 'password';
const defaultHttpHeaders = { 'Authorization': 'Basic ' + btoa(username + ':' + password) };
const client = new JsonApi.Client(httpAdapter, defaultHttpHeaders);
client.defaultHttpHeaders['x-foo'] = 'bar';
console.log(client.defaultHttpHeaders);
// { Authorization: 'Basic dXNlcm5hbWU6cGFzc3dvcmQ=', 'x-foo': 'bar' }
The client returns a Promise that resolves with a Result
for JSON:API operations with contains the properties:
Name | Type | Description |
---|---|---|
isSuccess |
boolean | whether the operation is successful. |
document |
object | JSON:API document. |
request |
object | HTTP request representation. |
response |
object | HTTP response representation. |
const result = await client.fetch('http://examples.com/articles/1');
console.log(result)
// {
// isSuccess: true,
// document: {
// links: {
// self: "http://example.com/articles/1"
// },
// data: {
// type: "articles",
// id: "1",
// attributes: {
// title: "JSON:API paints my bikeshed!"
// },
// relationships: {
// author: {
// links: {
// related: "http://example.com/articles/1/author"
// }
// }
// }
// }
// },
// request: {
// url: 'http://examples.com/articles/1',
// headers: {
// Accept: 'application/vnd.api+json'
// },
// method: 'GET',
// body: null
// },
// response: {
// status: 200,
// body: '{"type":"articles","id":"1","attributes":{"title":"JSON:API paints my bikeshed!"},"relationships":{"author":{"links":{"related":"http://example.com/articles/1/author"}}}}',
// headers: {
// 'content-type': 'application/vnd.api+json; charset=utf-8',
// etag: 'W/"47a7cbaefdec0639404a5946676f6e95"'
// }
// }
// }
There are some type guards (type predicats) that can be used to inspect the kind of JSON:API document.
import { JsonApi } from 'jsonapi-metal-client';
const {
isFetchResponse
isFetchResourceResponse
isFetchResourceIndividualResponse
isErrorDocument
} = JsonApi.Specification.TypeGuards
const result = await client.fetch('http://examples.com/articles/1');
if (result.isSuccess) {
isFetchResponse(result.document)
isFetchResourceResponse(result.document)
isFetchResourceIndividualResponse(result.document)
// true
} else {
if (result.document) {
isErrorDocument(result.document)
// true
}
}
Requirements:
- Yarn
Generate type guards (type predicats).
yarn type-guards
Generate documentation using TypeDoc:
yarn documentation
Executing lint check using ESLint:
yarn lint
Executing lint fix using ESLint:
yarn format
Executing Jest test suite:
yarn test