Github提供的GraphQL接口很是全面,那麼咱們該如何搭建出本身的接口呢?好在GraphQL提供了不少語言的解決方案。本文主要闡述如何用go搭建本身的GraphQL服務器。若是瞭解GraphQL建議先閱讀GraphQL — API查詢語言 或相關資料。python
An implementation of GraphQL in Go. Follows the official reference implementation
graphql-js
.
一套比較完善的框架,衆所周知go的結構體對json很是友好,因此並不須要對數據有特殊的處理,仍是很方便的。打開終端輸入命令git
go get github.com/graphql-go/graphql
github
在服務端編程中,編寫的一切均可以稱之爲對象(Object)。例如一個商品(goods)的實例能夠有商品名(name)、價格(price)、購買連接(url)三個字段。此時商品能夠很天然的被稱爲一個object,查詢的語句能夠寫成:golang
{ goods{ name price url } }
若是此時咱們要查詢商品和文章兩種object的信息:編程
/* query 能夠省去 */ query{ goods{ name } article{ name } }
是否你已經發覺,query像一個大的object,它有goods和article兩個字段。除此以外,mutation也是如此:json
mutation{ addGoods(input:goodsInput){ name } }
這裏的addGoods
能夠看作是一個能夠處理參數的對象,也就是某種意義上的函數。api
總之,GraphQL服務端的編程就是一個又一個的對象將造成的嵌套結構(schema)組織起來,並對外提供服務。數組
爲了防止低級錯誤的發生,在當前pkg下新建一個名爲query.go(隨便起)的文件。瀏覽器
import ( "github.com/graphql-go/graphql" "errors" )
定義good object服務器
type Goods struct { ID string `json:"id"` Name string `json:"name"` Price float64`json:"price"` Url string `json:"url"` } var goodsType = graphql.NewObject( graphql.ObjectConfig{ Name: "Goods", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.String, }, "name": &graphql.Field{ Type: graphql.String, }, "price": &graphql.Field{ Type: graphql.Float, }, "url": &graphql.Field{ Type: graphql.String, }, }, }, ) var goodsListType = graphql.NewList(goodsType)
注意:數組至關於新的object類型。
定義query object
var queryType = graphql.NewObject( graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ // 無需處理參數 "goodsList": &graphql.Field{ Type:goodsListType, // 處理結構體的回調函數,直接返回處理完成的結構體便可 Resolve: func(p graphql.ResolveParams) (interface{}, error) { return result, err }, }, // 參數是id "goods": &graphql.Field{ Type: goodsType, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ Type: graphql.String, }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { // 獲取參數 idQuery, isOK := p.Args["id"].(string) if isOK { return result, nil } err := errors.New("Field 'goods' is missing required arguments: id. ") return nil, err }, }, }, }, )
mutation定義基本相同,新建一個名爲mutation.go的文件:
定義input object
var goodsInputType = graphql.NewInputObject( graphql.InputObjectConfig{ Name: "goodsInput", Fields: graphql.InputObjectConfigFieldMap{ "name": &graphql.InputObjectFieldConfig{ Type: graphql.String, }, "price": &graphql.InputObjectFieldConfig{ Type: graphql.Float, }, "url": &graphql.InputObjectFieldConfig{ Type: graphql.String, }, }, }, )
定義 mutation object
var mutationType = graphql.NewObject( graphql.ObjectConfig{ Name: "Mutation", Fields: graphql.Fields{ "addGoods":&graphql.Field{ Type:goodsType, Args:graphql.FieldConfigArgument{ "input":&graphql.ArgumentConfig{ Type:goodsInputType, }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { input,isOk := p.Args["input"].(map[string]string) if !isOk{ err := errors.New("Field 'addGoods' is missing required arguments: input. ") return nil,err } result := Goods{ Name:input["name"].(string), Price:input["price"].(float64), Url:input["url"].(string), } // 處理數據 return result,err }, }, }, }, )
然而,input類型並不能直接轉換爲struct,而是一個map[string]interface{}類型,還須要進行手動轉換。
定義schema
var schema, _ = graphql.NewSchema( graphql.SchemaConfig{ Query: queryType, Mutation: mutationType, }, )
至此,咱們的所有的object定義完成。
graphql-go爲咱們提供了一個方便的接口,封裝好的handler能夠直接與go自帶的http包綁定。
package api import "github.com/graphql-go/handler" func Register() *handler.Handler { h := handler.New(&handler.Config{ Schema: &schema, Pretty: true, GraphiQL: true, }) return h }
func main() { h := api.Register() handler := cors.Default().Handler(h) http.Handle("/graphql", handler) fmt.Println("The api server will run on port : ", apiPort) http.ListenAndServe(apiPort, nil) }
打開瀏覽器,訪問http://localhost:apiPort/graphql, 查看你本身的GraphiQL界面吧!
若是你以爲這樣的代碼談不上優雅,甚至很是醜陋,那就對了。由於我也這樣以爲,看一看隔壁python的實現方式:
import graphene class Query(graphene.ObjectType): hello = graphene.String() def resolve_hello(self, args, context, info): return 'Hello world!' schema = graphene.Schema(query=Query)
有沒有涌來一口老血。
多是受限與golang自己反射系統並不夠完善,沒有python各類各樣的魔術方法,沒有泛型,或者說go自己不太適合編寫框架類的代碼。在編寫的過程當中,冗餘很是多,固然也多是框架自己的問題
不能否認的是,go確實是很是不錯的一門語言,雖然開發效率沒法與python媲美,可是在多併發環境下,go表現出很是出色,同時擁有與C級別的運行速度和豐富的生態。
go還年輕,其餘它愈來愈好!