[英]Best approach to handle graphql for aws lambda?
我正在關注教程https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-lambda-resolvers.html
對於僅使用switch
來處理graphql查詢,還有一些疑問。
有沒有更好的方法來處理更復雜的請求?
由您決定如何在AppSync API中設置lambda。 每個解析器都具有lambda函數並由一個函數負責單個解析器是完全合理的。 您也可以采用類似於本教程的方法,並使用單個函數和一些輕量級路由代碼來照顧正確的函數。 由於lambda的容器預熱如何工作(尤其是Java和C#,VM啟動時間可能加起來),因此使用單個函數通常可以帶來一些性能上的好處,但關注點之間的分離卻較少。
這是我過去采用的一些方法:
選項1:JS
這種方法使用JavaScript,對於以前運行自己的GraphQL服務器的用戶應該感到熟悉。
const Resolvers = {
Query: {
me: (source, args, identity) => getLoggedInUser(args, identity)
},
Mutation: {
login: (source, args, identity) => loginUser(args, identity)
}
}
exports.handler = (event, context, callback) => {
// We are going to wire up the resolver to give all this information in this format.
const { TypeName, FieldName, Identity, Arguments, Source } = event
const typeResolver = Resolvers[TypeName]
if (!typeResolver) {
return callback(new Error(`No resolvers found for type: "${TypeName}"`))
}
const fieldResolver = typeResolver[FieldName]
if (!fieldResolver) {
return callback(new Error(`No resolvers found for field: "${FieldName}" on type: "${TypeName}"`), null)
}
// Handle promises as necessary.
const result = fieldResolver(Source, Arguments, Identity);
return callback(null, result)
};
然后,您可以使用AppSync中的標准lambda解析器。 現在,我們必須手動提供TypeName和FieldName。
#**
The value of 'payload' after the template has been evaluated
will be passed as the event to AWS Lambda.
*#
{
"version" : "2017-02-28",
"operation": "Invoke",
"payload": {
"TypeName": "Query",
"FieldName": "me",
"Arguments": $util.toJson($context.arguments),
"Identity": $util.toJson($context.identity),
"Source": $util.toJson($context.source)
}
}
選項2:執行
出於好奇,我還通過AppSync成功使用了go lambda函數。 這是一種對我有效的方法。
package main
import (
"context"
"fmt"
"github.com/aws/aws-lambda-go/lambda"
"github.com/fatih/structs"
"github.com/mitchellh/mapstructure"
)
type GraphQLPayload struct {
TypeName string `json:"TypeName"`
FieldName string `json:"FieldName"`
Arguments map[string]interface{} `json:"Arguments"`
Source map[string]interface{} `json:"Source"`
Identity map[string]interface{} `json:"Identity"`
}
type ResolverFunction func(source, args, identity map[string]interface{}) (data map[string]interface{}, err error)
type TypeResolverMap = map[string]ResolverFunction
type SchemaResolverMap = map[string]TypeResolverMap
func resolverMap() SchemaResolverMap {
return map[string]TypeResolverMap{
"Query": map[string]ResolverFunction{
"me": getLoggedInUser,
},
}
}
func Handler(ctx context.Context, event GraphQLPayload) (map[string]interface{}, error) {
// Almost the same as the JS option.
resolvers := resolverMap()
typeResolver := resolvers[event.TypeName]
if typeResolver == nil {
return nil, fmt.Errorf("No type resolver for type " + event.TypeName)
}
fieldResolver := typeResolver[event.FieldName]
if fieldResolver == nil {
return nil, fmt.Errorf("No field resolver for field " + event.FieldName)
}
return fieldResolver(event.Source, event.Arguments, event.Identity)
}
func main() {
lambda.Start(Handler)
}
/**
* Resolver Functions
*/
/**
* Get the logged in user
*/
func getLoggedInUser(source, args, identity map[string]interface{}) (data map[string]interface{}, err error) {
// Decode the map[string]interface{} into a struct I defined
var typedArgs myModelPackage.GetLoggedInUserArgs
err = mapstructure.Decode(args, &typedArgs)
if err != nil {
return nil, err
}
// ... do work
res, err := auth.GetLoggedInUser()
if err != nil {
return nil, err
}
// Map the struct back to a map[string]interface{}
return structs.Map(out), nil
}
// ... Add as many more as needed
然后,您可以使用與選項1中使用的相同的解析器模板。還有許多其他方法可以執行此操作,但這是一種對我有效的方法。
希望這可以幫助 :)
您沒有被迫使用單個AWS Lambda來處理每個請求。 對於本教程,新手更容易理解它,因此他們使用了這種方法。
但是最終由您自己決定如何實施。 一種替代方法是為每個解析器創建一個單獨的AWS Lambda,以消除該switch
並遵循單一職責原則(SRP) 。
您可以將所有查詢代理到graphql服務器
Apollo GraphQL Server提供了一個非常好的設置,可以在AWS Lambda中部署GraphQL服務器。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.