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)
代碼:
onsenOnly:https://github.com/onsenOnly/graphql-test
有緣請點顆星,謝謝!