How to export field definitions in GraphQL - graphql

How can I export field definitions in GraphQL? For example, let's say I have
schema.graphql:
type Query {
comment: String!
}
can I instead do something like this?
query.graphql:
const query = comment: String!;
export query;
schema.graphql:
import { query } from './query.graphql';
type Query {
query
}
EDIT:
The real intent behind this question is how do you organize your Querys or Mutations by schema? For example:
type Mutation {
createComment(data: CreateCommentInput): Comment!,
createPost(data: CreatePostInput): Post!,
createUser(data: CreateUserInput): User!,
deleteComment(id: ID!): Comment!,
deletePost(id: ID!): Post!,
deleteUser(id: ID!): User!,
}
Right now my application only has three objects: Comments, Posts, and Users. My preference is to organize my Inputs, Resolvers, etc by schema (e.g. Comments, Posts, and Users), but that means at the end of the day I still have to put everything into a single Mutation type. This seems quite difficult to scale for much larger applications where there could be dozens and dozens of objects and relations, mutations, and more, and it would be nice to separate out individual mutations in their respective Comments folder, Users folder, etc. Thanks!

GraphQL does not support any kind of import/export syntax.
Certain libraries like graphql-tag and babel-plugin-import-graphql support importing fragments or type definitions through comments, but these libraries do not support importing individual field definitions.
At best, you could utilize template strings, but you'd have to utilize JavaScript/TypeScript files instead (assuming you're working with a Node.js server, but that's not totally clear from your question).
fields.js
export const fields = `
comment: String!
`
query.js
import { fields } from './fields'
export const typeDefs = `
type Query {
${fields}
}
`
At the end of the day, though, it's unlikely you have enough duplication between your type definitions to warrant doing something like this. Unless you have dozens of common fields across dozens of types, I would just deal with the duplication.
If you're just looking to modularize your schema across multiple files, you can use the extend to create multiple type definitions that will be merged into a single one. For example:
type Query {
someField: String!
}
extend type Query {
someOtherField: String!
}
extend type Query {
yetAnotherField: String!
}
Not that you must still define the type you're extending -- you cannot have extensions that reference a non-existent type. When using extensions, however, your "base" type doesn't necessarily have to have fields (as long as you have at least one extension). So you can do something like this as well:
type Query # Note the lack of curly brackets
extend type Query {
someOtherField: String!
}
There are also libraries out there, like this one, that let you merge type definitions without using the extend keyword. There are some known issues with this sort of programmatic merging, but YMMV.
Lastly, although I'm personally not a fan of doing things this way, you may find this pattern helpful in organizing your schema.

Related

Is it possible to extend an enum in graphql

I have one enum:
enum Content {
QUESTION
SOLUTION
}
Can this enum be extended like (In Node):
extend enum Content {
QUESTION #external
SOLUTION #external
ANSWER
}
It is allowed by the specification, see https://spec.graphql.org/June2018/#sec-Enum-Extensions
From the use of the external directive, I imagine you would want to use it in a federated gateway. I am not confident this will work considering the wording of the Apollo documentation: For enums and unions, all possible values must match across all defining subgraphs. I would suggest you use a shared package to create the shared types instead so the schema composition doesn't fail.

Can the return type be transformed for a GraphQL resolver

I have a graphene-django GraphQL API that I've added custom directives and middleware in that are very similar to what's offered by graphene-django-extras. There are several places where enum types are returned as a graphene.Int() field, I'd like to be able to use a directive to transform that a graphene.String() but it doesn't do that on its own. eg.
{
foo {
bar # return Int
# vs
bar #readable # return String
}
}
Is that even possible? I'm looking through the ResolvInfo fields and there is something for the return type, but initial attempts don't work.
Edit: FWIW I don't think it matters that the API is currently developed using Python and Graphene. The question is more about whether or not GraphQL even supports this, I assume that if it does not then no language or library would make it possible.
It's not really in the spirit of graphQL to have a variable output type. So strictly speaking, you shouldn't try to do this. That being said, instead you could easily add another field for the other type, i.e.
type Foo {
barStr: String
barInt: Int
}
and then just ask for the one that you want in your query.

Why is TYPE_ADDED_TO_INTERFACE considered a breaking change?

I am using the Apollo Server implementation of GraphQL, together with the Apollo Engine, and specifically the functionality to check whether a schema diff contains any breaking changes. I'd like to understand better why TYPE_ADDED_TO_INTERFACE is considered to be a breaking change, and if anyone can provide an example of a graphql query that would break, as a consequence?
I'm using the apollo/2.9.0 darwin-x64 node-v10.10.0 to perform the schema check with the apollo service:check command.
For example, if I have this schema:
interface Animal {
id: ID
}
type Dog implements Animal {
id: ID
favoriteToy: String
}
And then add this to the schema:
type Cat implements Animal {
id: ID
}
This is considered a breaking change. Why?
I can see that if someone is making a query for all the Animal objects, and has a ... on Dog fragment in the query, they would start getting Cat objects back with only the interface fields, until they also add a ... on Cat fragment. Is that what's considered breaking?
Having a type implement an interface it previously did not should not break existing queries. To your point, even if the inline fragment is omitted, the results will still be valid (they could result in an empty object being returned if no interface fields were selected, but that's still a valid response).
I could, however, foresee issues in specific clients resulting from this kind of change. For example, when using Apollo client, we often create an IntrospectionFragmentMatcher to specifically help the client correctly cache results from union or interface fields.
To support result validation and accurate fragment matching on unions and interfaces, a special fragment matcher called the IntrospectionFragmentMatcher can be used. If there are any changes related to union or interface types in your schema, you will have to update the fragment matcher accordingly.
In other words, having the schema change in this way could break client caching behavior. I suspect for clients that do schema-based code-generation, like apollo-android, this could also result in some runtime weirdness.

Is there a good pattern for merging the results of two graphQL schemas?

I've been looking around to see if a pattern exists for merging two graphQL datasets which contain the same type of data. What I mean is, given the following two type definitions;
type StevesBooks {
title: String
author: String
}
type DavesBooks {
title: String
author: String
}
If both of those are implemented as graphQL schemas separately/remotely, each with their own set of resolvers, is there a pattern or paradigm I can draw from to create a third graphQL instance that combines these two, so I can query "SteveAndDavesBooks" at the same time?
I found mergeSchemas in the apolloServer API but that solves a different problem to this one and all of the conflict-resolution methods in there require you to "choose a side" so to speak, rather than combine the results.
Is there already-written plugin or library somewhere that will help to achieve the above or do you think this is going to be something bespoke that I need to do myself?
I saw that query federation is on the roadmap - does anyone know any more details about that because that sounds like what I'm after.

Graphql complex boolean queries

I understand the principles of querying via graphql from the docs you could search:
{
"hero": {
"name": "R2-D2"
}
}
but how about you want to do something a bit more intricate such as:
{
"hero": {
"name": "R2-D2 AND C-3PO AND BB-8 NOT K-2SO"
}
}
is there any way to pass a string like this and get the appropriate results?
No, there isn't.
You can read through the GraphQL spec and see what it does and doesn't define. In particular the spec doesn't define any sort of filtering, any sort of expression language, or any sort of Boolean combinators. (There is no native way to say the equivalent of SQL's WHERE NAME='foo' without a field resolver explicitly adding it.)
What GraphQL allows for field arguments is sufficiently open-ended that you can build richer queries on top of it, but that's very specific to some application or library. Two prominent examples are the GitHub GraphQL API (which tends to allow exact-match queries on selected fields but nothing richer) and the Prisma API (which has an involved multi-level object scheme to replicate SQL queries).

Resources