Apollo Graphql: Rename schema for backward compatibility - graphql

What I want do ?
In Apollo Graphl server, I want to change an entity Person to Human in schema but i don't want to break my clients (frontend that are querying graphql). So if client is making query for Person i want to map it to Human.
Example:
CLIENT QUERY
query {
Person {
ID
firstName
}
}
REWRITE TO
query {
Human {
ID
name
}
}
REWRITE THE RESPONSE
{
data: {
Person: {
Id: 123,
name:"abc"
}
}
}
Things that I have tried
graphql-rewriter provides something similar to what i am looking for. I went through it documentation but it doesn't have the option to rewrite the field name.
In apollo graphql documentation Apollow graphql directives, They have mentioned about rename directive but i did not find rename-directive-package the node module.
apollo-directives-package I have tried this as well but it doesn't have the option to rename the scaler field e.g
import { makeExecutableSchema } from "graphql-tools";
import { RenameDirective } from "rename-directive-package";
const typeDefs = `
type Person #rename(to: "Human") {
name: String!
currentDateMinusDateOfBirth: Int #rename(to: "age")
}`;
const schema = makeExecutableSchema({
typeDefs,
schemaDirectives: {
rename: RenameDirective
}
});
Any suggestions/help would be appreciated.

Here i hope this gives helps you, first we have to create the schema-directive
import { SchemaDirectiveVisitor } from "graphql-tools";
import { GraphQLObjectType, defaultFieldResolver } from "graphql";
/**
*
*/
export class RenameSchemaDirective extends SchemaDirectiveVisitor {
/**
*
* #param {GraphQLObjectType} obj
*/
visitObject(obj) {
const { resolve = defaultFieldResolver } = obj;
obj.name = this.args.to;
console.log(obj);
}
}
type-defs.js
directive #rename(to: String!) on OBJ
type AuthorizedUser #rename(to: "Human1") {
id: ID!
token: ID!
fullName: String!
roles: [Role!]!
}

Related

How to make GraphQL enum data in resolver with nestjs/graphql?

In this way, it can pass enum data in resolver:
enum AuthType {
GOOGLE = 'google-auth',
GITHUB = 'github-auth',
OUTLOOK = 'outlook-auth',
}
interface UsersArgs {
first: number,
from?: string,
status?: String,
authType?: AuthType,
}
export const resolvers = {
AuthType,
Query: {
users: (_record: never, args: UsersArgs, _context: never) {
// args.authType will always be 'google-auth' or 'github-auth' or 'outlook-auth'
// ...
}
}
}
There is also good example for pure GraphQL syntax as:
https://www.graphql-tools.com/docs/scalars#internal-values
In NestJS, the code like
import { Args, Query, Resolver } from '#nestjs/graphql';
import { AuthType } from '#enum/authEnum';
#Resolver()
export class AuthResolver {
constructor(private readonly authRepo: AbstractAuthSettingRepository) {}
#Query(() => AuthSetting)
findAuth(
#Args('input')
id: string,
): Promise<AuthSetting | undefined> {
return this.authRepo.findOne({ id });
}
}
How can I use AuthType in the AuthResolver class?
In order to be able to use enums in NestJS GraphQL, you need to register them once:
import { registerEnumType } from '#nestjs/graphql';
import { AuthType } from '#enum/authEnum';
registerEnumType(AuthType, { name: 'AuthType' });

Handle types with identical properties in GraphQL

