编程语言编译器云原生语言运行时【免费下载链接】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点击查看免费下载cloud.Api是 Wing 标准库winglang/sdk中用于创建可由互联网客户端调用的一组 HTTP 端点的内置资源是应用对外暴露数据、业务逻辑与后端能力的前门。本文以 Wing 仓库中 api.md 文档为核心结合 cloud/api.ts 的抽象实现、模拟器与 AWS 各平台的落地代码及 API 测试集系统讲解路由建模、请求/响应类型、路径参数与校验规则、CORS 配置以及sim/tf-aws/awscdk各目标平台上的底层实现原理帮助读者完整掌握用 Wing 编写可移植 REST API 的方法。一、cloud.Api是什么路由与事件处理函数的建模在 Wing 中cloud.Api将“一个 HTTP 服务”抽象为一组**路由routes**的集合每条路由由两部分构成路径path例如/users/:userid支持以:前缀声明路径参数HTTP 方法集合例如GET、POST、DELETE等。当客户端调用某条路由时对应的事件处理函数event handler——即你为该路由注册的inflight函数——会被执行并返回响应。也就是说Api把“定义接口”和“实现接口”统一在同一个语言模型里注册路由是 preflight 阶段的行为而处理请求的业务逻辑是 inflight 阶段的行为两者天然同构无需在基础设施代码与业务代码之间切换。从抽象基类 cloud/api.ts 可以看到cloud.Api继承了Resource其构造函数接受可选的ApiProps并负责维护一份内部 OpenAPI specopenapi: 3.0.3每注册一条路由就向这份 spec 写入一个 method 条目。url属性则通过抽象的_endpoint一个cloud.Endpoint资源暴露 API 的基地址供 inflight 代码引用例如拼装{api.url}/employees进行调用。二、快速上手一个完整的 REST API员工管理原文档给出的示例组合了cloud.Api、cloud.Bucket存储员工数据与cloud.Counter生成唯一 id完整覆盖了GET、POST、PUT、DELETE四种常用操作是一个可以直接复制运行的 CRUD 样板bring cloud; let api new cloud.Api(); // Used for generating unique id let counter new cloud.Counter(); // our employee data let store new cloud.Bucket(); api.get(/employees, inflight (request: cloud.ApiRequest): cloud.ApiResponse { let result MutJson []; let var i 0; for employee in store.list() { result.setAt(i, employee); i i 1; } return cloud.ApiResponse { status: 200, body: Json.stringify(result) }; }); api.get(/employees/:id, inflight (request: cloud.ApiRequest): cloud.ApiResponse { let employee store.get(request.vars.get(id)); return cloud.ApiResponse { status: 200, body: Json.stringify(employee) }; }); api.post(/employees, inflight (request: cloud.ApiRequest): cloud.ApiResponse { if let body request.body { let employeeData Json.parse(body); let id {counter.inc()}; store.putJson(id, employeeData); return cloud.ApiResponse { status: 201, body: id }; } }); api.put(/employees/:id, inflight (request: cloud.ApiRequest): cloud.ApiResponse { if let body request.body { let employeeData Json.parse(body); let id request.vars.get(id); store.putJson(id, employeeData); return cloud.ApiResponse { status: 200, body: Json.stringify(employeeData) }; } }); api.delete(/employees/:id, inflight (request: cloud.ApiRequest): cloud.ApiResponse { let id request.vars.get(id); store.delete(id); return cloud.ApiResponse { status: 204 }; });这段示例体现了几个要点request.vars用于读取路径参数/employees/:id中的idrequest.body是可选字符串if let解包后交给Json.parse解析为 JSONcloud.ApiResponse显式声明状态码与响应体201表示创建成功、204表示无内容删除成功{counter.inc()}使用字符串插值把 Counter 的自增结果转成字符串作为对象 keystore.list()/store.get()/store.putJson()/store.delete()展示了 Api 与 Bucket 的协同所有存储操作都在 inflight 内完成。原文档还指出该资源是 REST 场景下的默认选择仓库文档 docs/by-example/34-http-server.md 给出了另一个更贴近日常的“笔记 API”示例GET/note?name...读 Bucket、PUT/note/:name写 Bucket并演示了隐式返回的写法——当 handler 不显式构造ApiResponse时默认返回status: 200。三、核心 API 形状ApiRequest / ApiResponse / HttpMethod要写出规范的 handler必须先理解两个核心数据结构的完整字段定义见 cloud/api.tsApiRequest请求字段类型说明methodHttpMethod请求的 HTTP 方法pathstring请求的路径queryMapstring, string查询字符串键值varsMapstring, string路径变量路径参数bodystring可选请求体headersMapstring, string可选请求头注意query与vars都返回Map读取时使用request.query.get(name)、request.vars.get(id)这样的.get()调用测试 get.test.w 中还演示了req.body?.length 0这种对可选体的安全访问。ApiResponse响应字段类型默认值说明statusnumber200响应状态码bodystring无 body响应体headersMapstring, string{}响应头DEFAULT_RESPONSE_STATUS 200常量定义于 cloud/api.ts。测试 get.test.w 专门验证了两种省略写法handler 完全不返回值时得到“200 且空 body”只返回{ body: ok }时自动补全status: 200。HttpMethod枚举支持的方法共有 8 种cloud/api.tsGET、HEAD、POST、PUT、DELETE、CONNECT、OPTIONS、PATCH。对应地Api基类提供了get、post、put、delete、patch、options、head、connect共 8 个 preflight 注册方法每个方法签名统一为(path, inflight, props?)。辅助函数parseHttpMethod负责把字符串解析为枚举遇到不支持的方法会抛出Unsupported HTTP method错误。四、路径参数、路径校验与冲突检测cloud.Api对路径做了严格的 preflight 校验与冲突检测这些逻辑全部实现在抽象基类 cloud/api.ts 中无论部署到哪个平台都会执行1. 路径合法性校验_validatePath路径被正则严格约束普通 URL 片段只能包含字母、数字、-、_和.:前缀的参数名只能包含字母、数字和_。非法路径会在注册时直接抛出错误Invalid path ... Url parts can only contain alpha-numeric chars, -, _ and .. Params can only contain alpha-numeric chars and _.2. 重复注册检测_addToSpec同一路径 同一方法重复注册会报错Endpoint for path ... and method ... already exists。3. 歧义路径检测_arePathsAmbiguous/_findAmbiguousPath若两条路径结构相同但参数名不同如/users/:id与/users/:name会被判定为歧义并拒绝注册。4. 兄弟路径冲突检测_arePathsSiblings/_findSiblingPath若两条路径共享同一段参数位置但使用了不同参数名如先注册/users/:id再注册/users/:name/sub会抛出“sibling endpoint”冲突错误提示统一参数命名来避免歧义。测试 root_path_vars.test.w 用try/catch精确断言了这些错误消息文本例如Endpoint for path /:username/something and method GET conflicts with existing sibling endpoint for path /:id- try to match the parameter names to avoid this error.路径参数在最终生成的 OpenAPI spec 中会被转换成标准的{}语法/users/:id→/users/{id}这是通过静态方法renderOpenApiPath的正则替换完成的。五、CORS 配置从默认值到自定义策略cloud.Api在构造时通过ApiProps支持全局 CORS 配置cloud/api.tscorsboolean默认false开启后即为所有路由添加 CORS 响应头corsOptionsApiCorsOptions对默认 CORS 行为进行细粒度定制。ApiCorsOptions的全部字段如下源码注释中给出了完整默认值字段类型默认值allowOriginstring*allowMethodsArrayHttpMethodGET, POST, PUT, PATCH, DELETE, HEAD, OPTIONSallowHeadersArraystring[Content-Type, Authorization, X-Requested-With]构造函数默认值exposeHeadersArraystring[]allowCredentialsbooleanfalsemaxAgeDuration5 分钟Duration.fromMinutes(5)开启方式非常简洁// 开启 CORS使用默认策略 let api new cloud.Api(cors: true); // 自定义来源 let api new cloud.Api(cors: true, corsOptions: { allowOrigin: https://example.com, });Api.renderCorsHeaders会根据这些选项生成两类响应头集合cloud/api.tsdefaultResponse普通请求的响应头包括Access-Control-Allow-Origin、Access-Control-Expose-Headers、Access-Control-Allow-CredentialsoptionsResponse预检preflight请求的响应头包括Access-Control-Allow-Origin、Access-Control-Allow-Headers、Access-Control-Allow-Methods、Access-Control-Max-Age。测试 cors.test.w 验证了开启cors: true后http.get响应中会携带access-control-allow-origin: *头。开启 CORS 后生成的 OpenAPI spec 中也会为每个路径的200响应声明这些响应头_corsOpenApiSchema。六、各目标平台target的实现细节原文档按编译目标列出了cloud.Api的落地差异这里是仓库源码确认的完整实现事实Simulatorsim——基于 Node.js Express模拟器实现位于 target-sim/api.ts 与 target-sim/api.inflight.ts其核心事实包括每个注册的 handler 会被包装成一个cloud.Function“OnRequestHandler”再通过EventMapping把“API 请求事件”订阅到该函数上inflight 运行时启动一个Express服务器通过appmethod挂载路由并用asyncMiddleware包装异步 handlerExpress v4 本身不原生支持 async handler请求体会以纯文本解析并限制为10MB以对齐 AWS API Gateway 的负载上限源码注释明确引用了 AWS 官方限制文档transformRequest会把 Express 的req转成ApiRequestreq.params→vars、req.query→query、req.headers→headers多值参数会被sanitizeParamLikeObject用逗号连接合并服务器启动时会优先复用状态文件state.json中记录的上一次端口init→isPortAvailable→listenExpress关闭时通过cleanup释放端口启用 CORS 时中间件会对OPTIONS请求直接返回204并写入 optionsResponse 头其余请求写入 defaultResponse 头。AWStf-aws/awscdk——基于 Amazon API GatewayAWS 的实现分为两层公共层 shared-aws/api.ts 定义了IAwsApi接口restApiArn、restApiId、restApiName、stageName、invokeUrl、deploymentId并提供了Api.from()辅助方法让你在 preflight 中把任意cloud.Api提升为 AWS 专属视图测试 aws-api.test.w 演示了用aws.Api.from(a)读取这些属性的用法。tf-aws实现target-tf-aws/api.ts的落地事实通过 CDK for Terraform 创建ApiGatewayRestApiApiGatewayDeploymentApiGatewayStage三件套stage 名固定为prodSTAGE_NAME定义于 shared-aws/api.tsAPI 的 OpenAPI 定义通过Lazy延迟生成因为路由可能在 API 创建之后才注册并合并一个/{proxy}兜底路由开启 CORS 时对OPTIONS返回 204、其余方法返回 404未开启时统一返回 mock 404——这正是 404.test.w 断言“访问未定义路由得到 404 且 body 包含 Error”的机制每个 handler 被包装为 Lambda 函数并在 OpenAPI extensionx-amazon-apigateway-integrationaws_proxy类型中按 preflight 可解析的方式手工拼接 Lambda ARN从而允许 Lambda 的 inflight 代码反向引用 API Gateway 的 URL避免 Terraform 循环依赖每个路由都会创建LambdaPermissionAllowExecutionFromAPIGateway-...授权 API Gateway 调用 Lambda调用 URL 手工构造为https://{restApiId}.execute-api.{region}.amazonaws.com/prod源码注释说明这是为了避免直接使用invokeUrl引发的 Terraform 循环依赖支持私有 API Gateway当应用参数tf-aws/vpc_api_gateway为true时会创建安全组与 VPC 接口端点并写入“仅允许来自该 VPC 端点流量”的资源策略。awscdk实现platform-awscdk/src/api.ts同样继承AwsApi但底层换成 aws-cdk-lib 的SpecRestApi基于 OpenAPI 定义的 REST APIDeploymentStagehandler 同样通过ApiEndpointHandler.toFunctionHandler包装为 Lambda并生成AWS::ApiGateway::RestApi等 CloudFormation 资源见其 快照测试。AWS 上的事件适配无论哪种 AWS 平台请求映射都由 shared-aws/api-util.ts 中的apigwFunctionHandler完成——把 API Gateway 的APIGatewayProxyEvent转换为ApiRequest含x-www-form-urlencoded体的自动 JSON 化再把 handler 返回的ApiResponse映射为APIGatewayProxyResult响应头默认带上Content-Type: application/json与 CORS 头。Azuretf-azure与 GCPtf-gcp——尚未支持原文档明确指出Azure 与 GCP 两个目标尚未支持cloud.Api分别由上游 issue 跟踪。因此当前使用cloud.Api的可移植代码请以sim、tf-aws、awscdk为目标。七、端到端验证仓库中的测试如何驱动真实请求仓库在 tests/sdk_tests/api 下提供了一整套端到端测试每条测试都用bring http在 inflight 内发起真实 HTTP 请求打到{api.url}非常适合作为理解Api行为的活文档get.test.w验证 GET 的请求形状method/path/body/headers与默认响应默认 200、默认空 bodypost.test.w验证 POST 的 body 回显与http.post调用delete.test.w验证 DELETE 上的查询参数req.query.get(page)options.test.w覆盖OPTIONS、HEAD、CONNECT三种方法并注明 CONNECT 在 WHATWG fetch 规范中是被禁止的方法因此只能通过http.fetch测试path_vars.test.w 与 root_path_vars.test.w覆盖多段路径参数与根路径参数、以及路径冲突报错404.test.w验证未定义路径返回 404cors.test.w验证 CORS 响应头aws-api.test.w验证 AWS 专属属性invokeUrl含https://与 stage 名等非 AWS 环境自动跳过。这些测试在sim目标上可完整运行在 AWS 目标上则验证 API Gateway 生成的资源与调用 URL是学习cloud.Api行为最直接的参考。八、实战小结与最佳实践综合原文档与仓库源码使用cloud.Api时有几条值得遵循的原则用路径参数而非查询参数表达资源身份/employees/:id比/employees?id...更符合 REST 语义且vars与 OpenAPI 路径参数声明required、type string自动联动依赖隐式默认值减负不返回 body 时默认200空响应DELETE语义上常用204显式声明提前规划参数命名以避免冲突同段位的路径参数必须全局统一命名否则 preflight 会因 sibling/ambiguous 冲突拒绝编译CORS 按需开启跨域浏览器场景才配置cors: true生产环境务必把allowOrigin收敛为具体域名而非*注意平台差异与限制sim与 AWS 均把请求体按文本处理并限制在 10MBAWS 为 API Gateway 负载上限超大请求需要自行分片或改用对象存储Azure/GCP 目标暂不支持cloud.Api统一读写接口与cloud.Bucket、cloud.Counter、cloud.Function等资源组合时所有业务逻辑都写在 inflight 闭包内从而获得跨平台的可移植性。cloud.Api是 Wing “基础设施与运行时代码同语言”理念最直观的体现你在同一份代码里声明路由、实现业务、声明存储依赖然后由编译器为simExpress、tf-awsAPI Gateway Lambda、awscdkSpecRestApi分别产出对应的云资源。想深入阅读实现可从 cloud/api.ts 出发依次对照 target-sim/api.inflight.ts 与 target-tf-aws/api.ts再用 tests/sdk_tests/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点击查看免费下载相关推荐抖音无水印批量下载免费开源教程douyin-downloader 使用说明抖音无水印批量下载免费开源教程douyin downloader 使用说明 douyin downloader 是一个免费的开源抖音无水印下载工具支持对单个编程语言编译器云原生语言运行时Wing QuickShare 演示解析用 cloud.Api、Queue 与 DynamoDB 构建文件分享云应用Wing QuickShare 演示解析用 cloud.Api、Queue 与 DynamoDB 构建文件分享云应用 QuickShare 是 Wing编程语言编译器云原生语言运行时Wing SDKWing 语言的云原生标准库与独立 CDK 云资源库Wing SDKWing 语言的云原生标准库与独立 CDK 云资源库 Wing SDK winglang/sdk 是 Wing 编程语言的标准库封装了编程语言编译器云原生语言运行时上一篇FidelityFX SDK 工具链实战FidelityFX_SC 着色器排列编译器与 MediaDelivery 媒体交付系统下一篇Betaflight黑匣子完整教程从零到精通的飞行数据分析指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考