为AWS Lambda处理graphql的最佳方法?

时间:2018-07-17 12:35:50

标签: amazon-web-services aws-lambda graphql aws-appsync

我正在关注教程https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-lambda-resolvers.html

对于仅使用switch处理graphql查询有一些疑问。

是否有更好的方法来处理更复杂的请求?

4 个答案:

答案 0 :(得分:3)

由您决定如何在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中使用的相同的解析器模板。还有许多其他方法可以执行此操作,但这是一种对我有效的方法。

希望这会有所帮助:)

答案 1 :(得分:2)

您不会被迫使用单个AWS Lambda来处理每个请求。对于本教程,新手更容易理解它,因此他们使用了这种方法。

但是最终由您自己决定如何实现它。一种替代方法是为每个解析器创建一个单独的AWS Lambda,以消除switch并遵循Single Responsibility Principle (SRP)

答案 2 :(得分:0)

您可以将所有查询代理到graphql-server

答案 3 :(得分:0)

Apollo GraphQL Server提供了一个很好的设置,可以在AWS Lambda中部署GraphQL服务器。