Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/contentful/cf-graphql
Generate a GraphQL schema out of your Contentful space
https://github.com/contentful/cf-graphql
contentful graphql
Last synced: 3 months ago
JSON representation
Generate a GraphQL schema out of your Contentful space
- Host: GitHub
- URL: https://github.com/contentful/cf-graphql
- Owner: contentful
- Archived: true
- Created: 2017-03-08T23:32:14.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2018-10-16T07:14:52.000Z (about 6 years ago)
- Last Synced: 2024-05-02T18:36:11.403Z (8 months ago)
- Topics: contentful, graphql
- Language: JavaScript
- Homepage:
- Size: 987 KB
- Stars: 185
- Watchers: 61
- Forks: 37
- Open Issues: 17
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# cf-graphql
[![travis build status](https://img.shields.io/travis/contentful-labs/cf-graphql.svg)](https://travis-ci.org/contentful-labs/cf-graphql)
[![npm version](https://img.shields.io/npm/v/cf-graphql.svg)](https://www.npmjs.com/package/cf-graphql)
[![npm downloads](https://img.shields.io/npm/dt/cf-graphql.svg)](https://www.npmjs.com/package/cf-graphql)
[![deps status](https://img.shields.io/david/contentful-labs/cf-graphql.svg)](https://david-dm.org/contentful-labs/cf-graphql)
[![dev deps status](https://img.shields.io/david/dev/contentful-labs/cf-graphql.svg)](https://david-dm.org/contentful-labs/cf-graphql?type=dev)
[![codecov coverage](https://img.shields.io/codecov/c/github/contentful-labs/cf-graphql.svg)](https://codecov.io/gh/contentful-labs/cf-graphql)`cf-graphql` is a library that allows you to query your data stored in [Contentful](https://www.contentful.com/) with [GraphQL](http://graphql.org/). A schema and value resolvers are automatically generated out of an existing space.
Generated artifacts can be used with any node-based GraphQL server. The outcome of the project's main function call is an instance of the [`GraphQLSchema`](http://graphql.org/graphql-js/type/#graphqlschema) class.
## Table of contents
- [Disclaimers](#disclaimers)
- [First steps](#first-steps)
- [Demo](#demo)
- [Run it locally](#run-it-locally)
- [Deploy to Zeit's now](#deploy-to-zeits-now)
- [Programmatic usage](#programmatic-usage)
- [Querying](#querying)
- [Helpers](#helpers)
- [Contributing](#contributing)## Disclaimers
Please note that `cf-graphql` library is released as an experiment:
- we might introduce breaking changes into programmatic interfaces and space querying approach before v1.0 is released
- there’s no magic bullet: complex GraphQL queries can result in a large number of CDA calls, which will be counted against your quota
- we might discontinue development of the library and stop maintaining it## First steps
If you just want to see how it works, please follow the [Demo](#demo) section. You can deploy the demo with your own credentials so it queries your own data.
In general `cf-graphql` is a library and it can be used as a part of your project. If you want to get your hands dirty coding, follow the [Programmatic usage](#programmatic-usage) section.
## Demo
We host an [online demo](https://cf-graphql-demo.now.sh/) for you. You can query Contentful's "Blog" space template there. This how its graph looks like:
![Demo space graph](./demo/demo-space-graph.png)
### Run it locally
This repository contains a demo project. The demo comes with a web server (with [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) enabled) providing the GraphQL, [an in-browser IDE (GraphiQL)](https://github.com/graphql/graphiql) and a React Frontend application using this endpoint.
To run it, clone the repository, install dependencies and start a server:
```
git clone [email protected]:contentful-labs/cf-graphql.git
cd cf-graphql/demo
# optionally change your node version with nvm, anything 6+ should work just fine
# we prefer node v6 matching the current AWS Lambda environment
nvm use
npm install
npm start
```Use to query the data from within your application and navigate to to use the IDE (GraphiQL) for test-querying. Please refer to the [Querying](#querying) section for more details.
If you also want to see how to integrate GraphQL in a React technology stack the demo project also contains an application based on the [Apollo framework](https://www.apollodata.com/). To check it out use .
To use your own Contentful space with the demo, you have to provide:
- space ID
- CDA token
- CMA tokenPlease refer the ["Authentication" section](https://www.contentful.com/developers/docs/references/authentication/) of Contentful's documentation.
You can provide listed values with env variables:
```
SPACE_ID=some-space-id CDA_TOKEN=its-cda-token CMA_TOKEN=your-cma-token npm start
```### Deploy to [Zeit's `now`](https://zeit.co/now)
To be able to deploy to [Zeit's `now`](https://zeit.co/now) you need to have an activated account. There is a free open source option available.
You can also deploy the demo with `now`. In your terminal, navigate to the `demo/` directory and run:
```
npm run deploy-demo-now
```As soon as the deployment is done you'll have a URL of your GraphQL server copied.
You can also create a deployment for your own space:
```
SPACE_ID=some-space-id CDA_TOKEN=its-cda-token CMA_TOKEN=your-cma-token npm run deploy-now
```Please note:
- when deploying a server to consume Contentful's "Blog" space template, the command to use is `npm run deploy-demo-now`; when the demo should be configured to use your own space, the command is `npm run deploy-now`
- if you've never used `now` before, you'll be asked to provide your e-mail; just follow on-screen instructions
- if you use `now`'s OSS plan (the default one), the source code will be public; it's completely fine: all credentials are passed as env variables and are not available publicly## Programmatic usage
The library can be installed with `npm`:
```
npm install --save cf-graphql
```Let's assume we've required this module with `const cfGraphql = require('cf-graphql')`. To create a schema out of your space you need to call `cfGraphgl.createSchema(spaceGraph)`.
What is `spaceGraph`? It is a graph-like data structure containing descriptions of content types of your space which additionally provide some extra pieces of information allowing the library to create a GraphQL schema.
To prepare this data structure you need to fetch raw content types data from the [CMA](https://www.contentful.com/developers/docs/references/content-management-api/). Let's create a Contentful client first:
```js
const client = cfGraphql.createClient({
spaceId: 'some-space-id',
cdaToken: 'its-cda-token',
cmaToken: 'your-cma-token'
});
````spaceId`, `cdaToken` and `cmaToken` options are required. You can also pass the following options:
- `locale` - a locale code to use when fetching content. If not provided, the default locale of a space is used
- `preview` - if `true`, CPA will be used instead of CDA for fetching content
- `cpaToken` - if `preview` is `true` then this option has to hold a CPA tokenFetch content types with your `client` and then pass them to `cfGraphql.prepareSpaceGraph(rawCts)`:
```js
client.getContentTypes()
.then(cfGraphql.prepareSpaceGraph)
.then(spaceGraph => {
// `spaceGraph` can be passed to `cfGraphql.createSchema`!
});
```The last step is to use the schema with a server. A popular choice is [express-graphql](https://github.com/graphql/express-graphql). The only caveat is how the context is constructed. The library expects the `entryLoader` key of the context to be set to an instance created with `client.createEntryLoader()`:
```js
// Skipped in snippet: `require` calls, Express app setup, `client` creation.
// `spaceGraph` was fetched and prepared in the previous snippet. In most cases
// you shouldn't be doing it per request, once is fine.
const schema = cfGraphql.createSchema(spaceGraph);// IMPORTANT: we're passing a function to `graphqlHTTP`: this function will be
// called every time a GraphQL query arrives to create a fresh entry loader.
// You can also use `expressGraphqlExtension` described below.
app.use('/graphql', graphqlHTTP(function () {
return {
schema,
context: {entryLoader: client.createEntryLoader()}
};
}));
```[You can see a fully-fledged example in the `demo/` directory](./demo/server.js).
## Querying
For each Contentful content type three root-level fields are created:
- a singular field accepts a required `id` argument and resolves to a single entity
- a collection field accepts an optional `q`, `skip` and `limit` arguments and resolves to a list of entities
- a collection metadata field accepts an optional `q` argument and resolves to a metadata object (currently comprising only `count`)Please note that:
- the `q` argument is a query string you could use with the [CDA](https://www.contentful.com/developers/docs/references/content-delivery-api/)
- both `skip` and `limit` arguments can be used to fetch desired page of results
* `skip` defaults to `0`
* `limit` defaults to `50` and cannot be greater than `1000`
* some query string parameters cannot be used:
* `skip`, `limit` - use collection field arguments instead
* `include`, `content_type` - no need for them, the library will determine and use appropriate values internally
* `locale` - all the content is fetched for a single locale. By default the default locale is used; alternate locale can be selected with the `locale` configuration option of `cfGraphql.createClient`Assuming you've got two content types named `post` and `author` with listed fields, this query is valid:
```graphql
{
authors {
name
}authors(skip: 10, limit: 10) {
title
rating
}_authorsMeta {
count
}posts(q: "fields.rating[gt]=5") {
title
rating
}_postsMeta(q: "fields.rating[gt]=5") {
count
}post(id: "some-post-id") {
title
author
comments
}
}
```Reference fields will be resolved to:
- a specific type, if there is a validation that allows only entries of some specific content type to be linked
- the `EntryType`, if there is no such constraint. The `EntryType` is an interface implemented by all the specific typesExample where the `author` field links only entries of one content type and the `related` field links entries of multiple content types:
```graphql
{
posts {
author {
name
website
}related {
... on Tag {
tagName
}
... on Place {
location
name
}
}
}
}
```Backreferences (_backrefs_) are automatically created for links. Assume our `post` content type links to the `author` content type via a field named `author`. Getting an author of a post is easy, getting a list of posts by an author is not. `_backrefs` mitigate this problem:
```graphql
{
authors {
_backrefs {
posts__via__author {
title
}
}
}
}
```When using backreferences, there is a couple of things to keep in mind:
- backrefs may be slow; always test with a dataset which is comparable with what you've got in production
- backrefs are generated only when a reference field specifies a single allowed link content type
- `_backrefs` is prefixed with a single underscore
- `__via__` is surrounded with two underscores; you can read this query out loud like this: _"get posts that link to author via the author field"_## Helpers
`cf-graphql` comes with helpers that help you with the `cf-graphql` integration. These are used inside of [the demo application](https://github.com/contentful-labs/cf-graphql/tree/master/demo).
### `expressGraphqlExtension`
`expressGraphqlExtension` is a simple utility producing a function that can be passed directly to the [`express-graphql` middleware](https://github.com/graphql/express-graphql).
```javascript
// Skipped in this snippet: client and space graph creation
const schema = cfGraphql.createSchema(spaceGraph);const opts = {
// display the current cf-graphql version in responses
version: true,
// include list of the underlying Contentful CDA calls with their timing
timeline: true,
// display detailed error information
detailedErrors: true
};const ext = cfGraphql.helpers.expressGraphqlExtension(client, schema, opts);
app.use('/graphql', graphqlHTTP(ext));
```**Important**: Most likely don't want to enable `timeline` and `detailedErrors` in your production environment.
### `graphiql`
If you want to run your own GraphiQL and don't want to rely on the one shipping with e.g. [express-graphql](https://github.com/graphql/express-graphql) then you could use the `graphiql` helper.
```javascript
const ui = cfGraphql.helpers.graphiql({title: 'cf-graphql demo'});
app.get('/', (_, res) => res.set(ui.headers).status(ui.statusCode).end(ui.body));
```## Contributing
Issue reports and PRs are more than welcomed.
## License
MIT