API Documentation

API Documentation

API_NETWORK_BASE_URL

This library uses the API_NETWORK_BASE_URL environment variable to set the base URL of all requests the network function does. The default value is /api/v2/ because it's tailored to Core usage.

useCollection

Read more in the React Integration documentation.

useResource

Read more in the React Integration documentation.

api

import { api } from 'coreql';

The API Client is a Proxy object that has no real properties, instead, it will receive the property name and use it as a resource name.

const users = api.users;

You will now get a new object with the following methods:

  • .hydrate
  • .read
  • .create
  • .find

The find method will return a new object with the following methods:

  • .hydrate
  • .read
  • .update
  • .update.relation
  • .destroy

This means if you want to create a new article you should do:

await api.articles.create(data, relationships);

And if you want to update an user you can do:

await api.users.find(id).update(newAttributes);

Note: The resource name should be in plural because of JSON:API usage of the plural form in the endpoints.

normalize

Receive the results of a json:api request and normalize the data to follow the structure:

Note: This is especially useful when you want to do the data fetching in one place and share it in multiple components accessing the same repeated data all over the tree in different ways, e.g. computing data based on the number of items and rendering those items in another part at the same time. If you are going to iterate the main object of your request and use the relation to access the related resource entities then take a look at denormalize below.

Example result

{
"projects": {
"ids": ["1", "2"],
"entities": {
"1": {
"id": "1",
"title": "CoreQL",
"owner": [
{ "type": "users", "id": "1" },
{ "type": "users", "id": "2" }
]
},
"2": {
"id": "2",
"title": "Core Client",
"owner": { "type": "users", "id": "1" }
}
}
},
"users": {
"ids": ["1", "2"],
"entities": {
"1": { "id": "1", "name": "Sergio" },
"2": { "id": "2", "name": "Kattya" }
}
}
}

denormalize

Receive the results of a json:api request and the resource you want to focus on, and it will return the denormalized data.

Note: This is especially useful when you need to iterate the main object of your request with all the related resources and don't want to manually search those objects in the included key.

Example result

[
{
"id": "1",
"title": "CoreQL",
"owner": [
{ "type": "users", "id": "1", "name": "Sergio" },
{ "type": "users", "id": "2", "name": "Kattya" }
]
},
{
"id": "2",
"title": "Core Client",
"owner": { "type": "users", "id": "1", "name": "Sergio" }
}
]

SSRSuspense

This component's a wrapper around React.Suspense which will check if you are running Server-Side and render the fallback always, this allows you to use suspense enabled components inside a Next.js application.

If you are not using Next.js or manually doing Server-Side Rendering then it's better to use React.Suspense directly.

<SSRSuspense fallback={<Fallback />}>
<SuspenseEnabledComponent />
</SSRSuspense>

ErrorBoundary

This component's a custom Error Boundary component which lets you pass a fallback component to render when an error is caught and pass a callback to run something when you catch an error.

<ErrorBoundary fallback={ErrorFallback} onError={handleError}>
<SSRSuspense fallback={<LoadingFallback />}>
<SuspenseEnabledThrowingComponent />
</SSRSuspense>
</ErrorBoundary>

ErrorFallback is a component that will receive an error prop and must return some valid React node.

function ErrorFallback({ error }) {
return <p>{error.message}</p>;
}

The handleError is a function that will receive the error object as the first argument and additional info as the second one.

function handleError(error, info) {
// Do something, maybe send the error to Sentry
}

buildURL

This is a low-level utility function used to get the path to a resource or collection passing the different parts of the URL and query.

import { buildURL } from 'coreql';

Resource

// Get `projects/1`
buildURL({ resource: 'projects', id: 1 });
// Get `projects/1?include=author,owner`
buildURL({ resource: 'projects', id: 1, included: ['author', 'owner'] });
// Get `projects/1/relationships/author`
buildURL({ resource: 'projects', id: 1, relationship: 'author' });

Collection

// Get `projects?include=author,owner&filter[status]=active,on-hold&filter[completed]=false&sort=author,-owner&fields[projects]=title&fields[users]=fullName`
buildURL({
resource: 'projects',
included: ['author', 'owner'],
filters: { status: ['active', 'on-hold'], completed: false },
sort: ['author', '-owner'],
fields: { projects: ['title'], users: ['fullName'] },
});

network

The network module is a wrapper over Fetch API. It receives the path to fetch, the result of buildURL, and an optional configuration.

import { network } from 'coreql';
const data = await network(buildURL({ resource: 'projects' }), {
method: 'POST',
body: JSON.stringify({ title: 'CoreQL' }),
headers: {
Authorization: `Bearer ${TOKEN}`,
},
});

It will also automatically add the Content-Type: application/vnd.api+json and Accept: application/vnd.api+json headers, both of them could be overwritten using the headers key in the configuration object.

Error Handling

Network will also detect any 4xx and 5xx HTTP error and create throw an instance of a ClientError and ServerError, you could use instanceof to detect them.

import { network, ServerError, ClientError } from 'coreql';
try {
const data = await network(buildURL({ resource: 'projects' }), {
method: 'POST',
body: JSON.stringify({ title: 'CoreQL' }),
headers: {
Authorization: `Bearer ${TOKEN}`,
},
});
} catch (error) {
if (error instanceof ServerError) {
// Do something
} else if (error instanceof ClientError) {
// Do something
} else {
// Do something with any other error
}
}