如何使用Node.js和CloudFormation在AWS Lambda中构建和部署GraphQL服务器

叶鹭洋
2023-12-01

介绍 (Introduction)

I have been building GraphQL APIs in a Serverless environment for over 3 years now. I can't even imagine working with RESTful APIs anymore. Combine the power of GraphQL with the scalability of AWS Lambda, and you have a server that can handle infinite amounts of traffic.

三年多来,我一直在无服务器环境中构建GraphQL API。 我什至无法想象再使用RESTful API。 将GraphQL的功能与AWS Lambda的可扩展性相结合,您便拥有了一台可以处理无限量流量的服务器。

In this tutorial, we will build and deploy a GraphQL server to AWS Lambda and access it via an API Gateway endpoint. We will use CloudFormation and the AWS CLI to deploy all our AWS Resources and application code.

在本教程中,我们将构建GraphQL服务器并将其部署到AWS Lambda并通过API Gateway终端节点对其进行访问。 我们将使用CloudFormation和AWS CLI部署所有我们的AWS资源和应用程序代码。

我们将介绍的内容 (What we'll cover)

  1. Build a GraphQL Server using Apollo

    使用Apollo构建GraphQL服务器
  2. Deploy that GraphQL Server to Lambda

    将该GraphQL服务器部署到Lambda
  3. Use API Gateway to proxy requests to Lambda

    使用API​​网关将请求代理到Lambda
  4. Use CloudFormation to deploy application stack to AWS

    使用CloudFormation将应用程序堆栈部署到AWS
  5. Set up Lambda for local development.

    设置Lambda以进行本地开发。

TL;DR – You can get the full source code for the application from Github.

TL; DR –您可以从Github获取该应用程序的完整源代码。

什么是GraphQL? (What is GraphQL?)

GraphQL is a query language for describing APIs using a strongly typed schema system. A GraphQL server fulfills those queries using existing data. Following are a few of the main advantages of using GraphQL.

GraphQL是用于使用强类型模式系统描述API的查询语言。 GraphQL服务器使用现有数据来完成那些查询。 以下是使用GraphQL的一些主要优点。

仅查询您的应用程序需要什么 (Query only what your application needs)

Unlike REST APIs, GraphQL enables clients to query precisely and only what they need. The server fulfills the client’s request by returning only what the client is asking for.

与REST API不同,GraphQL使客户端能够精确地查询并且仅查询其需要的内容。 服务器通过仅返回客户的要求来满足客户的请求。

GraphQL使用强类型系统 (GraphQL uses a strongly typed system)

The strongly typed system of GraphQL enables users to introspect the entire schema. And the GraphQL API serves as clear documentation about the capabilities of the server and notifies you about errors during development.

GraphQL的强类型系统使用户可以对整个架构进行内部检查。 GraphQL API可以作为有关服务器功能的清晰文档,并在开发过程中通知您有关错误的信息。

您可以在单个请求中组合查询 (You can compose your queries in a single request)

With GraphQL, you can query multiple resources and get combined responses with a single request. With fewer requests, apps using GraphQL perform much faster.

使用GraphQL,您可以查询多个资源并通过单个请求获得组合的响应。 使用更少的请求,使用GraphQL的应用程序可以更快地执行。

什么是AWS Lambda? (What is AWS Lambda?)

AWS Lambda is a compute service offered by AWS that lets you run your application code without having to manage any servers. AWS manages all the overhead like infrastructure, security, resources, operating system, and patches so developers can focus on just building the application.

AWS Lambda是AWS提供的计算服务,使您无需管理任何服务器即可运行应用程序代码。 AWS管理所有基础架构,安全性,资源,操作系统和补丁程序等开销,因此开发人员可以专注于仅构建应用程序。

Let’s get started…

让我们开始吧…

设置项目 (Setting up the project)

Let’s start by creating a project folder. Then, change into the directory and initialise a Node project. I am using node 10.x in the examples. You can install the Node version of your choice using asdf.

让我们开始创建一个项目文件夹。 然后,转到目录并初始化Node项目。 我在示例中使用的是node 10.x 您可以使用asdf安装所选的Node版本。

mkdir apollo-server-lambda-nodejs 
cd apollo-server-lambda-nodejs 
yarn init

Next, create a folder that houses all our source code.

接下来,创建一个包含我们所有源代码的文件夹。

mkdir src

Finally, create an index file inside the src directory that serves as the lambda handler.

最后,在src目录中创建一个索引文件,用作lambda处理程序。

cd src
touch index.js

Populate the index file with the following code.

用以下代码填充索引文件。

exports.handler = async () => {  
    return { 
        body: 'Hello from Lambda' 
    };
};

The above code is a very simple Lambda handler which will return Hello from Lambda when invoked. Let's first deploy our code to AWS Lambda.

上面的代码是一个非常简单的Lambda处理程序,将在调用时Hello from Lambda返回Hello from Lambda 。 首先,将代码部署到AWS Lambda。

打包应用程序代码 (Package the application code)

Before we can deploy our code to Lambda, we need to create a zip of our application and upload it to an S3 bucket. We are using AWS CLI to create the bucket. Set up AWS CLI now by following this guide if you have not already done so.

在将代码部署到Lambda之前,我们需要创建应用程序的zip并将其上传到S3存储桶。 我们正在使用AWS CLI创建存储桶。 如果尚未设置AWS CLI,请按照本指南进行设置。

Create an S3 bucket to use for deploying our code to Lambda. Pick a unique name for your S3 bucket. The bucket names are unique globally across all AWS Regions.

创建一个S3存储桶以用于将我们的代码部署到Lambda。 为您的S3存储桶选择一个唯一的名称。 存储桶名称在所有AWS区域中全局唯一。

aws s3 mb s3://lambda-deploy-asln

Create an archive of the application using the zip command and verify the files inside the zip.

使用zip命令创建应用程序的归档文件,并验证zip文件中的文件。

zip -rq dist-latest.zip src package.json 
zipinfo dist-latest.zip

Copy the zip file to S3 using the AWS CLI command.

使用AWS CLI命令将zip文件复制到S3。

aws s3 cp dist-latest.zip s3://lambda-deploy-asln/dist-latest.zip

Finally, use the following command to verify that the file exists in S3.

最后,使用以下命令来验证文件在S3中是否存在。

aws s3 ls s3://lambda-deploy-asln

Now that we have deployed the packaged application to S3, next we need to set up our Lambda and API Gateway in AWS. In the next section, we'll use CloudFormation to set up all necessary AWS Resources.

现在我们已将打包的应用程序部署到S3,接下来我们需要在AWS中设置Lambda和API网关。 在下一部分中,我们将使用CloudFormation设置所有必需的AWS资源。

使用API​​网关代理集成设置AWS Lambda (Set up AWS lambda with API gateway proxy integration)

CloudFormation is an AWS service that helps us to write infrastructure as code. CloudFormation makes it very simple to create and manage our application resources. Let’s use CloudFormation to define our stack.

CloudFormation是一项AWS服务,可帮助我们将基础架构编写为代码。 CloudFormation使创建和管理我们的应用程序资源变得非常简单。 让我们使用CloudFormation定义我们的堆栈。

Create a file named cloudformation.yml at the root of the project.

在项目的根目录下创建一个名为cloudformation.yml的文件。

touch cloudformation.yml

Add the following code to the cloudformation.yml

将以下代码添加到cloudformation.yml

---
Description: GraphQL server on AWS lambda

Parameters:
  Version:
    Description: Application version number
    Type: String

  BucketName:
    Description: S3 bucket name where the source code lives
    Type: String

Resources:
  LambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: !Ref BucketName
        S3Key: !Sub dist-${Version}.zip
      Handler: src/index.handler
      Description: GraphQL Apollo Server
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: nodejs10.x
      Timeout: 10

  LambdaExecutionRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Policies:
        - PolicyName: "LambdaFunctionPolicy"
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - logs:CreateLogGroup
              - logs:CreateLogStream
              - logs:PutLogEvents
              Resource: "*"

  GraphQLApi:
    Type: 'AWS::ApiGateway::RestApi'
    Properties:
      Name: apollo-graphql-api

  GraphQLApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      ParentId: !GetAtt GraphQLApi.RootResourceId
      RestApiId: !Ref GraphQLApi
      PathPart: 'graphql'

  GraphQLApiMethod:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      RestApiId: !Ref GraphQLApi
      ResourceId: !Ref GraphQLApiResource
      AuthorizationType: None
      HttpMethod: POST
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunction.Arn}/invocations

  GraphQLApiDeployment:
    Type: 'AWS::ApiGateway::Deployment'
    Properties:
      RestApiId: !Ref GraphQLApi
      StageName: v1
    DependsOn:
      - GraphQLApiResource
      - GraphQLApiMethod

  GraphQLApiPermission:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: lambda:invokeFunction
      FunctionName: !GetAtt LambdaFunction.Arn
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${GraphQLApi}/*

Outputs:
  ApiUrl:
    Description: Invoke url of API Gateway endpoint
    Value: !Sub https://${GraphQLApi}.execute-api.${AWS::Region}.amazonaws.com/v1/graphql

I know a lot is happening in this template. Let’s examine the code step by step.

我知道此模板中发生了很多事情。 让我们逐步检查代码。

模板参数 (Template Parameters)

Firstly, we define some parameters that we use in the template. We can pass those variables as parameter overrides when deploying the CloudFormation Stack.

首先,我们定义一些在模板中使用的参数。 部署CloudFormation堆栈时,我们可以将这些变量作为参数覆盖传递。

Description: GraphQL server on AWS lambda

Parameters:
  Version:
    Description: Application version number
    Type: String

  BucketName:
    Description: S3 bucket name where the source code lives
    Type: String

Lambda函数 (Lambda Function)

We define our lambda function specifying the path from where it should pull the application code. This bucket is the same one we created earlier.

我们定义了lambda函数,该函数指定应从中拉出应用程序代码的路径。 该存储桶与我们之前创建的存储桶相同。

LambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: !Ref BucketName
        S3Key: !Sub dist-${Version}.zip
      Handler: src/index.handler
      Description: GraphQL Apollo Server
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: nodejs10.x
      Timeout: 10

We want our Lambda function to be able to send application logs to AWS CloudWatch. Lambda requires special permissions to be able to write logs to CloudWatch. So we create a role that enables writing to CloudWatch and assign it to the Lambda function.

我们希望我们的Lambda函数能够将应用程序日志发送到AWS CloudWatch。 Lambda需要特殊权限才能将日志写入CloudWatch。 因此,我们创建了一个角色,该角色可以写入CloudWatch,并将其分配给Lambda函数。

LambdaExecutionRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Policies:
        - PolicyName: "LambdaFunctionPolicy"
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - logs:CreateLogGroup
              - logs:CreateLogStream
              - logs:PutLogEvents
              Resource: "*"

API网关 (API Gateway)

We also want an HTTP endpoint to invoke the lambda function. API Gateway can be used to create an HTTP endpoint. We can then configure API Gateway to proxy all incoming requests from the client to the Lambda function and send the response from Lambda back to the client.

我们还希望HTTP端点调用lambda函数。 API网关可用于创建HTTP端点。 然后,我们可以配置API Gateway,以将来自客户端的所有传入请求代理到Lambda函数,并将响应从Lambda发送回客户端。

Firstly, we create an API Gateway RestApi.

首先,我们创建一个API网关RestApi。

GraphQLApi:
    Type: 'AWS::ApiGateway::RestApi'
    Properties:
      Name: apollo-graphql-api

Then, we create an API Gateway Resource, which accepts requests at /graphql.

然后,我们创建一个API网关资源,该资源在/graphql处接受请求。

GraphQLApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      ParentId: !GetAtt GraphQLApi.RootResourceId
      RestApiId: !Ref GraphQLApi
      PathPart: 'graphql'

Next, we configure the Resource to accept POST requests by creating an API Gateway Method and then we integrate it with Lambda.

接下来,我们通过创建API网关方法将资源配置为接受POST请求,然后将其与Lambda集成。

GraphQLApiMethod:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      RestApiId: !Ref GraphQLApi
      ResourceId: !Ref GraphQLApiResource
      AuthorizationType: None
      HttpMethod: POST
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunction.Arn}/invocations

Finally, we create an API Gateway Deployment which deploys the API to the specified stage.

最后,我们创建一个API Gateway Deployment,将API部署到指定阶段。

GraphQLApiDeployment:
    Type: 'AWS::ApiGateway::Deployment'
    Properties:
      RestApiId: !Ref GraphQLApi
      StageName: v1
    DependsOn:
      - GraphQLApiResource
      - GraphQLApiMethod

Lambda / API网关权限 (Lambda / API Gateway permission)

At this point, we have both the Lambda function and API gateway configured correctly. However, API Gateway needs special permission to invoke a Lambda function. We permit API Gateway to invoke Lambda by creating a Lambda Permission resource.

至此,我们已经正确配置了Lambda函数和API网关。 但是,API网关需要特殊权限才能调用Lambda函数。 我们允许API网关通过创建Lambda权限资源来调用Lambda。

GraphQLApiPermission:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: lambda:invokeFunction
      FunctionName: !GetAtt LambdaFunction.Arn
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${GraphQLApi}/*

Finally, we export the API URL at the end of the template. We can use this URL to invoke calls to the Lambda.

最后,我们在模板末尾导出API URL。 我们可以使用此URL调用对Lambda的调用。

Outputs:
  ApiUrl:
    Description: Invoke url of API Gateway endpoint
    Value: !Sub https://${GraphQLApi}.execute-api.${AWS::Region}.amazonaws.com/v1/graphql

将CloudFormation堆栈部署到AWS (Deploy CloudFormation stack to AWS)

Now that we have the CloudFormation template ready let’s use the AWS CLI command to deploy it to AWS.

现在我们已经准备好了CloudFormation模板,让我们使用AWS CLI命令将其部署到AWS。

Run the following command in your console. Make sure to update the BucketName to whatever the name of the bucket you created earlier is.

在控制台中运行以下命令。 确保将BucketName更新为您之前创建的存储桶的名称。

aws cloudformation deploy \
  --template-file ./cloudformation.yml \
  --stack-name apollo-server-lambda-nodejs \
  --parameter-overrides BucketName=lambda-deploy-asln Version=latest \
  --capabilities CAPABILITY_IAM

It might take some time to deploy the stack. Lambda function should be ready to start taking requests when the deployment finishes.

部署堆栈可能需要一些时间。 部署完成后,Lambda函数应准备就绪,可以开始接收请求。

验证API网关和Lambda是否按预期工作 (Verify API Gateway and Lambda are working as expected)

Now that we have deployed our CloudFormation Stack let us verify if everything is working as expected. We need the API Gateway URL to send a request to our Lambda Function. The API URL we exported in the CloudFormation template comes in handy here.

现在我们已经部署了CloudFormation Stack,现在让我们验证一切是否按预期工作。 我们需要API网关URL才能向Lambda函数发送请求。 我们在CloudFormation模板中导出的API URL在这里很方便。

Run the following command to print the API URL in the command line.

运行以下命令以在命令行中打印API URL。

aws cloudformation describe-stacks \
--stack-name=apollo-server-lambda-nodejs \
--query "Stacks[0].Outputs[?OutputKey=='ApiUrl'].OutputValue" \
--output text

Now, use the curl command to invoke the API URL. You should get "Hello from Lambda" back from the server.

现在,使用curl命令调用API URL。 您应该从服务器返回“来自Lambda的Hello”。

curl -d '{}' https://o55ybz0sc5.execute-api.us-east-1.amazonaws.com/v1/graphql

添加部署脚本以简化部署 (Add deploy script for easier deployment)

You might have noticed that we ran a whole bunch of commands to package and deploy our application. It would be very tedious to have to run those commands every time we deploy the application. Let’s add a bash script to simplify this workflow.

您可能已经注意到,我们运行了一堆命令来打包和部署我们的应用程序。 每次部署应用程序时都必须运行这些命令将非常繁琐。 让我们添加一个bash脚本来简化此工作流程。

Create a directory called bin at the root of the application and add a file named deploy.

在应用程序的根目录下创建一个名为bin的目录,并添加一个名为deploy的文件。

mkdir bin 
touch bin/deploy

Before we can execute the script, we need to set correct file permissions. Let’s do that by running the following command.

在执行脚本之前,我们需要设置正确的文件权限。 让我们通过运行以下命令来做到这一点。

chmod +x bin/deploy

At this point, our directory structure should look like in the screenshot below.

此时,我们的目录结构应如下图所示。

Add the following code to the file.

将以下代码添加到文件中。

#!/bin/bash

set -euo pipefail

OUTPUT_DIR=dist
CURRENT_DIR=$(pwd)
ROOT_DIR="$( dirname "${BASH_SOURCE[0]}" )"/..
APP_VERSION=$(date +%s)
STACK_NAME=apollo-server-lambda-nodejs

cd $ROOT_DIR

echo "cleaning up old build.."
[ -d $OUTPUT_DIR ] && rm -rf $OUTPUT_DIR

mkdir dist

echo "zipping source code.."
zip -rq $OUTPUT_DIR/dist-$APP_VERSION.zip src node_modules package.json

echo "uploading source code to s3.."
aws s3 cp $OUTPUT_DIR/dist-$APP_VERSION.zip s3://$S3_BUCKET/dist-$APP_VERSION.zip

echo "deploying application.."
aws cloudformation deploy \
  --template-file $ROOT_DIR/cloudformation.yml \
  --stack-name $STACK_NAME \
  --parameter-overrides Version=$APP_VERSION BucketName=$S3_BUCKET \
  --capabilities CAPABILITY_IAM

# Get the api url from output of cloudformation stack
API_URL=$(
  aws cloudformation describe-stacks \
  --stack-name=$STACK_NAME \
  --query "Stacks[0].Outputs[?OutputKey=='ApiUrl'].OutputValue" \
  --output text
)

echo -e "\n$API_URL"

cd $CURRENT_DIR

OK, let’s break down what’s going on in this script.

好的,让我们分解一下此脚本中发生的事情。

We start by defining some variables. We generate the archive file inside the dist directory. We set the app version to the current timestamp at which the script runs. Using the timestamp, we can make sure that the version number is always unique and incremental.

我们首先定义一些变量。 我们在dist目录中生成存档文件。 我们将应用程序版本设置为脚本运行的当前时间戳。 使用时间戳,我们可以确保版本号始终是唯一的和递增的。

#!/bin/bash

set -euo pipefail

OUTPUT_DIR=dist
CURRENT_DIR=$(pwd)
ROOT_DIR="$( dirname "${BASH_SOURCE[0]}" )"/..
APP_VERSION=$(date +%s)
STACK_NAME=apollo-server-lambda-nodejs

We then clean up any old builds and create a new dist directory.

然后,我们清理所有旧版本,并创建一个新的dist目录。

echo "cleaning up old build.."
[ -d $OUTPUT_DIR ] && rm -rf $OUTPUT_DIR

mkdir dist

Then we run the zip command to archive the source code and its dependencies.

然后,我们运行zip命令来存档源代码及其依赖项。

echo "zipping source code.."
zip -rq $OUTPUT_DIR/dist-$APP_VERSION.zip src node_modules package.json

Next, we copy the zip file to the S3 bucket.

接下来,我们将zip文件复制到S3存储桶。

echo "uploading source code to s3.."
aws s3 cp $OUTPUT_DIR/dist-$APP_VERSION.zip s3://$S3_BUCKET/dist-$APP_VERSION.zip

Then we deploy the CloudFormation stack.

然后,我们部署CloudFormation堆栈。

echo "deploying application.."
aws cloudformation deploy \
  --template-file $ROOT_DIR/cloudformation.yml \
  --stack-name $STACK_NAME \
  --parameter-overrides Version=$APP_VERSION BucketName=$S3_BUCKET \
  --capabilities CAPABILITY_IAM

Finally, we query the CloudFormation Stack to get the API URL from the CloudFormation Outputs and print it in the console.

最后,我们查询CloudFormation堆栈以从CloudFormation输出获取API URL并将其打印在控制台中。

# Get the api url from output of cloudformation stack
API_URL=$(
  aws cloudformation describe-stacks \
  --stack-name=$STACK_NAME \
  --query "Stacks[0].Outputs[?OutputKey=='ApiUrl'].OutputValue" \
  --output text
)

echo -e "\n$API_URL"

使用部署脚本部署到AWS (Deploy to AWS using the deploy script)

Let’s try out the deployment using the deploy script. The script expects the S3_Bucket variable to be present in the environment. Run the following command to run the deployment. When the deployment is successful, the script will output the API URL that we can use to invoke the lambda.

让我们尝试使用deploy脚本进行部署。 该脚本希望环境中存在S3_Bucket变量。 运行以下命令以运行部署。 部署成功后,脚本将输出API URL,我们可以使用该URL来调用lambda。

S3_BUCKET=lambda-deploy-asln ./bin/deploy

To simplify this even further, let’s invoke it using yarn. Add the following in your package.json.

为了进一步简化,让我们使用yarn调用它。 在您的package.json添加以下内容。

"scripts": {
  "deploy": "S3_BUCKET=lambda-deploy-asln ./bin/deploy"
}

Hereafter we can simply run yarn deploy to initiate deployments.

此后,我们可以简单地运行yarn deploy来启动部署。

使用本地Lambda和API网关改善工作流程 (Improve workflow with local Lambda and API Gateway)

We frequently modified the application code while working on our application. Right now, deploying to AWS us-east-1 region takes me around 10 seconds. I am on a 40Mb/s upload speed internet connection.

在处理应用程序时,我们经常修改应用程序代码。 现在,部署到AWS us-east-1区域大约需要10秒钟。 我正在以40Mb / s的上传速度上网。

Time to deploy becomes more significant as the size of the application grows. Having to wait 10 seconds or more to realize I have made a syntax error is not productive at all.

随着应用程序大小的增长,部署时间变得越来越重要。 必须等待10秒钟或更长时间才能意识到我犯了语法错误,这根本无效。

Let’s fix this by setting up the lambda function locally and invoke it using a local API Endpoint. AWS SAM CLI enables us to do just that. Follow the instruction on this page to install it.

让我们通过在本地设置lambda函数并使用本地API端点调用它来解决此问题。 AWS SAM CLI使我们能够做到这一点。 请按照此页面上的说明进行安装。

Once done, from the root of the project, run the following command.

完成后,从项目的根目录运行以下命令。

sam local start-api --template-file cloudformation.yml

The local endpoint is now available at http://localhost:3000. We can use this endpoint to send requests to our local Lambda.

现在可以在http:// localhost:3000上找到本地端点 我们可以使用此端点将请求发送到本地Lambda。

Open another terminal and run the following command to send a request. You should see the response from our local Lambda function.

打开另一个终端,然后运行以下命令来发送请求。 您应该看到本地Lambda函数的响应。

curl -d '{}' http://localhost:3000/graphql

Finally, add the following lines in the scripts section of the package.json.

最后,在package.jsonscripts部分添加以下行。

"dev": "sam local start-api --template-file cloudformation.yml"

Hereafter we can run the yarn dev command to start the dev server.

此后,我们可以运行yarn dev命令启动dev服务器。

在Lambda中设置GraphQL服务器 (Set up the GraphQL server in Lambda)

Without further talking, let’s jump right into the code and build the GraphQL server.

无需进一步讨论,让我们直接进入代码并构建GraphQL服务器。

Start by installing the dependencies. We are using Apollo Server to build our GraphQL server. Apollo Server is an open-source implementation of GraphQL Server.

首先安装依赖项。 我们正在使用Apollo Server构建我们的GraphQL服务器。 Apollo Server是GraphQL Server的开源实现。

yarn add apollo-server-lambda graphql

Replace the content of src/index.js with the following code.

用以下代码替换src/index.js的内容。

const { ApolloServer, gql } = require('apollo-server-lambda');

const typeDefs = gql`
  type Query {
    user: User
  }

  type User {
    id: ID
    name: String
  }
`;

const resolvers = {
  Query: {
    user: () => ({ id: 123, name: 'John Doe' })
  }
};

const server = new ApolloServer({ typeDefs, resolvers });

exports.handler = server.createHandler();

Here, we define a schema which consists of a type User and a user query. We then define a resolver for the user query. For the sake of simplicity, the resolver returns a hardcoded user. Finally, we create a GraphQL handler and export it.

在这里,我们定义了一个由类型User和用户查询组成的架构。 然后,我们为用户查询定义一个解析器。 为了简单起见,解析器返回一个硬编码的用户。 最后,我们创建一个GraphQL处理程序并将其导出。

To perform queries to our GraphQL server, we need a GraphQL client. Insomnia is my favourite client. However, any other GraphQL client should be just fine.

要对我们的GraphQL服务器执行查询,我们需要一个GraphQL客户端。 失眠是我最喜欢的客户。 但是,任何其他GraphQL客户端都应该可以。

Now, let’s run a query to ensure our server is working as expected.

现在,让我们运行一个查询以确保我们的服务器按预期工作。

Create a new GraphQL request in Insomnia.

在Insomnia中创建一个新的GraphQL请求。

Add the following query in the body and submit the query to http://localhost:3000. Assuming your dev server is still running, you should see the following response from the GraphQL server.

在正文中添加以下查询,并将查询提交到http://localhost:3000 。 假设您的开发服务器仍在运行,您应该从GraphQL服务器看到以下响应。

Now that we've verified everything is working fine in the local server let’s run the following command to deploy the GraphQL server to AWS.

现在,我们已经验证了本地服务器上的一切工作正常,让我们运行以下命令将GraphQL服务器部署到AWS。

yarn deploy

The API URL is outputted in the console once the deployment is complete. Replace the URL in Insomnia with the one from API Gateway. Rerun the query to see it resolve.

部署完成后,API URL将在控制台中输出。 用API Gateway中的URL替换Insomnia中的URL。 重新运行查询以查看它可以解决。

摘要 (Summary)

Congratulations, you have successfully deployed a GraphQL Server in AWS Lambda purely using CloudFormation. The server can receive GraphQL requests from the client and return the response accordingly.

恭喜,您已完全使用CloudFormation在AWS Lambda中成功部署了GraphQL Server。 服务器可以从客户端接收GraphQL请求,并相应地返回响应。

We also set up the development environment for local development without adding many dependencies.

我们还为本地开发设置了开发环境,而没有添加很多依赖项。

If you liked this tutorial, please share it with your network.

如果您喜欢本教程,请与您的网络共享。

翻译自: https://www.freecodecamp.org/news/how-to-build-and-deploy-graphql-server-in-aws-lambda-using-nodejs-and-cloudformation/

 类似资料: