Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gatsby-source-contentful): provide gql type definitions using content model introspection and schema-customization #12816

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
cec21d1
fix(schema): fix `types` for buildUnionType config object
pieh Mar 24, 2019
a90d932
feat(gatsby-source-contentful): provide gql type definitions using co…
pieh Mar 24, 2019
c8659b6
actually let's use empty space
pieh Mar 24, 2019
ab73df4
Merge remote-tracking branch 'origin/master' into contentful-schema
pieh May 20, 2019
ddac58b
use hot new extensions to define resolvers instead of importing inter…
pieh May 20, 2019
691469e
remove old RichTextNode type extension
pieh May 20, 2019
628aa6c
revert backreferece handling removal in nodes, adjust type def genera…
pieh May 20, 2019
c3e5483
bump peerDep - we rely on extensions added in 2.5.0
pieh May 21, 2019
738a726
remove unused import
pieh May 21, 2019
d59c28a
update snapshot - json fields no longer creates child nodes - it's em…
pieh May 21, 2019
0971d54
get rid of useless comment
pieh May 21, 2019
64fbe33
name union same way Gatsby does it
pieh May 21, 2019
2e2cbb3
remove stray commented out console.log
pieh May 21, 2019
01f1938
remove more stray comments that no longer apply after using extensions
pieh May 22, 2019
7e14ce6
create unions always for reference fields
pieh May 26, 2019
7f64fbd
skip checking if createTypes is available - this is hard requirment n…
pieh May 26, 2019
bc193f7
Merge remote-tracking branch 'origin/master' into contentful-schema
pieh May 26, 2019
f768ec3
skip back references fields if fieldname is already used
pieh May 26, 2019
81996b9
Merge remote-tracking branch 'origin/master' into contentful-schema
pieh Jun 24, 2019
2113bdc
using-contentful: union on refererences
pieh Jun 24, 2019
cb47eb0
gatsby-source-contentful: use `fieldName type` as base for backrefere…
pieh Jun 24, 2019
e3a3b02
using-contentful: update to make it work with changed back reference …
pieh Jun 24, 2019
d4d101b
chore: update yarn.lock
pieh Jun 24, 2019
0350f71
handling of childMarkdownRemark
pieh Jun 24, 2019
737d3d0
docs updates
pieh Jun 24, 2019
248ba72
add migration step on json fields
pieh Jun 24, 2019
5b155a5
remove note about api limitation
pieh Jun 24, 2019
c5052c2
revert unnecesary change
pieh Jun 24, 2019
aa1dfb9
update snapshots
pieh Jun 24, 2019
9717a34
revert changes to example's config file
pieh Jun 24, 2019
abc0e15
Apply suggestions from code review
pieh Jun 26, 2019
db68354
chore: format
Jul 1, 2019
ae7a0e8
Apply suggestions from code review
pieh Jul 4, 2019
7aa2bac
Merge remote-tracking branch 'origin/master' into contentful-schema
pieh Jul 4, 2019
1c0ec2f
Merge remote-tracking branch 'origin/master' into contentful-schema
pieh Jul 15, 2019
c9c2bf2
don't create reverse links for untyped references, show warning
pieh Jul 17, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 39 additions & 2 deletions examples/using-contentful/gatsby-node.js
Expand Up @@ -2,6 +2,43 @@ const _ = require(`lodash`)
const path = require(`path`)
const slash = require(`slash`)

exports.sourceNodes = ({ actions, schema }) => {
actions.createTypes(`
# This is needed if there aren't any MarkdownRemark nodes.
type MarkdownRemark implements Node @infer {
html: String
}
`)

actions.createTypes(
[`contentfulProductProductDescriptionTextNode`].map(typeName =>
schema.buildObjectType({
name: typeName,
fields: {
childMarkdownRemark: {
type: `MarkdownRemark`,
resolve: async (source, args, context) => {
const { path } = context
const result = await context.nodeModel.getNodesByIds(
{ ids: source.children, type: `MarkdownRemark` },
{ path }
)
if (result && result.length > 0) {
return result[0]
} else {
return null
}
},
},
},
extensions: {
infer: false,
},
})
)
)
}

