GraphQL versioning, not nullable to nullable - graphql

At the begining we have schema
type User {
id: ID!
name: String!
birthday: String!
}
After some time it was decided that birthday is not mandatory for new users, so the schema should change to
type User {
id: ID!
name: String!
birthday: String
}
This is breaking change.
How to versioning case like this in GraphQL?

As mentionned in these official best practices under the section versioning, it isn't recommanded to do traditional API versioning in GraphQL even though there isn't any technical problems in doing so. I would feel that we are corrupting our model since it would introduce a technical field in a business API... which is definitely not ideal.
To help manage the API's evolution, they introduced the concept of field deprecation as described in this link.
To summarize in a few words, I would say that you have basically two solutions:
Do versioning anyway;
Set your field birthday as deprecated and add a new one with an equivalent name (birthday_date maybe?). Obviously, don't forget to tell your api clients to use this new field. In the long run, remove the deprecated field.

Related

Best practice for mailing addresses types

I am fairly new to GraphQL and i am writing a schema which will include companies and users. Each of these entities will have a mailing address associated with them. I am also using AWS Amplify to generate the resolvers and the DB (at least to get the project going).
I don't intend to retrieve an address separate from its user/company
Want to make the schema as modular as possible without repeating information unnecessarily
Here's an abbreviated version of what I started
type Address {
id: ID!
streetAddress1: String!
streetAddress2: String
city: String!
state: String!
zipCode: String!
country: String!
coordinates: String
}
type Company
{
id: ID!
name: String!
address: Address!
...
}
My question is whether it is best to have the address as a separate type in my schema or to lump each of the company/user types with their own address?
These are my concerns though
Separating address and entity increases complexity of the business logic and/or mutations.
In essence, turning the CRUD operations transactional in nature so that both user and address are mutated/queried.
Figured I would use an Address type without #model annotation and no #connection from the types that require it.

How to export field definitions in 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.

How to develop AppSync schemas using Apollo tools

I'm using AppSync with Serverless and in the early phase of a new GraphQL implementation, that will eventually become rather large.
I've started off small, following the AWS recommended and published standards for schema development. My schema is starting to get larger and larger, and I'm left wanting better tools that I find are available in Apollo (it appears that with Apollo, you can extend types, modularize, etc).
The schema development is static thus far -- you point serverless to a schema and thats it. Is anyone aware of a library that supports an Apollo like environment (extending types, modular design, etc)? Possibly something that compiles a schema, that I could point serverless to? I have looked a little bit, but haven't really found anything that would work.
I finally found library that does this for me. If you're in need, take a look at graphql-s2s
I was able to take the below schema, transpile it, save it, and point serverless to the generated schema.
Original:
type TenantScope {
tenantId: String
}
type Asset inherits TenantScope {
type: String!
}
type Vehicle inherits Asset {
vin: String!
stockNum: String!
}
Transpiled:
type TenantScope {
tenantId: String
}
type Asset {
type: String!
tenantId: String
}
type Vehicle {
vin: String!
stockNum: String!
type: String!
tenantId: String
}

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.

Spring-Couchbase auto generated unique ID not for production?

The feature documentation
and the reference document of the spring-data-couchbase module says that the feature of generating IDs, using the build in 'UNIQUE' generation strategy shall only be used for test scaffolding. This statement is given without an explanation.
Why shall this method not be suitable for production?
Example usage:
#Document
class Entity(
#Id
#GeneratedValue(strategy = GenerationStrategy.UNIQUE)
val id: String?,
#Version
val version: String?,
#CreatedDate
val creationTime: LocalDateTime?
)
Writes in couchbase are asynchronous by default, same with views and indexes. But, if you need strong consistency (read after you write ) you should get the document by its key.
So, if you rely on the database to autogenerate they key for you, you will need to wait until the document is actually persisted in the database in order to get the generated id back. This wait can increase significantly your overall write throughput.
Generate your own ids is also considered a good practice, but please, avoid generating sequential ones (owasp security flaw - sequential ids).
This is the code I use for id generation:
public String generateId(Class t) {
return t.getSimpleName()+"--"+UUID.randomUUID().toString()+UUID.randomUUID().toString();
}

Resources