GraphQL提供了一种灵活而有效的方式来查询服务器中的数据。 它正在成为设计后端的流行技术,通常会替换或封装一些不灵活的REST API,并让客户负责决定他们需要的数据。 现在有许多用于编写JavaScript的GraphQL客户端和服务器的库和框架,其中最着名的是Apollo和Graphcool 。 Apollo团队还开发了针对WebSockets的GraphQL协议,该协议主要用于Apollo Client和Graphcool中的Subscriptions。
1.介绍graphqlws今天,我们开放了一个新的Go库来填补这个空白: graphqlw。 它有一个简单的目的:
- 实现GraphQL在WebSocket(由所有流行的GraphQL客户端使用),所以不必考虑与net/http无缝集成
- 与net/http无缝集成
- 提供访问已建立订阅的简单方法,执行身份验证并向相应的客户端发送更新。 你可以在https://github.com/functionalfoundry/graphqlws上的GitHub上找到它。
第1步 - 基本设置
authToken
package main
import (
"net/http"
"github.com/functionalfoundry/graphqlws"
"github.com/graphql-go/graphql"
)
func main() {
// Create a GraphQL schema with a subscription object
schema, err := graphql.NewSchema(graphql.SchemaConfig{
Subscription: graphql.NewObject(...),
})
// Create a subscription manager
subscriptionManager := graphqlws.NewSubscriptionManager(&schema)
// Create a WebSocket/HTTP handler
graphqlwsHandler := graphqlws.NewHandler(graphqlws.HandlerConfig{
// Wire up the GraphqL WebSocket handler with the subscription manager
SubscriptionManager: subscriptionManager,
// Optional: Add a hook to resolve auth tokens into users that are
// then stored on the GraphQL WS connections
Authenticate: func(authToken string) (interface{}, error) {
// This is just a dumb example
return "Joe", nil
},
})
// The handler integrates seamlessly with existing HTTP servers
http.Handle("/subscriptions", graphqlwsHandler)
http.ListenAndServe(":8080", nil)
}
第2步 - 使用 Subscriptions
Graphqlws库本身仅仅实现了基于WebSocket协议的GraphQL。 它没有实现任何开箱即用的订阅。 一个典型的服务器实现将监听数据库的变化,并通过识别哪些订阅需要更新,重新执行这些订阅的查询并将结果发送给相应的订阅客户端来对这些更改做出反应。
以下代码示例显示了订阅管理器在任何时候如何检索订阅。 他们按照他们的关系分组。 每个连接都有唯一的ID,可选地,还有前面描述的Authenticate函数返回的用户。
QueryVariablesOperationNameFieldsDocument
QueryVariablesOperationNameSendData
// This assumes you have access to the above subscription manager
subscription := subscriptionManager.Subscriptions()
for _, conn := range subscriptions {
// Things you have access to here:
conn.ID() // The connection ID
conn.User() // The user returned from the subscription manager's Authenticate
for _, subscription := range subscriptions[conn] {
// Things you have access to here:
subscription.ID // The subscription ID (unique per conn)
subscription.OperationName // The name of the subcription
subscription.Query // The subscription query/queries string
subscription.Variables // The subscription variables
subscription.Document // The GraphQL AST for the subscription
subscription.Fields // The names of top-level queries
subscription.Connection // The GraphQL WS connection
// Prepare an execution context for running the query
ctx := context.Context()
// Re-execute the subscription query
params := graphql.Params{
Schema: schema, // The GraphQL schema
RequestString: subscription.Query,
VariableValues: subscription.Variables,
OperationName: subscription.OperationName,
Context: ctx,
}
result := graphql.Do(params)
// Send query results back to the subscriber at any point
data := graphqlws.DataMessagePayload{
// Data can be anything (interface{})
Data: result.Data,
// Errors is optional ([]error)
Errors: graphqlws.ErrorsFromGraphQLErrors(result.Errors),
}
subscription.SendData(&data)
}
}
第3步 - 与graphql-go / handler结合使用
net/http
package main
import (
"net/http"
"github.com/functionalfoundry/graphqlws"
"github.com/graphql-go/graphql"
"github.com/graphql-go/handler"
)
func main() {
// Create a GraphQL schema with a subscription object
schema, err := graphql.NewSchema(graphql.SchemaConfig{
Subscription: graphql.NewObject(...),
})
// Create a GraphQL over WebSocket handler
subscriptionManager := graphqlws.NewSubscriptionManager(&schema)
graphqlwsHandler := graphqlws.NewHandler(graphqlws.HandlerConfig{
SubscriptionManager: subscriptionManager,
})
// Create a GraphQL over HTTP handler
graphqlHandler := handler.New(&handler.Config{
Schema: &schema,
Pretty: true,
GraphiQL: true,
})
// Serve both handlers on different endpoints
http.Handle("/", graphqlHandler)
http.Handle("/subscriptions", graphqlwsHandler)
http.ListenAndServe(":8080", nil)
}
概要
graphqlws
在GitHub上提交 bug 或 issue 。
如果您正在寻找下一个项目的React或GraphQL开发方面的帮助,我们很乐意在Functional Foundry处听到您的消息。