Closed freiksenet closed 4 years ago
I'm having exactly the same problem as @kennedyrose , but in my case the solution provided by @stefanprobst didn't quite help, although I'm not really sure what I'm doing, I just tried every possible way of creating this schema but it always returns an error regarding multiple types named...
.
Here's the code:
exports.sourceNodes = ({ actions }) => {
const { createTypes } = actions;
const typeDefs = `
type Wordpress__PAGEAcfIntro {
title: String
content: String
}
type Wordpress__PAGEAcfThe_problem {
title: String
content: String
}
type Wordpress__PAGEAcfThe_solution {
title: String
content: String
}
type Wordpress__PAGEAcf {
Intro: Wordpress__PAGEAcfIntro
The_problem: Wordpress__PAGEAcfThe_problem
The_solution: Wordpress__PAGEAcfThe_solution
}
type Wordpress__PAGE implements Node {
acf: Wordpress__PAGEAcf
}
`;
createTypes(typeDefs);
};
At first I tried setting only the types I needed (the first 3) with their fields, but then I got Error: Schema must contain unique named types but contains multiple types named "Wordpress__PAGEAcfIntro".
. While searching for a solution I tried @stefanprobst solution (as in my code, not sure if correct though) but didn't have any luck.
Also, this is quite a lot to just make some fields have optional string values (the query breaks if any of the fields doesn't have a title or content), and this is just the initial implementation, I'll probably have to do the same in the whole website for a lot more fields that also might be optional, so I'm very scared of this solution and really hope there's a better way of solving it.
Well, after more digging around and trying stuff without actually know what I'm doing, I came up with this snippet that solved the problem:
exports.createResolvers = ({ createResolvers }) => {
createResolvers({
Wordpress__PAGEAcfIntro: {
title: { type: `String` },
content: { type: `String` },
},
Wordpress__PAGEAcfThe_problem: {
title: { type: `String` },
content: { type: `String` },
},
Wordpress__PAGEAcfThe_solution: {
title: { type: `String` },
content: { type: `String` },
},
});
};
Although I'm still not sure why my first solution didn't work. This seems to be a lot easier to maintain though.
Final thoughts is that I'm not sure if I just lack the knowledge of Gatsby APIs or the docs are misleading for this specific issue. I think it should be easier to find a solution for the question how to have optional fields in a graphql query using gatsby
, because it's an extremely basic thing when working with a CMS like WordPress where you can have multiple custom fields and most likely a lot of them are going to be optional.
Declaring a field as an array of files doesn't work for me.
const { createTypes } = actions
const typeDefs = `
type MarkdownRemarkFrontmatter implements Node {
images: [File]
}
type MarkdownRemark implements Node {
frontmatter: MarkdownRemarkFrontmatter
}
`
createTypes(typeDefs)
}
Probably has something to do with https://github.com/gatsbyjs/gatsby/issues/12696
I'm having exactly the same problem as @kennedyrose , but in my case the solution provided by @stefanprobst didn't quite help, although I'm not really sure what I'm doing, I just tried every possible way of creating this schema but it always returns an error regarding
multiple types named...
.Here's the code:
exports.sourceNodes = ({ actions }) => { const { createTypes } = actions; const typeDefs = ` type Wordpress__PAGEAcfIntro { title: String content: String } type Wordpress__PAGEAcfThe_problem { title: String content: String } type Wordpress__PAGEAcfThe_solution { title: String content: String } type Wordpress__PAGEAcf { Intro: Wordpress__PAGEAcfIntro The_problem: Wordpress__PAGEAcfThe_problem The_solution: Wordpress__PAGEAcfThe_solution } type Wordpress__PAGE implements Node { acf: Wordpress__PAGEAcf } `; createTypes(typeDefs); };
At first I tried setting only the types I needed (the first 3) with their fields, but then I got
Error: Schema must contain unique named types but contains multiple types named "Wordpress__PAGEAcfIntro".
. While searching for a solution I tried @stefanprobst solution (as in my code, not sure if correct though) but didn't have any luck.Also, this is quite a lot to just make some fields have optional string values (the query breaks if any of the fields doesn't have a title or content), and this is just the initial implementation, I'll probably have to do the same in the whole website for a lot more fields that also might be optional, so I'm very scared of this solution and really hope there's a better way of solving it.
@eddiemf, not totally sure but I think the issue you could be having is that the types you are trying to define have already been inferred from the Wordpress data source. So in effect they are being defined twice. Using createResolvers will simply create new fields on existing types, or override existing fields(?) by the looks of things.
Lots of small fixes in 2.2.10
, including explicit Node relationships working correctly.
@Wolfsun Yeah that's exactly what I thought about it, but I feel like the docs lead you to use createTypes
as a solution for this problem, when in fact you should use createResolvers
.
As I've said, I think this is a super common problem when dealing with WordPress, so it would be good to have a well documented solution for this.
@eddiemf I am not super familiar with the wordpress plugin, but extending types in the using-wordpress
example seemed to work as expected. If you are able to provide a link to your repo I could take a look what might be the issue.
Please note that we're aware that we are still very light on documentation. My guess is that the issue has to do with which types must implement the Node
interface -- this is something which should mostly be handled by the plugins themselves (once they are ported to the new APIs).
The semantics of the Node
interface is to mark the types that are backed by actual nodes in Gatsby's internal data store, i.e. the objects that are created by the createNode
action by plugins, and have an id
field. This means that while the Frontmatter
type is just there to define the shape on the frontmatter
field on MarkdownRemark
nodes, I would guess that the wordpress plugin actually registers lots of top-level node types.
@stefanprobst I completely understand about being light on the documentation for now, I'm just trying to help :)
In short, a WordPress page in my app has a structure kinda like page -> acf -> someGroupOfFields -> actualField
. In a query I would do the following as an example:
wordpressPage(slug: { eq: "home" }) {
acf {
intro {
title
content
}
}
}
The types are automatically generated to be something like WordPress__PAGE -> WordPress__PAGEAcf -> WordPress__PAGEAcfIntro
. The problem is that these fields might very often be just optional fields (title
and content
), so if one of these fields were not provided my query would break since it's generated automatically based on the fetched data.
I see no possible way for the plugin to create these fields automatically (how would it know?), but I might be wrong. So my first solution was to just use createTypes
and create this WordPress__PAGEAcfIntro
type with the proper fields, but then I got the mentioned error.
I would say there's some conflict between my type creation and Gatsby/source plugin creating the same type after fetching the data, but I'm really not in the best position to make assumptions because I'm not at all experienced with GraphQL or Gatsby API, so I'm not sure how things should actually work.
But as I've said, for now, creating the resolvers just as in my last post worked very nicely, so I'm basically creating types for everything I need to fetch, since they can always be optional in the CMS.
You can check my gatsby-node.js
here to see how I did it.
@eddiemf This is interesting. Do you have an example with the "Schema must contain unique named types but contains multiple types named "Wordpress__PAGEAcfIntro"" error? Gatsby should be able to handle overriding types that are inferred, so I'm not sure why your code doesn't work.
@freiksenet I got this error when trying to solve it like this:
exports.sourceNodes = ({ actions }) => {
const { createTypes } = actions;
const typeDefs = `
type Wordpress__PAGEAcfIntro {
title: String
content: String
}
`;
createTypes(typeDefs);
};
The title
field was set in the CMS, but content
was empty, so I tried the snippet above and got this unique name error.
I also thought the same about overriding types being possible because that's what the docs and the article regarding this new feature also says, so I was surprised to see it didn't work as expected.
I think this is almost the same problem as the following:
I'm trying to set the schema for the frontmatter nodes generated by gatsby-transformer-remark and always run into this error:
Error: Schema must contain unique named types but contains multiple types named "MarkdownRemarkFrontmatter".
My schema looks like this:
type MarkdownRemarkFrontmatter implements Node { title: String }
With the difference that the solution that worked for him didn't actually work for me. But it also looks like the implements Node
part is wrongly used here, while in my case it should be correct.
@eddiemf you need to use the non-node types somewhere to override it. So MarkdownFrontmatter
(without implements Node) needs to be used in Markdown
node and Wordpress__PageAcfIntro
should be used in WorpressPage. We'll add a better error, but we've made this behavior this way so that one doesn't accidentally override an inline node.
@freiksenet you mean like I did here?
I'm having exactly the same problem as @kennedyrose , but in my case the solution provided by @stefanprobst didn't quite help, although I'm not really sure what I'm doing, I just tried every possible way of creating this schema but it always returns an error regarding
multiple types named...
.Here's the code:
exports.sourceNodes = ({ actions }) => { const { createTypes } = actions; const typeDefs = ` type Wordpress__PAGEAcfIntro { title: String content: String } type Wordpress__PAGEAcfThe_problem { title: String content: String } type Wordpress__PAGEAcfThe_solution { title: String content: String } type Wordpress__PAGEAcf { Intro: Wordpress__PAGEAcfIntro The_problem: Wordpress__PAGEAcfThe_problem The_solution: Wordpress__PAGEAcfThe_solution } type Wordpress__PAGE implements Node { acf: Wordpress__PAGEAcf } `; createTypes(typeDefs); };
At first I tried setting only the types I needed (the first 3) with their fields, but then I got
Error: Schema must contain unique named types but contains multiple types named "Wordpress__PAGEAcfIntro".
. While searching for a solution I tried @stefanprobst solution (as in my code, not sure if correct though) but didn't have any luck.Also, this is quite a lot to just make some fields have optional string values (the query breaks if any of the fields doesn't have a title or content), and this is just the initial implementation, I'll probably have to do the same in the whole website for a lot more fields that also might be optional, so I'm very scared of this solution and really hope there's a better way of solving it.
I tried to create, let's say, the "whole type tree" or "type model", by setting every possible field and use them as in the example, but I got the same error (sometimes a slightly different error accusing some other type of not being unique).
Although I must admit that I had no idea what I was doing when I tried this, I was just trying every possible combination of solutions, but all of them failed for me.
@eddiemf Would it be possible to get the url of the wordpress site that you are using? I want to test it myself to find out what causes the error.
@freiksenet Sure, the url is https://gatsbyislove.com
I'll leave the title
field from the intro section empty so you can check against it.
You can see at https://gatsbyislove.netlify.com/ that the intro section has no title, but it's working properly because of the resolvers that I created.
@eddiemf Thanks a lot! Got the error, will investigate.
Lol, that's the funniest error. So we accidentally uppercased the wordpress types. They should all start with wordpress
. Instead, we kept Nodes lowercased, but uppercased inner objects. So this would have worked:
type Wordpress__PAGEAcfIntro {
title: String
content: String
}
type Wordpress__PAGEAcf {
Intro: Wordpress__PAGEAcfIntro
}
type wordpress__PAGE implements Node {
acf: wordpress__PAGEAcf
}
I'm pushing a fix now, so all types would start with lowercase w
.
Awesome 😄
But now I think, at least for this specific situation, that using the resolvers can keep the code better organized since I don't need to declare these nested fields all the way up to the main one that implements Node
.
Is it really better or am I not seeing something here?
Anyway I'll play around with different solutions and see which one fits me best.
Thanks for the great support!
@eddiemf It is fine to use createResolvers
, but you won't get those fields in filter
and sort
parameters of this type's root fields. If it's okay for you, then use createResolvers
.
Here is the fix: https://github.com/gatsbyjs/gatsby/pull/12837/files
I see, that shouldn't be a problem in most cases since filter
and sort
are usually made on fields that are always populated, but I'll keep that in mind. Thanks again :)
Edit: This no longer happens, even though I didn't update anything. I have no idea what happened, or what led me to believe that it didn't work; but it works now... great work folks!
Hi folks, I played around with this code:
exports.sourceNodes = ({ actions }) => {
const { createTypes } = actions
createTypes(`
type MarkdownRemarkFrontmatter {
image: File // <---- could be a relative path, could be an empty string
}
type MarkdownRemark implements Node {
frontmatter: MarkdownRemarkFrontmatter
}
`)
}
I was expecting to get either a File
node or null
when query for a markdown remark node. Instead, I always get null
... I'd have to manually look up the file:
createResolvers({
MarkdownRemarkFrontmatter: {
image: {
type: `File`,
resolve(src, args, context) {
const filePath = src[info.fieldName]
// find & return the file node
}
}
}
})
Is there a way for me to simply tell gatsby, "this will be a File node, please find it or return null"?
Hi! Is it possible for warning There are conflicting field types in your data. GraphQL schema will omit those fields
to appear even if createTypes
is set up, preventing GraphQL from omitting the fields?
This is the warning from gatsby develop
:
ThumbprintToken.tokens.value.web:
- type: number
value: 1025
source: File "../packages/thumbprint-tokens/src/tokens/breakpoint.json"
- type: string
value: '4px'
source: File "../packages/thumbprint-tokens/src/tokens/border-radius.json"
And this is the usage of createTypes
:
exports.sourceNodes = ({ actions }) => {
const { createTypes } = actions;
const typeDefs = `
type ThumbprintToken implements Node {
tokens: [ThumbprintTokenTokens!]!
}
type ThumbprintTokenTokens {
value: ThumbprintTokenTokensValue!
}
type ThumbprintTokenTokensValue {
web: String
ios: String
android: String
}
`;
createTypes(typeDefs);
};
Without using createTypes
, GraphQL does indeed omit the fields. The data for those JSON files comes from gatsby-source-filesystem
and gatsby-transformer-json
. I'm using a function for the typeName
config in gatsby-transformer-json
.
Happy to make a small repro if it seems that the warning shouldn't be appearing.
Hello!
I am getting an error when using the built-in JSON
type.
// gatsby-node.js
export const sourceNodes = ({ actions: { createTypes }, schema }) => {
createTypes([
schema.buildObjectType({
name: 'MyTypeName',
fields: {
id: 'ID!',
json: 'JSON!',
},
}),
])
}
The following error is emitted:
success source and transform nodes — 1.550 s
error UNHANDLED REJECTION
Error: Schema must contain unique named types but contains multiple types named "JSON".
- Array.reduce
- SchemaComposer.js:122 SchemaComposer.buildSchema
[gatsby-ww]/[graphql-compose]/lib/SchemaComposer.js:122:12
- schema.js:480
[gatsby-starter-ww]/[gatsby]/dist/schema/schema.js:480:47
- Generator.next
- new Promise
- schema.js:539 addCustomResolveFunctions
[gatsby-starter-ww]/[gatsby]/dist/schema/schema.js:539:18
- schema.js:162
[gatsby-starter-ww]/[gatsby]/dist/schema/schema.js:162:11
- Generator.next
Could this be a result of graphql-compose
providing its own JSON
type rather than using the gatsby/graphql
version?
gatsby info
output:
System:
OS: macOS 10.14.2
CPU: (4) x64 Intel(R) Core(TM) i5-7600K CPU @ 3.80GHz
Shell: 5.6.2 - /usr/local/bin/zsh
Binaries:
Node: 10.15.3 - /var/folders/3z/fgqk0pmx30l2pc4801884_sm0000gn/T/yarn--1554423671012-0.23391063288947023/node
Yarn: 1.12.3 - /var/folders/3z/fgqk0pmx30l2pc4801884_sm0000gn/T/yarn--1554423671012-0.23391063288947023/yarn
npm: 6.4.1 - ~/.n/bin/npm
Languages:
Python: 2.7.10 - /usr/bin/python
Browsers:
Chrome: 73.0.3683.86
Firefox: 64.0
Safari: 12.0.2
npmPackages:
gatsby: 2.3.11 => 2.3.11
@angeloashmore It should be fixed with https://github.com/gatsbyjs/gatsby/pull/13028, I'll make a pre-release version today so you could test.
@danoc Currently there is no way to disable warnings like that. With https://github.com/gatsbyjs/gatsby/pull/13028 if you use @dontInfer
, no example value checking should happen and then there won't be a warning. However there won't be any inference too.
@d4rekanguok Could you provide a small reproduction for this? It should work as you described.
Published gatsby@2.4.0-alpha.1
@samovertonjr @smurrayatwork Pleae don't unpin this issue. Thanks!
Didn't know that clicking that would affect everyone.
Published 2.4.0-alpha.2
.
@prashant-andani Pleae don't unpin this issue. Thanks!
Hi, that was accidental... sorry for that
On Tue, 30 Apr 2019 at 6:38 PM, Lennart notifications@github.com wrote:
@prashant-andani https://github.com/prashant-andani Pleae don't unpin this issue. Thanks!
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/gatsbyjs/gatsby/issues/12272#issuecomment-487944961, or mute the thread https://github.com/notifications/unsubscribe-auth/AAGKROYK4RRFYRE3MOQL2NLPTBAE7ANCNFSM4G3OVU5Q .
-- Regards Prashant S Andani
What's the order of execution for mapping? I have a set of posts that I am trying to map to categories like the post -> authors
example. My raw source has id's in numbers, so I used create types to enforce a string assumption. Unfortunately, mapping doesn't seem to work if I use createTypes
. I thought createTypes
ran before the master schema was created?
//gatsby-config.js
mapping: {
"MarkdownRemark.frontmatter.speaker": `AuthorsYaml.name`, // works as expected
"MarkdownRemark.frontmatter.categories": `CategoriesYaml`,
},
//gatsby-node.js
exports.sourceNodes = ({ actions }) => {
const { createTypes } = actions
const typeDefs = `
type MarkdownRemarkFrontmatter {
categories: [String]
}
type MarkdownRemark implements Node {
frontmatter: MarkdownRemarkFrontmatter
}
`
createTypes(typeDefs)
}
Querying…
{
allMarkdownRemark {
nodes {
frontmatter {
categories
speaker {
name
}
}
}
}
}
Yields…
"allMarkdownRemark": {
"nodes": [
{
"frontmatter": {
"categories": [
"22"
],
"speaker": {
"name": "Sean Higgins"
}
}
}
]
I found a working solution where I tell the type to expect a CategoryYaml type instead of coercing it to a string and use a custom resolver to fetch the data.
It just seems like with the mapping mechanism in place, I probably should be able to force the string coercion, and then use the mapping to do the hookup for me.
Maybe I'm missing something?
Nested types :
gatsby-source-prismic
e.g.
PrismicNews
PrismicNewsBody
PrismicNewsBody
PrismicNewsBodyPrimary
PrismicNewsBodyItems
Types have the notion of repeatable groups (which end up in the Items) but if you don't have anything in the group, querying for it fails (because you're querying a type member that hasn't been inferred).
However, if you define the type so that you can declare items
, it's called out as a duplicate once you actually use the repeating group ; leaving you in the state where you have a [0..] piece of data but can only have code that supports 0 or 1..
So could the code (is there already a way) merge types that are not implements Node
?
Next one : Prismic's type system is a royal PITA and when using slices, etc, creates types with names appended to their container's name. This is reasonable because of the way it behaves - it has a "Slice library" concept, but it's a copy library, not a reference library - the type definition is just copied into the type def for the content type.
OTOH programmers hate duplication. So I've taken care to make sure the Slice type of a given name is the same everywhere by defining it on one page, saving it to the "library" and copying it outward - could we (do we?) have the ability to add interfaces so instead of
query {
pageOne {
data {
body {
... on PageOneBodyMyslice {
primary {
field
}
}
}
}
}
pageTwo {
data {
body {
... on PageTwoBodyMyslice {
primary {
field
}
}
}
}
}
}
... we could do
interface MySlice {
primary {
field
}
}
# somehow we mark the page slice types as implementing this
query {
pageOne {
data {
body {
... on MySlice {
... MySliceFragment
# etc
@awilkins gatsby-source-prismic
author here.
We're working on implementing automatic schema loading so Gatsby knows everything about your custom type shapes. We're hoping to publish a beta this week (which also includes a preview system!).
You will need to provide your schemas to the plugin going forward.
Re: your question about interfaces, the idea is sound, but I'm not sure if the types are merged. All slices implement the Node
interface and follow the pascalcase(${customType} ${sliceZoneName} ${sliceName})
naming convention.
@motleydev Hi! So createTypes and mappings are ran pretty much at the same time. Types defined by users always take priority over mapping types. You need to use custom resolver in this case. Gatsby can't really know that you want an object that will be serialized as string in this case, as String and CategoriesYaml aren't compatible types.
@angeloashmore Thanks for the response! I'll look forward to it ; my client no doubt will want changes and this will make things much easier.
interfaces
I'm sure you've noted that due to the way that Prismic does things, it's "slice library" just lets you copy slice type information into your custom type - so the different type names are necessary from the POV that you can actually have radically different slice types with the same name in different page types.
It's a PITA to update slice types in the CMS because you have to do it in one place, then copy that to all the other types, then open all the content and update it (if you introduced any incompatible changes).
But... if you're well behaved about it and do this consistently (or just have a very well used and mature set of slices), the benefits of being able to declare one global GraphQL fragment for each slice type or (maybe?) even one for all slices would be lovely - but fragments can only be applied to a type or interface, hence the desire to assign common interfaces to the different-but-identical-slice-types with the same name on different pages.
Published gatsby@2.5.0
.
Hello everyone. I have updated to Gatsby 2.5.0
but seem to run into the same type conflicts as @angeloashmore between graphql-compose and gatsby with the JSON type. Is there any simple way to resolve this conflict?
I am upgrading from Gatsby 1.9.x if that helps. Logs are below:
error UNHANDLED REJECTION
Error: Schema must contain uniquely named types but contains multiple types named "JSON".
- Array.reduce
- Array.reduce
- SchemaComposer.js:130 SchemaComposer.buildSchema
[blog]/[graphql-compose]/lib/SchemaComposer.js:130:12
- schema.js:500
[blog]/[gatsby]/dist/schema/schema.js:500:47
- Generator.next
- debuggability.js:313 Promise._execute
[npm]/[gatsby-cli]/[bluebird]/js/release/debuggability.js:313:9
- promise.js:483 Promise._resolveFromExecutor
[npm]/[gatsby-cli]/[bluebird]/js/release/promise.js:483:18
- promise.js:79 new Promise
[npm]/[gatsby-cli]/[bluebird]/js/release/promise.js:79:10
- schema.js:559 addCustomResolveFunctions
[blog]/[gatsby]/dist/schema/schema.js:559:18
- schema.js:163
[blog]/[gatsby]/dist/schema/schema.js:163:11
- Generator.next
- util.js:16 tryCatcher
[npm]/[gatsby-cli]/[bluebird]/js/release/util.js:16:23
- promise.js:512 Promise._settlePromiseFromHandler
[npm]/[gatsby-cli]/[bluebird]/js/release/promise.js:512:31
- promise.js:569 Promise._settlePromise
[npm]/[gatsby-cli]/[bluebird]/js/release/promise.js:569:18
- promise.js:606 Promise._settlePromiseCtx
[npm]/[gatsby-cli]/[bluebird]/js/release/promise.js:606:10
- async.js:142 _drainQueueStep
[npm]/[gatsby-cli]/[bluebird]/js/release/async.js:142:12
@Spiderpig86 Do you have this issue when upgrading to 2.4? I wonder if you could provide a reproduction project (or code to your app).
In the end, I ended up scrapping whatever dependencies I had and reinstalling all of it completely. This is the configuration I use now and it works very well.
We're running into an issue with gatsby-source-prismic
v3.0.0-alpha.2 with gatsby-source-filesystem
File nodes.
We tell Gatsby image fields will have a localFile
field with type File
, but if no File
nodes are created anywhere in the site, Gatsby does not know what File
is.
Error: Type with name "File" does not exists
Sorry, this might be a gatsby-source-filesystem
question more than a schema customization question, but just wondering if there's a way we can reliably tell Gatsby what File
is. Would gatsby-source-filesystem
need to export a File type definition from the package where source plugins could then explicitly provide to Gatsby?
Related issue: https://github.com/angeloashmore/gatsby-source-prismic/issues/97
@angeloashmore we could make gatsby-source-filesystem
explicitly register the File
type (and make it not panic
when the configured path does not exist). This way it would be possible to just provide gatsby-source-filesystem
(without options) in gatsby-config
and have the File
type available in the schema. Would something like this work in your case? This would still require gatsby-source-filesystem
to be installed because it owns the type -- but there are not-yet-concrete plans to maybe promote File
to a core type at some point.
@stefanprobst Yes, something like that looks like it could work.
In regards to plugin authors, if the plugin nondeterministically creates a File node, this would mean:
gatsby-source-filesystem
to their gatsby-config.js
to ensure Gatsby knows the File
type, orFile
type in type definitions if the plugin can determine a File
node will be created. I.e. if we know no nodes will be created with a File
field, don't include the File
field on the node that uses it. This could break builds if queries contain the now non-existent field.With Option 1, users could see the nonexistent path error message on every develop
or build
if they do not provide a path. In some projects, there may not be a need to use gatsby-source-filesystem
except to provide the File
type. Maybe we could change it so it only checks if the path exists if a path is provided?
With Option 2, plugin authors need to deal with the increased complexity of tracking File
node creation. This could be as simple as updating a global variable but it's still something to consider.
If gatsby-source-filesystem
exported the File
type (via GraphQL object or SDL string) and allowed plugin authors to register it with createType
, users do not need to change their workflow and plugin authors do not need to track File
usage.
This could potentially cause issues in the future if/when the File
type changes and plugins use different gatsby-source-filesystem
versions with incompatible File
definitions. This works okay now since, from what I understand, Gatsby infers the shape aggregately.
For reference, this is where we define a field using File
: standardTypes.graphql. This gets passed directly to createTypes
.
Correct me if I'm wrong @pieh, @stefanprobst, but I think making File
a core type isn't going to be a breaking change. It will break only the cases where it used to fail because File
wasn't there. So I propose that we do it.
Apologies for plopping this in here, if you can steer me in the right direction, I'll file a more focused ticket.
tl;dr Frontmatter-driven types.
I come from a CMS background so controlling my schemas is attractive. My Gatsby site uses Markdown frontmatter with type: author
in the YAML to specify the "type", but since everything is a MarkdownRemark
node type, I don't get real schemas.
I now have an Author
type via createTypes
. I have tried a number of avenues to make an Author
node, preferably as a child of the MarkdownRemark
node (so it gets deleted for free), but I can't find a way to do so. createNode
doesn't appear to be available in a resolver.
@pauleveritt One way to set up foreign-key relations between fields is with the @link
directive. For a typical blog (posts as .md
files, author info and tags in .yaml
files) it could look like this:
exports.sourceNodes = ({ actions }) => {
actions.createTypes(`
type MarkdownRemark implements Node @dontInfer {
frontmatter: Frontmatter
}
type Frontmatter {
title: String!
author: AuthorYaml @link(by: "email")
tags: [TagYaml] @link(by: "slug")
}
type AuthorYaml implements Node @dontInfer {
name: String!
email: String!
info: String
posts: [MarkdownRemark] @link(by: "frontmatter.author.email", from: "email")
}
type TagYaml implements Node @dontInfer {
slug: String!
title: String!
description: String
posts: [MarkdownRemark] @link(by: "frontmatter.tags.slug", from: "slug")
}
`)
}
I've also put this together in this repo.
We also finally have a bit of documentation on the schema customization APIs here. Please let us know if anything there is unclear or missing.
@freiksenet I think it depends if it means moving the type definitions for File
to core, or if (parts of) what is now gatsby-source-filesystem
should be moved with it as well. Moving File
alone should be ok I think.
@stefanprobst Neat concept...but I think the challenge is here:
I don't know how I can get a node created as a AuthorYaml
based on the frontmatter coming from the existing gatsby-source-filesystem
and gatsby-transformer-remark
.
It's likely I need to stop thinking about link targets as Markdown content and use .yaml
gatsby-transformer-yaml which lets me name the node type.
@pauleveritt
use
.yaml
gatsby-transformer-yaml
yes, this is what I do in the linked example. Any reason to put author info in markdown files?
@stefanprobst "Any reason to put author info in markdown files?"
I want everything -- author, category, tag, etc. -- to be a rich "resource" that people can edit, add images, code blocks, MDX stuff in the Markdown, etc.
But I'm not going to easily get that. :) I'll switch to YAML for those. Alas my "regular content" (tutorials, articles, blog posts) could also use being types with different schema, but I'll stick with inferred schema, instead of the new world of explicit types/schemas promoted since 2.2.
@pauleveritt yes, gatsby-transformer-remark
will only create one MarkdownRemark
type - and using that to represent different entities will be problematic. so this is not really a schema related issue, but you'd need a markdown transformer plugin that can create differently named makrkdown nodes (which should be quite doable).
that said (only as an experiment), it is possible to do this with MarkdownRemark
nodes only and use @link
on frontmatter fields. it looks a bit ugly but it works, see here for the example.
This is a meta issue for all the issues with 2.2.0, that were introduced by the schema refactoring.
What?
See the blog post for the details about why we did the refactoring and what's it all about.
See the release blog post for release notes and final updates.
How?
Install latest version of Gatsby and try running your site. Hopefully it will all just work. If you want, you could also try the two new APIs (
createTypes
andcreateResolvers
).Changelog
gatsby@2.5.0
gatsby@2.5.0-rc.1
gatsby@2.4.0-alpha.2
gatsby@2.4.0-alpha.1
gatsby@2.2.0
gatsby@2.2.0-rc.2
gatsby@2.2.0-rc.1
gatsby@2.2.0-alpha.6
gatsby@2.2.0-alpha.5
gatsby@2.2.0-alpha.4
gatsby@2.2.0-alpha.3
gatsby@2.2.0-alpha.2
graphql-compose@5.11.0
FilterInput
types are now not prefixed by output type, reducing proliferation of typesgatsby@2.2.0-alpha.1
@dontInfer(noDefaultResolvers: false)
actually workscreateResolvers
resolversinfo.originalResolver
is available even if there is no resolver on original fieldgatsby@2.2.0-alpha.0
gatsby@2.1.20-alpha.0