2. ➢ Just a query language
GraphQL is …
type User {
id: ID!
name: String!
}
type Query {
user(id: ID): User
}
query {
user(id: "10") {
id
name
}
}
{
"data": {
"user": {
"id": "10",
"name": "Croquis"
}
}
}
+
4. import { GraphQLObjectType, GraphQLSchema,
GraphQLString, printSchema } from 'graphql';
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'RootQueryType',
fields: {
hello: {
type: GraphQLString,
},
},
}),
});
console.log(printSchema(schema));
Define Schema: raw object
schema {
query: RootQueryType
}
type RootQueryType {
hello: String
}
5. import { GraphQLList, GraphQLNonNull, GraphQLObjectType,
GraphQLSchema, GraphQLString } from 'graphql';
const user = new GraphQLObjectType({
name: 'User', fields: {
name: {
type: GraphQLNonNull(GraphQLString),
} } });
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: {
users: {
type: GraphQLNonNull(GraphQLList(GraphQLNonNull(user))),
} } }) });
Define Schema: custom type
type Query {
users: [User!]!
}
type User {
name: String!
}
6. import { buildSchema } from 'graphql';
const schema = buildSchema(`
type User {
name: String!
}
type Query {
users: [User!]!
}
`);
Define Schema: using GraphQL schema language
13. var defaultFieldResolver = function defaultFieldResolver(source, args, contextValue,
info) {
// ensure source is a value for which property access is acceptable.
if (_typeof(source) === 'object' || typeof source === 'function') {
var property = source[info.fieldName];
if (typeof property === 'function') {
return source[info.fieldName](args, contextValue, info);
}
return property;
}
};
Root Value: internal
16. ➢ Function signature: resolver(obj, args, context, info)
✓ For root value: (args, context, info)
➢ Call defaultFieldResolver if not defined
➢ Always called even if object has a field value
Resolver
17. const schema = buildSchema(`
type User { name: String! }
type Query { users: [User!]! }`);
const resolvers = {
Query: {
users(obj) {
return [{ name: 'Name1' }, { name: 'Name2' }];
} },
User: {
name(obj) {
return obj.name.toLowerCase();
} } };
console.log(await graphql(schema, '{ users { name } }', { foo: 1 }));
// { data: { users: [ { name: 'name1' }, { name: 'name2' } ] } }
Resolver when object has a field value
18. ➢ Contains the result returned from the resolver on the parent field
✓ Root Value for Query field
➢ @Root() in TypeGraphQL
Resolver Arguments: 1) obj (source, parent)
22. ➢ An object shared by all resolvers in a particular query
➢ Per-request
➢ For examples:
✓ authentication information
✓ dataloader instances
➢ @Ctx() in TypeGraphQL
Resolver Arguments: 3) context
34. ➢ Use DataLoader
➢ Batch function must return an array of values that have same order to an array of
keys
➢ It is common to create a new DataLoader per request (context will be helpful)
Advanced: N+1 problem
import DataLoader from 'dataloader';
resolve(parent, args, context, info) {
if (!context.loader) {
context.loader = new DataLoader((keys) => {
return ['value for keys[0]', 'value for keys[1]', ...];
});
}
return context.loader.load(key);
},
35. ➢ Subscription is a one-way communication from server to client.
✓ Socket.io is a two-way
➢ You need to implement ‘subscribe’ method that returns AsyncIterator
Advanced: subscription
36. import { PubSub } from 'graphql-subscriptions';
const pubSub = new PubSub();
async function doTask(task_id: number) {
for (let i = 0; i < 10; i++) {
await Bluebird.delay(1000);
pubSub.publish(`doTask-${task_id}`, i);
}
pubSub.publish(`doTask-${task_id}`, 'done');
}
const schema = new GraphQLSchema({
subscription: new GraphQLObjectType({
name: 'RootSubscriptionType',
fields: {
doTaskProgressed: {
type: GraphQLString,
args: { task_id: { type: new GraphQLNonNull(GraphQLInt) } },
subscribe: (source, args) => {
const task_id = args.task_id;
return pubSub.asyncIterator(`doTask-${task_id}`);
},
} } }) });
Advanced: subscription - run task in separate thread
- Task will run regardless subscription
- You need ‘done’ to notify task ended
37. const schema = new GraphQLSchema({
subscription: new GraphQLObjectType({
name: 'RootSubscriptionType',
fields: {
doTaskWithProgress: {
type: GraphQLString,
async *subscribe(source, args) {
for (let i = 0; i < 10; i++) {
await Bluebird.delay(1000);
yield i;
}
},
} } }) });
Advanced: subscription - run task in subscribe
- Task will stop when subscription ended
- Subscription will be ended when task ended