Skip to main content

REST

What you'll learn
  • Using Foscia to interact with a REST API
  • Common configuration recipes

Setup

Please follow the getting started guide to set up your REST action factory.

Usage

Currently, REST implementations does not support additional features compared to generic Foscia features, because REST is not that much standardized about filtering, sorting, etc.

If your REST API supports eager loading relations, you should configure your REST adapter to serialize relationships inclusion in every request.

If you need something specific, you can open a new issue on the repository.

Configuration recipes

Here are common configuration for @foscia/rest implementation. You can read the implementation and configuration guide for more details.

You can also take a look at HTTP usage and common configuration recipes, as the REST adapter is based on HTTP adapter.

Customizing include query

If your REST API supports eager loading relations, you can use include enhancer to request relations loading. This will define a query parameter such as include=author,comments.

To define a custom query parameter, use the includeParamKey option.

import { makeJsonRestAdapter } from '@foscia/http';

const { adapter } = makeJsonRestAdapter({
includeParamKey: 'with',
});

Changing content format

If your REST API interacts with another data type than JSON, such as XML, you can configure this behavior as a default on your adapter:

import { makeRestAdapterWith } from '@foscia/rest';
import { objectToXML, objectFromXML } from 'some-xml-library';

makeRestAdapterWith({
defaultBodyAs: (body) => objectToXML(body),
defaultResponseReader: (response) => objectFromXML(body),
defaultHeaders: {
Accept: 'application/xml',
'Content-Type': 'application/xml',
},
});

Deserializing nested data

If your REST API document nest records inside the document (not at root, such as inside a data property), you can add extractData option which will extract records data using the given transformation function.

import { makeJsonRestDeserializer } from '@foscia/rest';

makeJsonRestSerializer({
extractData: (data: { data: any }) => ({ records: data.data }),
});

Nesting serialized data

If your REST API document expect record data to be nested (not at root, such as inside a data property), you can add createData option which will wrap records data using the given transformation function.

import { makeJsonRestSerializer } from '@foscia/rest';

makeJsonRestSerializer({
createData: (records) => ({ data: records }),
});

Changing endpoint case

By default, JSON:API use kebab case for models and relations endpoints (e.g. favorite-posts for a favoritePosts relation). If you want to use another case for endpoints, you can use modelPathTransformer and relationPathTransformer options.

import { camelCase } from 'lodash-es';
import { makeJsonRestAdapter } from '@foscia/rest';

makeJsonRestAdapter({
modelPathTransformer: (path) => camelCase(path),
relationPathTransformer: (path) => camelCase(path),
});

Changing serialization keys case

By default, serialized and deserialized attributes and relations keep keys specified in the model. If you are using camel cased keys (e.g. firstName) but want to exchange kebab cased keys (e.g. first-name) with your API, you can use serializeKey and deserializeKey options.

import { kebabCase } from 'lodash-es';
import { makeJsonRestSerializer, makeJsonRestDeserializer } from '@foscia/rest';

makeJsonRestSerializer({
serializeKey: ({ key }) => kebabCase(key),
});

makeJsonRestDeserializer({
deserializeKey: ({ key }) => kebabCase(key),
});

Customizing relation serialized data

By default, REST implementation will only serialize the related IDs as the serialized relation's data. You can customize this behavior using serializeRelation option.

Here is an example which will serialize ID and type to support polymorphic relations:

import { makeJsonRestSerializer } from '@foscia/rest';

makeJsonRestSerializer({
serializeRelation: (_, related) => ({ type: related.$model.$type, id: related.id }),
});

Here is another example where we serialize the whole related record:

import { makeJsonRestSerializer } from '@foscia/rest';

makeJsonRestSerializer({
serializeRelation: ({ context, serializer }, related, parents) => serializer
.serializeInstance(related, context, parents)
});
tip

If you want to customize relations serialization behavior when writing relations (e.g. using attach, associate, etc.), you can use the serializeRelated option which have the same signature.

Parsing URL IDs

Some API implementation may serialize records IDs as URL to the record endpoint (such as https://example.com/api/posts/1 for post 1). You can customize the deserializer to support ID and type extraction from URL ID using the pullIdentifier option.

import { makeJsonRestDeserializer } from '@foscia/rest';

makeJsonRestDeserializer({
pullIdentifier: (record) => {
// This will support IDs like `https://example.com/api/posts/1`, `/api/posts/1`, etc.
const [id, type] = String(record.id).split('/').reverse();

return { id, type };
},
});

Reference