在Lambda中使用Apollo GraphQL是否必须依赖AppSync?能否通过API Gateway+Terraform实现?
Great question! Let's break this down into two key parts to address your concerns:
一、是否必须使用AppSync?
完全不需要。AppSync是AWS托管的GraphQL服务,它确实简化了实时订阅、数据源集成、认证等开箱即用的功能,但它并不是在Lambda上运行Apollo Server的必要条件。
Apollo Server是一个独立的GraphQL实现,可以直接部署在Lambda上,而API Gateway完全可以作为前端入口点。因为GraphQL主要通过单一HTTP端点(通常是POST请求处理查询/变更)工作,API Gateway能够毫无压力地将这类流量路由到你的Lambda函数。你可以完全掌控自己的GraphQL层,无需绑定到AppSync的预设工作流。
二、如何通过API Gateway + Terraform配置Lambda上的Apollo Server
这完全可行,而且你可以全程用Terraform管理基础设施。以下是分步指南:
1. 编写Apollo Server的Lambda代码
首先使用apollo-server-lambda包将Apollo Server适配为Lambda可执行的格式,这里是一个极简示例:
const { ApolloServer, gql } = require('apollo-server-lambda'); // 定义GraphQL Schema const typeDefs = gql` type Query { hello: String! } `; // 定义Resolver逻辑 const resolvers = { Query: { hello: () => 'Hello from Apollo Server running on Lambda!', }, }; // 初始化适配Lambda的Apollo Server实例 const server = new ApolloServer({ typeDefs, resolvers, // 开启调试用的Schema自省和Playground(生产环境建议关闭) introspection: true, playground: true, }); // 导出Lambda处理函数 exports.handler = server.createHandler({ cors: { origin: '*', // 生产环境请限制为你的前端域名 credentials: true, }, });
createHandler()方法会将Apollo Server包装成Lambda可处理的格式,自动解析HTTP请求体中的GraphQL查询内容。
2. 用Terraform配置基础设施
接下来定义Lambda函数、API Gateway以及它们的集成,拆分为几个逻辑模块:
2.1 Lambda函数与IAM角色
首先定义Lambda执行角色(包含基础权限)和Lambda函数:
# Lambda执行角色 resource "aws_iam_role" "apollo_lambda_exec_role" { name = "apollo-graphql-lambda-exec-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "lambda.amazonaws.com" } } ] }) } # 附加基础Lambda执行权限 resource "aws_iam_role_policy_attachment" "lambda_basic_execution" { role = aws_iam_role.apollo_lambda_exec_role.name policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" } # Lambda函数(指向你的代码压缩包) resource "aws_lambda_function" "apollo_graphql" { filename = "apollo-lambda-code.zip" # 本地代码压缩包路径 function_name = "apollo-graphql-handler" role = aws_iam_role.apollo_lambda_exec_role.arn handler = "index.handler" # 与代码中导出的函数名对应 runtime = "nodejs18.x" # 根据你的Node.js版本调整 # 如果代码存储在S3,替换filename为以下配置: # s3_bucket = "your-code-storage-bucket" # s3_key = "apollo-lambda-code.zip" }
2.2 API Gateway配置
创建REST API,添加/graphql端点,并通过Lambda代理集成将其与Lambda函数关联(这种集成方式让API Gateway直接转发完整的HTTP请求/响应到Lambda,无需手动配置映射模板):
# API Gateway REST API实例 resource "aws_api_gateway_rest_api" "apollo_graphql_api" { name = "ApolloGraphQL-API" description = "API Gateway for Apollo Server on Lambda" } # /graphql资源节点 resource "aws_api_gateway_resource" "graphql_endpoint" { rest_api_id = aws_api_gateway_rest_api.apollo_graphql_api.id parent_id = aws_api_gateway_rest_api.apollo_graphql_api.root_resource_id path_part = "graphql" } # POST方法(处理GraphQL查询/变更) resource "aws_api_gateway_method" "graphql_post" { rest_api_id = aws_api_gateway_rest_api.apollo_graphql_api.id resource_id = aws_api_gateway_resource.graphql_endpoint.id http_method = "POST" authorization = "NONE" # 生产环境请替换为IAM/Cognito等认证方式 request_parameters = { "method.request.header.Content-Type" = true } } # 将POST方法与Lambda集成 resource "aws_api_gateway_integration" "lambda_post_integration" { rest_api_id = aws_api_gateway_rest_api.apollo_graphql_api.id resource_id = aws_api_gateway_resource.graphql_endpoint.id http_method = aws_api_gateway_method.graphql_post.http_method integration_http_method = "POST" # Lambda集成必须使用POST type = "AWS_PROXY" uri = aws_lambda_function.apollo_graphql.invoke_arn } # 可选:GET方法(用于Apollo Playground和Schema自省) resource "aws_api_gateway_method" "graphql_get" { rest_api_id = aws_api_gateway_rest_api.apollo_graphql_api.id resource_id = aws_api_gateway_resource.graphql_endpoint.id http_method = "GET" authorization = "NONE" } resource "aws_api_gateway_integration" "lambda_get_integration" { rest_api_id = aws_api_gateway_rest_api.apollo_graphql_api.id resource_id = aws_api_gateway_resource.graphql_endpoint.id http_method = aws_api_gateway_method.graphql_get.http_method integration_http_method = "POST" type = "AWS_PROXY" uri = aws_lambda_function.apollo_graphql.invoke_arn } # 将API部署到生产阶段 resource "aws_api_gateway_deployment" "apollo_prod_deployment" { depends_on = [ aws_api_gateway_integration.lambda_post_integration, aws_api_gateway_integration.lambda_get_integration # 如果配置了GET方法则包含 ] rest_api_id = aws_api_gateway_rest_api.apollo_graphql_api.id stage_name = "prod" } # 允许API Gateway调用Lambda函数 resource "aws_lambda_permission" "api_gateway_invoke" { statement_id = "AllowAPIGatewayInvoke" action = "lambda:InvokeFunction" function_name = aws_lambda_function.apollo_graphql.function_name principal = "apigateway.amazonaws.com" source_arn = "${aws_api_gateway_rest_api.apollo_graphql_api.execution_arn}/*/*/graphql" }
3. 生产环境注意事项
- CORS配置:生产环境请将Apollo Server的CORS
origin限制为你的前端域名,避免使用*。 - 认证:将
authorization = "NONE"替换为你偏好的认证方式(IAM、Cognito用户池、API密钥等),确保GraphQL端点的安全性。 - 调试功能:生产环境建议关闭
playground和introspection,减少攻击面。 - Lambda层:如果多个Lambda函数共享依赖,可以将
apollo-server-lambda打包到Lambda层中,减小代码包体积。
总结
你完全不需要依赖AppSync就能在Lambda上运行Apollo Server——API Gateway是一个完全合格的入口点,而且你可以全程用Terraform管理基础设施,无需引入Serverless Framework。核心模式就是通过代理集成,将API Gateway的/graphql端点路由到运行Apollo的Lambda函数,这种方式简单且易于维护。
内容的提问来源于stack exchange,提问作者Joey Yi Zhao