I've joined a codebase that used GraphQL and is in dire need of DRYing up. Example code would look like this:
/plugins/abc/schemas/user.js
const { gql } = require('apollo-server-express')
module.export.defTypes = gql`
type User {
name: String
id: String
location: String
}
`
/plugins/def/schemas/user.js
const { gql } = require('apollo-server-express')
module.export.defTypes = gql`
type User {
name: String
id: String
location: String
}
`
I don't know GraphQL terribly well, but given that this was just exporting string content, I assumed I could do this:
/plugins/def/schemas/user.js
const { gql } = require('apollo-server-express');
const { user } = require('../shared/schemas');
module.export.defTypes = gql`
type User {
${user}
}
But graphQL throws up an error:
(node:78551) UnhandledPromiseRejectionWarning: MissingSchemaError: Schema hasn't been registered for model "<name of unrelated model>".
Is there a correct, GraphQL-y way to do this?

Nested query and mutation in type-Graphql

I found a feature in graphql to write nested query and mutation, I tried it but got null. I found the best practices of building graphqL schema on Meetup HolyJs and the speaker told that one of the best ways is building "Namespaced" mutations/queries nested, in this way you can write some middlewares inside the "Namespaced" mutations/queries and for get the Child mutation you should return an empty array because if you return an empty array, Graphql understand it and go one level deep.
Please check the example code.
Example in graphql-tools
const typeDefs = gql`
type Query { ...}
type Post { ... }
type Mutation {
likePost(id: Int!): LikePostPayload
}
type LikePostPayload {
recordId: Int
record: Post
# ✨✨✨ magic – add 'query' field with 'Query' root-type
query: Query!
}
`;
const resolvers = {
Mutation: {
likePost: async (_, { id }, context) => {
const post = await context.DB.Post.find(id);
post.like();
return {
record: post,
recordId: post.id,
query: {}, // ✨✨✨ magic - just return empty Object
};
},
}
};
This is my Code
types
import { ObjectType, Field } from "type-graphql";
import { MeTypes } from "../User/Me/Me.types";
#ObjectType()
export class MeNameSpaceTypes {
#Field()
hello: string;
#Field({ nullable: true })
meCheck: MeTypes;
}
import { Resolver, Query } from "type-graphql";
import { MeNameSpaceTypes } from "./MeNamespace.types";
#Resolver()
export class MeResolver {
#Query(() => MeNameSpaceTypes)
async Me() {
const response = {
hello: "world",
meCheck:{}
};
return response;
}
}
Result of code
query {
Me{
hello
meCheck{
meHello
}
}
}
--RESULT--
{
"data": {
"Me": {
"hello": "world",
"meCheck": {
"meHello": null
}
}
}
}
I got a null instead a meHello resolver. Where am I wrong?
Namespaced mutations are against GraphQL spec as they are not guarranted to run sequentially - more info in this discussion in GitHub issue related to your problem:
https://github.com/MichalLytek/type-graphql/issues/64

Schema Stitching in Apollo GraphQL doesn't resolve types from other parts

I'm trying to make my GraphQL schema composable through schema stitching, but I'm struggling with how to resolve properties of types from a different part.
Here's the schema before decomposing:
type Referee {
id: ID!
stringProp: String!
}
type Referer {
id: ID!
pointer: Referee!
}
type Query {
referers: [Referer]
}
The types both have resolvers, in their respective schemas, that expand object { id } into { id, stringProp } or { id, pointer: { id } }, so that a query
query FromSingleSchema {
referers: {
id
pointer {
id
stringProp
}
}
}
resolves as expected; Query.referers resolves to a list of [{id}] objects, and each of those in turn resolve first into a Referer and then fetches the pointed-to Referee through type resolvers.
Now, I try to decompose the schema:
// schema A
type Referee {
id: ID!
stringProp: String!
}
// schema B
type Referer {
id: ID!
}
type Query {
referers: [Referer]
}
// schema Extensions
extend type Referer {
pointer: Referee!
}
and compose it again:
// both schemaA and schemaB have been created with makeExecutableSchema
import schemaA from './A'
import schemaB from './B'
// schemaExtensions is just a raw GraphQL string
// resolverExtensions is shown below
import { schemaExtensions, resolverExtensions } from './B'
const schema = mergeSchemas({
schemas: [schemaA, schemaB, schemaExtensions],
resolvers: Object.assign({}, resolverExtensions)
})
// resolverExtensions defined as follows:
{
Referer: {
pointer: {
fragment: 'fragment IdFragment on Referee { id }',
resolve: o => ({ id: o.pointerId })
}
}
}
With this, I can run this query without problems:
query OnlyIdFromDecomposedSchemas {
referers: {
id
pointer {
id
}
}
}
but this fails
query FullRefereeFromDecomposedSchemas {
referers: {
id
pointer {
id
stringProp
}
}
}
with the error message
Cannot return null for non-nullable field Referee.stringProp.
What do I need to do for the type resolver for Referee to be able to fill in the rest of the properties once { id } is available, like it does in a single, non-decomposed, schema?
I think you are looking for schema delegation. Schema Delegation is a way to automatically forward a query (or a part of a query) from a parent schema to another schema (called a subschema) that is able to execute the query.
You can use delegateToSchema method like this in your resolver:
{
Referer: {
pointer : {
resolve(parent, args, context, info) {
return info.mergeInfo.delegateToSchema({
schema: schemaA,
operation: 'query',
fieldName: 'referee', // modify according to your query for referee
context,
info,
});
}
}
}
}

Hello world example for Apollo Client 2 + React?

Im trying to return a string with React and GraphQL but I'm getting stuck at the first stage. Here is my attempt:
import { makeExecutableSchema } from 'graphql-tools';
const typeDefs = `
type Query {
author: Person
}
type Person {
name: String
}
`;
const resolvers = {
Query: {
author: { name: 'billy' },
},
};
const schema = makeExecutableSchema({
typeDefs,
resolvers,
});
createApolloServer({ schema });
And this is my understanding of that code:
In my schema I've defined a Query called author which should return a Person.
A Person has a name field which is a string.
My resolver has a Query called author which should return an object with a name field of value 'billy'
However in my Graphicool browser tools this query:
query {
author{
name
}
}
Returns this:
{
"data": {
"author": null
}
}
Resolvers are functions which GraphQL will call when resolving that particular field. That means your resolvers object should look more like this:
const resolvers = {
Query: {
author: () => ({ name: 'billy' }),
},
}
Or, alternatively,
const resolvers = {
Query: {
author() {
return { name: 'billy' }
},
},
}
You can check out the docs for more information.
import { createApolloServer } from 'meteor/apollo';
import { makeExecutableSchema } from 'graphql-tools';
import merge from 'lodash/merge'; // will be useful later when their are more schemas
import GroupsSchema from './Groups.graphql';
import GroupsResolvers from './resolvers';
const typeDefs = [GroupsSchema];
const resolvers = merge(GroupsResolvers);
const schema = makeExecutableSchema({
typeDefs,
resolvers,
});
createApolloServer({ schema });
In ./Groups.graphql:
type Query {
hi: String
groups: [Group]
group: Group
}
type Group {
name: String
}
In './resolvers':
export default {
Query: {
hi() {
return 'howdy';
},
groups() {
return [{ name: 'one', _id: '123' }, { name: 'two', _id: '456' }];
// return Groups.find().fetch();
},
group() {
return { name: 'found me' };
},
},
};
In a React component:
const mainQuery = gql`
{
groups {
name
}
}
`;
export default graphql(mainQuery)(ComponentName);

Resources