// Implement the Gatsby API “createPages”. This is
// called after the Gatsby bootstrap is finished so you have
// access to any information necessary to programmatically
Expand Down Expand Up @@ -51,7 +88,7 @@ exports.createPages = ({ graphql, actions }) => {
})
})
})
.then(() => {
.then(() =>
graphql(
`
{
Expand Down Expand Up @@ -90,5 +127,5 @@ exports.createPages = ({ graphql, actions }) => {
})
})
})
})
)
}
5 changes: 1 addition & 4 deletions examples/using-contentful/package.json
Expand Up @@ -25,12 +25,9 @@
],
"license": "MIT",
"main": "n/a",
"resolutions": {
"contentful": "6.1.0"
},
"scripts": {
"develop": "gatsby develop",
"build": "gatsby build",
"start": "gatsby serve"
}
}
}
2 changes: 1 addition & 1 deletion examples/using-contentful/src/templates/category.js
Expand Up @@ -76,7 +76,7 @@ export const pageQuery = graphql`
width
}
}
product {
categoriesProduct {
id
productName {
productName
Expand Down
14 changes: 9 additions & 5 deletions examples/using-contentful/src/templates/product.js
Expand Up @@ -83,14 +83,18 @@ export const pageQuery = graphql`
}
}
brand {
companyName {
companyName
... on ContentfulBrand {
companyName {
companyName
}
}
}
categories {
id
title {
title
... on ContentfulCategory {
id
title {
title
}
}
}
}
Expand Down
151 changes: 143 additions & 8 deletions packages/gatsby-source-contentful/README.md
Expand Up @@ -156,14 +156,6 @@ List of locales and their codes can be found in Contentful app -> Settings -> Lo

Prevents the use of sync tokens when accessing the Contentful API.

## Notes on Contentful Content Models

There are currently some things to keep in mind when building your content models at Contentful.

1. At the moment, fields that do not have at least one populated instance will not be created in the GraphQL schema.

2. When using reference fields, be aware that this source plugin will automatically create the reverse reference. You do not need to create references on both content types.

## How to query for nodes

Two standard node types are available from Contentful: `Asset` and `ContentType`.
Expand Down Expand Up @@ -307,6 +299,103 @@ To get **all** the `CaseStudy` nodes with ShortText fields `id`, `slug`, `title`

When querying images you can use the `fixed`, `fluid` or `resize` nodes to get different sizes for the image (for example for using [gatsby-image](https://www.gatsbyjs.org/packages/gatsby-image/)). Their usage is documented at the [gatsby-plugin-sharp](https://www.gatsbyjs.org/packages/gatsby-plugin-sharp/) package. The only difference is that gatsby-source-contentful also allows setting only the `width` parameter for these node types, the height will then automatically be calculated according to the aspect ratio.

## Notes on Contentful Content Models

### References

Contentful reference fields will create [Union type](https://graphql.org/learn/schema/#union-types) fields. [Inline fragments](https://graphql.org/learn/queries/#inline-fragments) should be used to access the data on these fields.

See below for a references example where you query for categories on a product:

```graphql
{
contentfulProduct {
name
price
categories {
# We are using inline fragment on Category type
# to access category fields
... on ContentfulCategory {
title
}
}
}
}
```

pieh marked this conversation as resolved.
Show resolved Hide resolved
The above example assumes that you have `Product` and `Category` Content Models in your Contentful space, and that `Product` has a `categories` field that references `Category` entries.

### Reverse references

When using reference fields, be aware that this source plugin will automatically create the reverse reference. You do not need to create references on both content types. The name of the reverse reference will contain field and type names.

See below for a reverse references example where you query for all products in a given category:

```graphql
{
contentfulCategory {
title
categoriesProduct {
name
price
}
}
}
```

pieh marked this conversation as resolved.
Show resolved Hide resolved
The above example assumes that you have `Product` and `Category` Content Models in your Contentful space, and `Product` has a `categories` field that references `Category` entries.

### Markdown transformers on Long Text fields

Version 3 of `gatsby-source-contentful` creates GraphQL schema directly from the Contentful Content Model and no longer infers fields from data.

This means that queries will keep working even if your Contentful space doesn't have any fields in it.

There is however, an edge case for transformed data - particularly for Long Text fields that can be transformed with `gatsby-transformer-remark` or `gatsby-mdx`. The Contentful plugin is not aware of transformers so you might need to provide hints for Gatsby to create `childMarkdownRemark`/`childMdx` fields.

Here's an example of attaching `childMarkdownRemark`:

```js
// in your gatsby-node.js
exports.sourceNodes = ({ actions, schema }) => {
actions.createTypes(`
# This is needed if there aren't any MarkdownRemark nodes.
type MarkdownRemark implements Node {
html: String
}
`)

actions.createTypes(
// list all types that need to have `childMarkdownRemark` attached
[`contentfulProductProductDescriptionTextNode`].map(typeName =>
schema.buildObjectType({
name: typeName,
fields: {
childMarkdownRemark: {
type: `MarkdownRemark`,
resolve: async (source, args, context) => {
const { path } = context
const result = await context.nodeModel.getNodesByIds(
{ ids: source.children, type: `MarkdownRemark` },
{ path }
)
if (result && result.length > 0) {
return result[0]
} else {
return null
}
},
},
},
extensions: {
infer: false,
},
})
)
)
}
```

## More on Queries with Contentful and Gatsby

It is strongly recommended that you take a look at how data flows in a real Contentful and Gatsby application to fully understand how the queries, Node.js functions and React components all come together. Check out the example site at
Expand Down Expand Up @@ -353,5 +442,51 @@ documentToReactComponents(node.bodyRichText.json, options)

Check out the examples at [@contentful/rich-text-react-renderer](https://github.com/contentful/rich-text/tree/master/packages/rich-text-react-renderer).

## Migration to `gatsby-source-contentful` version 3:

- Reference fields are always unions:
```diff
{
contentfulProduct {
name
price
categories {
- title
+ # We are using inline fragment on Category type
+ # to access category fields
+ ... on ContentfulCategory {
+ title
+ }
}
}
}
```
- Reverse reference fields now include referencing field name:
```diff
{
contentfulCategory {
title
- product {
+ categoriesProduct {
name
price
}
}
}
```
- Rich text fields now don't infer fields. Only available field is `json`. See [Contentful Rich Text](#contentful-rich-text) section on how to use it.
- JSON object fields now don't infer fields:
```diff
{
contentfulSomeType {
title
- jsonField {
- someFieldInsideJsonObject
- }
+ jsonField
}
}
```

[dotenv]: https://github.com/motdotla/dotenv
[envvars]: https://gatsby.dev/env-vars
4 changes: 2 additions & 2 deletions packages/gatsby-source-contentful/package.json
Expand Up @@ -13,7 +13,7 @@
"base64-img": "^1.0.3",
"bluebird": "^3.5.0",
"chalk": "^2.3.2",
"contentful": "^6.1.0",
"contentful": "^7.6.0",
"deep-map": "^1.5.0",
"fs-extra": "^4.0.2",
"gatsby-plugin-sharp": "^2.2.7",
Expand All @@ -37,7 +37,7 @@
],
"license": "MIT",
"peerDependencies": {
"gatsby": "^2.0.33"
"gatsby": "^2.5.0"
},
"repository": {
"type": "git",
Expand Down