REST
- 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)
});
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 };
},
});