GraphQL學習與實踐3(Mutations And Input Types)

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

有緣請點顆星,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章