编程语言编译器云原生语言运行时【免费下载链接】wingA programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚡项目地址https://gitcode.com/gh_mirrors/wi/wing点击查看免费下载导读本文以 Wing 开源仓库中options.test.w的 hangar 编译快照为主线完整剖析cloud.Api如何注册OPTIONS、HEAD、CONNECT三种 HTTP 方法路由并逐层解读其编译到tf-aws目标后生成的main.tf.jsonTerraform 配置从 OpenAPI 3.0.3 的 API Gateway 定义、每个方法对应的 Lambda 函数到 IAM 权限、CloudWatch 日志组与 S3 代码资产的完整资源拓扑。读完本文你将掌握在 Wing 中定义非常规 HTTP 方法路由的写法、其底层实现调用链以及如何通过 hangar 快照验证 SDK 行为。一、背景hangar 快照与测试用例1.1 hangar 快照是什么在 Wing 仓库中tools/hangar是负责批量编译与测试 SDK 用例的测试工具其运行结果以 Markdown 快照的形式沉淀在tools/hangar/__snapshots__/test_corpus/目录下。本文分析的对象是options.test.w_compile_tf-aws.md快照原文它记录了options.test.w编译到tf-aws目标后生成的完整main.tf.json其兄弟快照options.test.w_test_sim.mdsim 运行快照则记录了在本地模拟器sim 目标中运行该测试的 stdout 日志。这类快照的典型特征是Terraform 输出中的资产路径、资源哈希、ASSET_KEY等占位符会被归一化便于对比与审查例如 Lambda 函数的s3_key固定为ASSET_KEY。1.2 被测用例options.test.w快照头部的链接指向被测源文件 tests/sdk_tests/api/options.test.w其完整逻辑如下bring cloud; bring http; bring util; let api new cloud.Api(); let path /path; api.options(path, inflight (req: cloud.ApiRequest): cloud.ApiResponse { assert(req.method cloud.HttpMethod.OPTIONS); assert(req.path path); assert(req.body?.length 0); return cloud.ApiResponse { status: 204 }; }); api.head(path, inflight (req: cloud.ApiRequest): cloud.ApiResponse { assert(req.method cloud.HttpMethod.HEAD); assert(req.path path); assert(req.body?.length 0); return cloud.ApiResponse { status: 204 }; }); // CONNECT is a forbidden method in the fetch API and therefore could not be tested // https://fetch.spec.whatwg.org/#methods api.connect(path, inflight (req: cloud.ApiRequest): cloud.ApiResponse { return cloud.ApiResponse { status: 204 }; }); test http.fetch can preform a call to an api to CONNECT, HEAD and OPTIONS { let url api.url path; let options: http.Response http.fetch(url, method: http.HttpMethod.OPTIONS); let head: http.Response http.fetch(url, method: http.HttpMethod.HEAD); assert(options.status 204); assert(options.url url); }该用例验证了三件事路由注册api.options(path, handler)、api.head(path, handler)、api.connect(path, handler)三种方法在同一个路径/path上注册 inflight 处理器。请求语义OPTIONS与HEAD处理器断言req.method与req.path正确且请求体为空req.body?.length 0三者均返回status: 204No Content。端到端调用在test块内通过http.fetch以OPTIONS、HEAD方法发起真实 HTTP 请求断言响应状态码为 204、URL 与预期一致。值得注意的是代码注释CONNECT 是 fetch 规范中禁止的方法见 Fetch 规范 §Methods因此connect路由虽然注册了处理器但无法通过http.fetch做端到端断言——这正是它在测试块中被排除在外的原因也解释了快照中为何仍然能看到connect_path0的 Lambda 资源编译产物只关心路由是否存在不关心能否被 fetch 调用。二、Wing 侧的 API 设计options/head/connect方法族2.1 抽象基类中的方法定义在 SDK 抽象层 packages/winglang/sdk/src/cloud/api.ts 中cloud.Api是跨平台sim / tf-aws / 云厂商共用的抽象资源类。options、head、connect与get、post等一样是声明式的 preflight 方法签名统一为public options(path: string, inflight: IApiEndpointHandler, props?: ApiOptionsOptions): void public head(path: string, inflight: IApiEndpointHandler, props?: ApiHeadOptions): void public connect(path: string, inflight: IApiEndpointHandler, props?: ApiConnectOptions): void三者的参数类型均继承自ApiEndpointOptions即FunctionProps参见 api.ts 第 653-693 行意味着你可以像配置普通函数一样为每个端点传入内存、超时、环境变量等运行参数。同一文件还定义了HttpMethod枚举第 703-720 行包含GET、HEAD、POST、PUT、DELETE、CONNECT、OPTIONS、PATCH八种方法与options.test.w中cloud.HttpMethod.OPTIONS的引用一一对应。ApiRequest接口第 725-738 行method、path、query、vars、body?、headers?其中method即HttpMethod类型这是测试中assert(req.method cloud.HttpMethod.OPTIONS)的类型基础。ApiResponse接口第 745-762 行status?默认 200、body?、headers?测试返回的{ status: 204 }即该接口的实例。2.2 OpenAPI Spec 的生成机制Api基类内部维护一个apiSpecOpenAPI 3.0.3 格式每次注册路由都会调用_addToSpec(path, method, apiSpecExtension)第 567-629 行核心逻辑包括重复与冲突检测同一路径 方法重复注册会抛错路径参数:param形式与既有路径存在歧义或兄弟冲突时也会抛错。operationId 生成${method.toLowerCase()}${path 去掉斜杠}快照中options-path、head-path、connect-path即由此规则产生路径为/path首字符/被移除后拼接为-path。路径参数提取/:param形式的路径会转换为 OpenAPI 的parametersrenderOpenApiPath将其渲染为{param}形式。最终输出_getOpenApiSpec()返回{ openapi: 3.0.3, paths: {...} }这正是快照中aws_api_gateway_rest_api的body内容来源。三、编译产物逐资源拆解tf-aws 的 main.tf.json快照核心是一份完整的main.tf.json由 CDK for Terraformcdktf生成。下面按资源类型逐个解读并对照.w源码找到映射关系。3.1 API Gateway 三件套RestApi、Deployment、Stageaws_api_gateway_rest_apiApi_api_91C07D84是整个 API 的定义中心其body是一份内联的 OpenAPI 3.0.3 文档/path下注册了options、head、connect三个方法每个方法都有operationIdoptions-path/head-path/connect-pathresponses.200固定描述 200 response注意这是 OpenAPI 层的默认响应描述与处理器实际返回的 204 状态码是两层概念后者在运行时通过 Lambda 返回x-amazon-apigateway-integration扩展字段type: aws_proxy、httpMethod: POST、uri指向对应 Lambda 的 ARNarn:aws:apigateway:${region}:lambda:path/2015-03-31/functions/arn:aws:lambda:...:function:options_path0-c858e550/invocations、passthroughBehavior: when_no_match、contentHandling: CONVERT_TO_TEXT。路径/{proxy}配置了x-amazon-apigateway-any-method的mock 集成任何未匹配的请求都会返回 404响应体为{statusCode: 404, message: Error: Resource not found}并设置Content-Type: application/json响应头。这是 wing SDK 自动为所有 API 追加的兜底 404 路由保证未注册路径不会命中其它方法。aws_api_gateway_deploymentApi_api_deployment_7FB64CC4通过triggers.redeployment与 RestApi 的body摘要绑定${sha256(aws_api_gateway_rest_api.Api_api_91C07D84.body)}任何路由变更都会触发重新部署create_before_destroy生命周期保证发布过程无停机。aws_api_gateway_stageApi_api_stage_E0FA39D6的stage_name为prod与共享常量 shared-aws/api.ts 第 10 行STAGE_NAME prod对应。同时快照中的output.Api_Endpoint_Url_473FEE9F展示了最终访问地址的拼装模板https://${aws_api_gateway_rest_api.Api_api_91C07D84.id}.execute-api.${data.aws_region.Region.name}.amazonaws.com/${aws_api_gateway_stage.Api_api_stage_E0FA39D6.stage_name}即rest-api-id.execute-api.region.amazonaws.com/prod与测试中的api.url path一致。3.2 每个方法一个 Lambda三个 handler 的资源族options、head、connect三个路由各自生成一组完整的 Lambda 资源命名规律为{method}_path0-{hash}方法Lambda 函数名对应资源OPTIONSoptions_path0-c858e550Api_options_path0_AA6A3AADHEADhead_path0-c8127a73Api_head_path0_CD0BF570CONNECTconnect_path0-c88ada6cApi_connect_path0_9A10CD07函数名的前缀{method}_path0与 SDK 实现中addInflightHandler的命名规则\${method.toLowerCase()}${path.replace(///g, _)}见 [target-tf-aws/api.ts 第 227 行](https://link.gitcode.com/i/1dffab7bcf7772fda45dc1e1e2aa0057)完全吻合——/path去掉/后拼成path加上方法小写前缀。每颗 Lambda 的配置以 OPTIONS 为例runtime: nodejs20.x、architectures: [arm64]、handler: index.handlermemory_size: 1024、timeout: 60秒、publish: trueenvironment.variables注入NODE_OPTIONS--enable-source-maps、WING_FUNCTION_NAMEoptions_path0-c858e550、WING_TARGETtf-awslogging_config.log_format: JSON配合aws_cloudwatch_log_group按retention_in_days: 30留存日志日志组名遵循/aws/lambda/{函数名}约定代码存放在aws_s3_bucketCodebucket_prefix: code-c84a50b1-中通过aws_s3_objectkey: ASSET_KEY占位分发——这正是 wing 将编译后的 JS 资产上传 S3、再触发 Lambda 的经典部署链路。3.3 IAM 与调用权限最小权限原则每个 Lambda 配套生成三层 IAM 资源aws_iam_roleassume_role_policy只允许lambda.amazonaws.com服务代入STS AssumeRole三类角色分别以IamRole_879E3AD0、IamRole_8A76125C、IamRole_993D1A6D为唯一标识aws_iam_role_policy内联策略为{Effect:Allow,Action:none:null,Resource:*}——这是一个占位策略说明测试用例的 inflight 处理器没有显式声明任何需要授权的云资源操作aws_iam_role_policy_attachment附加托管策略arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole赋予 Lambda 写入 CloudWatch Logs 的基本执行权限。aws_lambda_permission则是 API Gateway 与 Lambda 之间的桥梁每个方法一条{ action: lambda:InvokeFunction, principal: apigateway.amazonaws.com, source_arn: ${aws_api_gateway_rest_api.Api_api_91C07D84.execution_arn}/*/OPTIONS/path, statement_id: AllowExecutionFromAPIGateway-OPTIONS-e2131352 }source_arn精确限定到/*/OPTIONS/path粒度——API Gateway 只能以对应 HTTP 方法调用对应 Lambda这正是三个 handler 各自成函数、权限互相隔离的体现。四、sim 目标本地验证与快照对照除了 tf-aws 编译快照同一用例还有一份 sim 运行快照 options.test.w_test_sim.mdpass ─ options.test.wsim » root/Default/test:http.fetch can preform a call to an api to CONNECT, HEAD and OPTIONS Tests 1 passed (1) Snapshots 1 skipped Test Files 1 passed (1) Duration DURATION它证明在本地模拟器中http.fetch以OPTIONS与HEAD方法访问/path返回 204 的断言全部通过Duration DURATION为快照归一化的时长占位符。也就是说options/head路由的语义在 sim 与 tf-aws 两个目标上保持一致。在 sim 实现中target-sim/api.ts 第 220-254 行options、head、connect均委托给addEndpoint(path, cloud.HttpMethod.OPTIONS/HEAD/CONNECT, inflight, props)通过toSimulator()将_getOpenApiSpec()与 CORS 头传入模拟器运行时——与 AWS 实现共用同一套 OpenAPI Spec 生成逻辑这是跨平台行为一致性的根本原因。五、从源码看实现链路一个路由如何变成云资源综合 target-tf-aws/api.ts 与 cloud/api.ts 的源码api.options(/path, handler)在tf-aws目标上的完整调用链为Api.options()→httpRequests(OPTIONS, /path, inflight, props)第 61-83 行_validatePath()校验路径合法性——只允许字母数字、-、_、.与:param形式addHandler()→addInflightHandler()将 inflight 处理器包装为cloud.FunctionLambda命名前缀为options_path并记录到handlers字典避免同一 inflight 重复创建this.api.addEndpoint(path, OPTIONS, fn)在WingRestApiAPI Gateway 抽象上登记端点_addToSpec(path, OPTIONS, endpointExt, corsOptions)把路由写入 OpenAPI Spec生成operationId: options-path等Node.addConnection()记录资源依赖图options()路由 → Lambda 的invoke编译收尾时WingRestApi将完整 Spec 序列化为aws_api_gateway_rest_api.body并连同 Deployment、Stage、Lambda、IAM、S3 等资源一起写入main.tf.json——即快照呈现的最终产物。CORS 与 OPTIONS 的关系值得注意cloud.Api通过props.cors/props.corsOptions支持全局 CORS 配置默认值见 cloud/api.ts 第 231-245 行renderCorsHeaders在 第 175-208 行。手动api.options()注册的 OPTIONS 路由与 CORS 自动生成的预检响应是两个独立机制前者是业务级路由本次快照展示的场景后者由 SDK 在响应头中注入Access-Control-*头二者互不干扰。六、实践要点与注意事项方法命名与路径约束options、head、connect与get/post/put/patch/delete一样路径需满足_validatePath的正则约束字母数字、-、_、.、:param路径参数必须以:开头否则编译期报错。重复/冲突注册会抛错同一路径下相同方法重复注册、或:param路径与其他路径存在歧义如/users/:id与/users/:name参数名不同但结构相同_addToSpec会在编译期抛出明确错误。CONNECT 的测试局限由于浏览器/Node 的 fetch API 禁止 CONNECT 方法api.connect()路由可以正常注册与部署但无法用http.fetch做端到端断言如需验证应使用底层的原生 HTTP 客户端或自定义协议。返回状态码语义OpenAPI Spec 中固定写responses.200只是 API 文档层的默认描述实际响应状态由 inflight 处理器返回的cloud.ApiResponse.status决定本用例为 204二者不要混淆。快照中的占位符ASSET_KEY、ASSET_SOURCE、DURATION是 hangar 归一化占位符实际部署时会替换为真实的 S3 资产键与运行耗时。七、相关文件索引被测用例tests/sdk_tests/api/options.test.w本文分析的主快照tools/hangar/snapshots/test_corpus/sdk_tests/api/options.test.w_compile_tf-aws.mdsim 运行快照tools/hangar/snapshots/test_corpus/sdk_tests/api/options.test.w_test_sim.mdAPI 抽象基类与 OpenAPI 生成packages/winglang/sdk/src/cloud/api.tstf-aws 目标实现packages/winglang/sdk/src/target-tf-aws/api.tssim 目标实现packages/winglang/sdk/src/target-sim/api.tsAWS 共享层STAGE_NAME、Lambda 包装packages/winglang/sdk/src/shared-aws/api.ts通过本文的逐资源拆解可以看到wing 的cloud.Api将“注册一个 HTTP 方法路由”这一简单声明自动扩展为 API Gateway 定义、Lambda 函数、IAM 权限、日志与代码资产的全套云基础设施——这正是 wing「统一编程模型」在 API 场景下的直接体现。赞分享编程语言编译器云原生语言运行时【免费下载链接】wingA programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚡项目地址https://gitcode.com/gh_mirrors/wi/wing点击查看免费下载相关推荐Wing 云原生 API 的 CORS 配置解析从 cloud.Api(cors: true) 到 tf-aws Terraform 编译产物Wing 云原生 API 的 CORS 配置解析从 cloud.Api cors: true 到 tf aws Terraform 编译产物 Wing 语言将编程语言编译器云原生语言运行时Wing 的 cloud.Api 在 tf-aws 目标下的编译产物深入解读 aws-api.test.w 的 Terraform 快照Wing 的 cloud.Api 在 tf aws 目标下的编译产物深入解读 aws api.test.w 的 Terraform 快照 Wing 语言把基础编程语言编译器云原生语言运行时Wing 语言 DELETE 接口实战从 cloud.Api 路由定义到 tf-aws 云端部署解析Wing 语言 DELETE 接口实战从 cloud.Api 路由定义到 tf aws 云端部署解析 导读 本文以 Wing 仓库中的 SDK 测试用例 de编程语言编译器云原生语言运行时上一篇Harbor 集成 LDAP 用户组管理项目组成员配置、测试用例与权限生效机制详解下一篇Langfuse Next.js 服务端安全实践像保护 API 路由一样认证 Server Actions 与服务端变更入口创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考