如何让共享Resolver模板识别调用它的AppSync API环境?
好问题!我之前在基于Serverless框架搭建多环境AppSync API的项目里,刚好碰到过一模一样的需求——不想让客户端额外传自定义头,又要让复用的Resolver知道当前运行的环境。这里有几个亲测有效的方案,你可以根据自己的场景选:
方案1:直接通过Serverless变量注入环境标识到Resolver模板
这是最简单直接的方法,利用Serverless框架的变量替换能力,在部署阶段就把当前环境(stage)写入到Resolver的请求/响应模板里,完全不需要客户端参与。
比如在你的serverless.yml中定义Resolver时,直接把${self:provider.stage}变量嵌入到模板内容里:
provider: name: aws stage: ${opt:stage, 'dev'} # 从命令行参数取stage,默认dev resolvers: Query.getResource: requestMappingTemplate: | { "version": "2017-02-28", "operation": "Invoke", "payload": { "currentEnv": "${self:provider.stage}", # 这里直接注入环境名 "input": $util.toJson($context.arguments) } } responseMappingTemplate: "$util.toJson($context.result)" dataSource: MyLambdaDataSource
部署时,Serverless会自动将${self:provider.stage}替换为实际的环境名(dev/stage/prod),Resolver在执行时就能通过$context.payload.currentEnv拿到当前环境标识,后续不管是在模板里做逻辑判断,还是传递给下游数据源都很方便。
方案2:给Lambda数据源注入环境变量
如果你的Resolver是基于Lambda数据源的,也可以把环境标识直接注入到Lambda函数的环境变量中,让业务逻辑层直接读取,这种方式更适合需要在代码里处理环境相关逻辑的场景。
在serverless.yml的函数配置里添加环境变量:
functions: resourceResolver: handler: src/resolvers/resource.handler environment: APP_ENV: ${self:provider.stage} # 注入当前环境
然后在Lambda函数代码里,直接读取环境变量:
exports.handler = async (event) => { const currentEnv = process.env.APP_ENV; // 根据环境做不同的业务逻辑处理 if (currentEnv === 'production') { // 生产环境逻辑 } else { // 开发/预发布环境逻辑 } return { /* 返回结果 */ }; };
这种方式下,Resolver本身不需要做额外处理,直接调用Lambda即可,Lambda会自动感知当前环境。
方案3:从AppSync API元数据中解析环境信息
如果你的AppSync API命名本身就包含环境标识(比如my-app-api-dev、my-app-api-prod),还可以通过Resolver的$context.apiId获取API ID,再通过AWS SDK调用AppSync的getGraphqlApi接口获取API名称,进而解析出环境。不过这个方案需要Resolver调用额外的Lambda来完成API信息查询,相对复杂一些,适合无法提前注入变量的场景。
举个简单的Lambda查询示例:
const { AppSyncClient, GetGraphqlApiCommand } = require("@aws-sdk/client-appsync"); const client = new AppSyncClient({ region: process.env.AWS_REGION }); exports.getEnvFromApiId = async (apiId) => { const command = new GetGraphqlApiCommand({ apiId }); const response = await client.send(command); const apiName = response.graphqlApi.name; // 假设API名称格式是xxx-{env},解析出环境 const env = apiName.split('-').pop(); return env; };
然后在Resolver的请求模板里调用这个Lambda,传入$context.apiId,就能拿到环境标识。
总结
如果只是需要在Resolver模板中快速获取环境,方案1是最优解;如果业务逻辑主要在Lambda中,方案2更合适;方案3属于兜底方案,适合无法提前注入变量的特殊场景。
内容的提问来源于stack exchange,提问作者Fook

