👉 [Visit the DatoCMS homepage](https://www.datocms.com) or see [What is DatoCMS?](#what-is-datocms)
---
# @datocms/cda-client
A lightweight, TypeScript-ready package that offers various helpers around the native Fetch API to perform GraphQL requests towards DatoCMS [Content Delivery API](https://www.datocms.com/docs/content-delivery-api).
## TypeScript Support
This package is built with TypeScript and provides type definitions out of the box. It supports `TypedDocumentNode` for improved type inference when using [gql.tada](https://gql-tada.0no.co/), [GraphQL Code Generator](https://the-guild.dev/graphql/codegen) or similar tools.
## Examples
### Basic Query Execution
```typescript
import { executeQuery } from "@datocms/cda-client";
const query = `
query {
allArticles {
id
title
}
}
`;
const result = await executeQuery(query, {
token: "your-api-token-here",
});
console.log(result);
```
### Using with TypeScript and GraphQL Code Generator
```typescript
import { executeQuery } from "@datocms/cda-client";
import { AllArticlesQuery } from "./generated/graphql";
const result = await executeQuery(AllArticlesQuery, {
token: "your-api-token-here",
variables: {
limit: 10,
},
});
console.log(result.allArticles);
```
## Installation
```bash
npm install @datocms/cda-client
```
## Usage
This package provides several utility functions to help you interact with the DatoCMS Content Delivery API using GraphQL.
### `executeQuery`
The main function to execute a GraphQL query against the DatoCMS Content Delivery API.
```typescript
import { executeQuery } from "@datocms/cda-client";
const result = await executeQuery(query, options);
```
#### Parameters
- `query`: A GraphQL query string, `DocumentNode`, or `TypedDocumentNode`.
- `options`: An object containing execution options.
#### Options
| Option | Type | Description |
| -------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `token` | `string` | DatoCMS API token (required) [Read more](https://www.datocms.com/docs/content-delivery-api/authentication) |
| `includeDrafts` | `boolean` | If true, return draft versions of records [Read more](https://www.datocms.com/docs/content-delivery-api/api-endpoints#preview-mode-to-retrieve-draft-content) |
| `excludeInvalid` | `boolean` | If true, filter out invalid records [Read more](https://www.datocms.com/docs/content-delivery-api/api-endpoints#strict-mode-for-non-nullable-graphql-types) |
| `environment` | `string` | Name of the DatoCMS environment for the query [Read more](https://www.datocms.com/docs/content-delivery-api/api-endpoints#specifying-an-environment) |
| `contentLink` | `'vercel-v1'` | If true, embed metadata for Content Link [Read more](https://www.datocms.com/docs/content-delivery-api/api-endpoints#content-link) |
| `baseEditingUrl` | `string` | Base URL of your DatoCMS project [Read more](https://www.datocms.com/docs/content-delivery-api/api-endpoints#content-link) |
| `returnCacheTags` | `boolean` | If true, receive Cache Tags associated with the query [Read more](https://www.datocms.com/docs/content-delivery-api/api-endpoints#cache-tags) |
| `variables` | `object` | Variables to be sent with the query |
| `fetchFn` | `function` | Custom fetch function (optional) |
| `requestInitOptions` | `Partial` | Additional request initialization options (optional) |
| `autoRetry` | `boolean` | Automatically retry on rate limit (default: true) |
### `rawExecuteQuery`
Similar to `executeQuery`, but returns both the query result and the full response object. This can be handy when used together with returnCacheTags to actually retrieve the cache tags.
```typescript
import { rawExecuteQuery } from "@datocms/cda-client";
const [result, response] = await rawExecuteQuery(query, {
token: "your-api-token-here",
returnCacheTags: true,
});
const cacheTags = response.headers.get("x-cache-tags");
```
### `executeQueryWithAutoPagination`
This function comes handy when the query contains a paginated collection: behind the scene,
`executeQueryWithAutoPagination` reworks the passed query and collects the results, so that
it's possible to get a collection of records that is longer than Content Delivery API's result limit.
That is done with a single API call, in a transparent way.
```typescript
import { executeQueryWithAutoPagination } from "@datocms/cda-client";
const result = await executeQueryWithAutoPagination(query, options);
```
#### Parameters
Parameters are the same available for `executeQuery`:
- `query`: A GraphQL query string, `DocumentNode`, or `TypedDocumentNode`.
- `options`: An object containing execution options with the same shape of options for `executeQuery`.
### How does it work?
Suppose you want to execute the following query on an model with `2500` records:
```graphql
query BuildSitemapUrls {
allBlogPosts {
slug
}
entries: allSuccessStories(first: 2500) {
...SuccessStoryUrlFragment
}
}
fragment SuccessStoryUrlFragment on SuccessStoryRecord {
slug
}
```
Well, that's a roadblock: The CDA is limited to returning a maximum of `500` items at a time. If you try to fetch more than that, you'll get an error. Instead, if you wanted to fetch all `2500` records, you would normally have to manually paginate it by executing the query multiple times, each time incrementing the `skip` parameter by an additional 500. That's a lot of work!
Fortunately, the helper function `executeQueryWithAutoPagination` does that on your behalf: the above query is analyzed and rewritten on the fly like this:
```graphql
query BuildSitemapUrls {
allBlogPosts {
slug
}
splitted_0_entries: allSuccessStories(first: 500, skip: 0) {
...SuccessStoryUrlFragment
}
splitted_500_entries: allSuccessStories(first: 500, skip: 500) {
...SuccessStoryUrlFragment
}
splitted_1000_entries: allSuccessStories(first: 500, skip: 1000) {
...SuccessStoryUrlFragment
}
splitted_1500_entries: allSuccessStories(first: 500, skip: 1500) {
...SuccessStoryUrlFragment
}
splitted_2000_entries: allSuccessStories(first: 500, skip: 2000) {
...SuccessStoryUrlFragment
}
}
fragment SuccessStoryUrlFragment on SuccessStoryRecord {
slug
}
```
Once executed, the results get collected and recomposed as if nothing happened.
#### Limitations
`executeQueryWithAutoPagination` works only when the query contains only one selection that has
an oversized `first:` argument (i.e. the `first:` argument surpasses the Content Delivery API's result limit of `500`).
If two or more requested models have oversized pagination, the function will return an error.
The rewritten query must still respect the [GraphQL complexity cost](https://www.datocms.com/docs/content-delivery-api/complexity).
### `rawExecuteQueryWithAutoPagination`
As for `executeQuery`, also `executeQueryWithAutoPagination` has a pair raw version that returns both the query result and the full response object.
This can be handy when used together with returnCacheTags to actually retrieve the cache tags.
```typescript
import { rawExecuteQueryWithAutoPagination } from "@datocms/cda-client";
const [result, response] = await rawExecuteQueryWithAutoPagination(query, {
token: "your-api-token-here",
returnCacheTags: true,
});
const cacheTags = response.headers.get("x-cache-tags");
```
### `buildRequestHeaders`
Builds request headers for a GraphQL query towards the DatoCMS Content Delivery API.
```typescript
import { buildRequestHeaders } from "@datocms/cda-client";
const headers = buildRequestHeaders(options);
```
#### Options
The `buildRequestHeaders` function accepts the same options as `executeQuery`, except for `variables`, `fetchFn`, and `autoRetry`.
### `buildRequestInit`
Builds the request initialization object for a GraphQL query towards the DatoCMS Content Delivery API.
```typescript
import { buildRequestInit } from "@datocms/cda-client";
const requestInit = buildRequestInit(query, options);
```
#### Parameters
- `query`: A GraphQL query string or `DocumentNode`.
- `options`: An object containing execution options (same as `executeQuery`).
## Error Handling
In case a query fails (either with an HTTP status code outside of the 2xx range, or for an error in the query), an `ApiError` exception will be thrown by the client. This error contains all the details of the request and response, allowing you to debug and handle errors effectively.
### Example
```typescript
import { executeQuery, ApiError } from "@datocms/cda-client";
const query = `
query {
allArticles {
id
title
}
}
`;
try {
const result = await executeQuery(query, {
token: "your-api-token-here",
});
console.log(result);
} catch (e) {
if (e instanceof ApiError) {
// Information about the failed request
console.log(e.query);
console.log(e.options);
// Information about the response
console.log(e.response.status);
console.log(e.response.statusText);
console.log(e.response.headers);
console.log(e.response.body);
} else {
// Handle other types of errors
throw e;
}
}
```
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
This project is licensed under the MIT License.
---
# What is DatoCMS?
[DatoCMS](https://www.datocms.com/) is the REST & GraphQL Headless CMS for the modern web.
Trusted by over 25,000 enterprise businesses, agencies, and individuals across the world, DatoCMS users create online content at scale from a central hub and distribute it via API. We ❤️ our [developers](https://www.datocms.com/team/best-cms-for-developers), [content editors](https://www.datocms.com/team/content-creators) and [marketers](https://www.datocms.com/team/cms-digital-marketing)!
**Why DatoCMS?**
- **API-First Architecture**: Built for both REST and GraphQL, enabling flexible content delivery
- **Just Enough Features**: We believe in keeping things simple, and giving you [the right feature-set tools](https://www.datocms.com/features) to get the job done
- **Developer Experience**: First-class TypeScript support with powerful developer tools
**Getting Started:**
- ⚡️ [Create Free Account](https://dashboard.datocms.com/signup) - Get started with DatoCMS in minutes
- 🔖 [Documentation](https://www.datocms.com/docs) - Comprehensive guides and API references
- ⚙️ [Community Support](https://community.datocms.com/) - Get help from our team and community
- 🆕 [Changelog](https://www.datocms.com/product-updates) - Latest features and improvements
**Official Libraries:**
- [**Content Delivery Client**](https://github.com/datocms/cda-client) - TypeScript GraphQL client for content fetching
- [**REST API Clients**](https://github.com/datocms/js-rest-api-clients) - Node.js/Browser clients for content management
- [**CLI Tools**](https://github.com/datocms/cli) - Command-line utilities for schema migrations (includes [Contentful](https://github.com/datocms/cli/tree/main/packages/cli-plugin-contentful) and [WordPress](https://github.com/datocms/cli/tree/main/packages/cli-plugin-wordpress) importers)
**Official Framework Integrations**
Helpers to manage SEO, images, video and Structured Text coming from your DatoCMS projects:
- [**React Components**](https://github.com/datocms/react-datocms)
- [**Vue Components**](https://github.com/datocms/vue-datocms)
- [**Svelte Components**](https://github.com/datocms/datocms-svelte)
- [**Astro Components**](https://github.com/datocms/astro-datocms)
**Additional Resources:**
- [**Plugin Examples**](https://github.com/datocms/plugins) - Example plugins we've made that extend the editor/admin dashboard
- [**Starter Projects**](https://www.datocms.com/marketplace/starters) - Example website implementations for popular frameworks
- [**All Public Repositories**](https://github.com/orgs/datocms/repositories?q=&type=public&language=&sort=stargazers)