GraphQL学习与实践3(Mutations And Input Types)
在上一节中留下了三个类型没有做讲述,分别为:接口、联合类型、输入类型
剩下的三个类型
接口类型
接口是一个抽象类型,它包含某些字段,而对象类型需要实现该接口,必须包含这些字段,接口用interface表示。
这里直接引用官网的例子进行举例:
interface Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
}
type Human implements Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
starships: [Starship]
totalCredits: Int
}
type Droid implements Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
primaryFunction: String
}
两个类型都具备 Character 接口的所有字段,但也引入了其他的字段 totalCredits、starships 和 primaryFunction,这都属于特定的类型的角色。(即:如果返回的类型是Character,需要primaryFunction属性的话就会报错。)
联合类型
联合类型和接口十分相似,但是它并不指定类型之间的任何共同字段,用union表示。例如:
union SearchResult = Human | Droid | Starship
表示任何返回一个 SearchResult 类型的地方,都可能得到一个 Human、Droid 或者 Starship。或许简单点的来理解就是一个或的运算。
输入类型
为了更容易的传递复杂对象,特别是在变更(mutation)中特别有用,比如需要传递一整个对象的时候。input就是用在这个时候的关键字。例如:
input ReviewInput {
stars: Int!
commentary: String
}
变更
我们知道query在GraphQL中一个读的操作,那么想修改数据的时候,那又应该怎样呢?
在GraphQL中有这样一个约定来规范任何导致写入的操作都应该显式通过变更(mutation)来发送。
就如同查询一样,如果任何变更字段返回一个对象类型,你也能请求其嵌套字段。获取一个对象变更后的新状态也是十分有用的。我们来看看一个变更例子:
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
createReview(episode: $ep, review: $review) {
stars
commentary
}
}
注意 createReview 字段如何返回了新建的 review 的 stars 和 commentary 字段。这在变更已有数据时特别有用,例如,当一个字段自增的时候,我们可以在一个请求中变更并查询这个字段的新值。
这个例子中,我们传递的 review 变量并非标量。它是一个输入对象类型,一种特殊的对象类型,可以作为参数传递。
Mutations And Input Types
在官网上就有这样的一个章节叫 Mutations And Input Types的。可以看得出一般mutations比较适合和Input类型一起使用,这里直接上官网的例子,新建一个test8-mutation.js文件,输入:
var express = require('express');
var graphqlHTTP = require('express-graphql');
var { buildSchema } = require('graphql');
// Construct a schema, using GraphQL schema language
var schema = buildSchema(`
input MessageInput {
content: String
author: String
}
type Message {
id: ID!
content: String
author: String
}
type Query {
getMessage(id: ID!): Message
}
type Mutation {
createMessage(input: MessageInput): Message
updateMessage(id: ID!, input: MessageInput): Message
}
`
);
// If Message had any complex fields, we'd put them on this object.
class Message {
constructor(id, { content, author }) {
this.id = id;
this.content = content;
this.author = author;
}
}
// Maps username to content
var fakeDatabase = {};
var root = {
getMessage: function ({ id }) {
if (!fakeDatabase[id]) {
throw new Error('no message exists with id ' + id);
}
return new Message(id, fakeDatabase[id]);
},
createMessage: function ({ input }) {
// Create a random id for our "database".
var id = require('crypto').randomBytes(10).toString('hex');
fakeDatabase[id] = input;
return new Message(id, input);
},
updateMessage: function ({ id, input }) {
if (!fakeDatabase[id]) {
throw new Error('no message exists with id ' + id);
}
// This replaces all old data, but some apps might want partial update.
fakeDatabase[id] = input;
return new Message(id, input);
},
};
var app = express();
app.use('/graphql', graphqlHTTP({ schema: schema, rootValue: root, graphiql: true, }));
app.listen(4000, () => { console.log('Running a GraphQL API server at localhost:4000/graphql'); });
在上面的例子中,我们可以看出这个文件中定义了三个操作方法,一个是getMessage(获取信息)、一个是createMessage(创建信息)、一个是updateMessage(更新信息)。
执行node test8-mutation.js。打开浏览器(localhost:4000/graphql)的调试工具,输入:
mutation{
createMessage(input:{
author:"andy",
content:"hope is a good thing",
}){id}
}
这里是创建一个信息。如图:
然后查看信息类型对象的值是否创建成功了,注释点上面的创建信息的操作(ctrl+/),然后输入查询的操作,输入:
{
getMessage(id:"20e68b77867e3a0dec9a") {
id,
author,
}
}
如图:
这里的查询是引用了上面的创建操作之后的,如果id输入错误会是得到一个报错的返回的。然后,我们在执行修改操作,把author为“andy”修改为“andy123”,输入:
mutation{
updateMessage(id:"20e68b77867e3a0dec9a",input:{
author:"andy123",
# content:"hope is a good thing",
}){id,author}
}
得到的操作结果,如图:
从上图中,我们看到了此时内存中的数据已经被改变了。
然后,我们把上面用buildSchema的方式同样根据第二章节的做法进行用对象的形式改写一下,修改test8-mutation.js的文件:
var express = require('express');
var graphqlHTTP = require('express-graphql');
var graphql = require('graphql');
// Maps id to User object
var fakeDatabase = {};
// Define the User type
class Message {
constructor(id, { content, author }) {
this.id = id;
this.content = content;
this.author = author;
}
}
var messageType = new graphql.GraphQLObjectType({
name: 'Message',
fields: {
id: {
type: graphql.GraphQLString
},
author: {
type: graphql.GraphQLString
},
content: {
type: graphql.GraphQLString
},
}
});
var messageInputType = new graphql.GraphQLInputObjectType({
name: 'MessageInput',
fields: {
id: {
type: graphql.GraphQLString
},
author: {
type: graphql.GraphQLString
},
content: {
type: graphql.GraphQLString
},
}
});
// Define the Query type
var queryType = new graphql.GraphQLObjectType({
name: 'Query',
fields: {
getMessage: {
type: messageType,
args: {
id: {
type: graphql.GraphQLString
}
},
resolve: function (_, { id }) {
if (!fakeDatabase[id]) {
throw new Error('no message exists with id ' + id);
}
return new Message(id, fakeDatabase[id]);
}
}
}
});
var mutationType = new graphql.GraphQLObjectType({
name: 'Mutation',
fields: {
createMessage: {
type: messageType,
args: {
input: {
type: messageInputType
}
},
resolve: function (_, { input }) {
var id = require('crypto').randomBytes(10).toString('hex');
fakeDatabase[id] = input;
return new Message(id, input);
}
},
updateMessage: {
type: messageType,
args: {
id: {
type: graphql.GraphQLString
},
input: {
type: messageInputType
}
},
resolve: function (_, { id, input }) {
if (!fakeDatabase[id]) {
throw new Error('no message exists with id ' + id);
}
// This replaces all old data, but some apps might want partial update.
fakeDatabase[id] = input;
return new Message(id, input);
}
}
}
});
var schema = new graphql.GraphQLSchema({ query: queryType, mutation: mutationType });
var app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
graphiql: true,
}));
app.listen(4000);
console.log('Running a GraphQL API server at localhost:4000/graphql');
如上所示,我们把buildSchema中的type的Message和input的MessageInput分别用GraphQLObjectType和GraphQLInputObjectType表示,同时把Query读操作和变更操作的Mutations也用GraphQLObjectType表示。在Query中只有getMessage一个区域,在Mutations中有createMessage和updateMessage两个区域。
然后同样的执行node test8-mutation.js。打开浏览器(localhost:4000/graphql)的调试工具,输入上面测试用例进行调试即可。
更多
GraphQL学习与实践1(入门介绍)
GraphQL学习与实践2(类型、传参与构造函数类型)
GraphQL学习与实践3(Mutations And Input Types)
GraphQL学习与实践4(模拟客户端请求)
GraphQL学习与实践5(连接数据库mongodb与mysql)
代码:
onsenOnly:https://github.com/onsenOnly/graphql-test
有缘请点颗星,谢谢!