mirror of
https://github.com/zap-proto/web.git
synced 2026-10-30 15:03:09 +00:00
httpServe(httpServer, opts) mounts POST /<service>/<method> on the SAME
http.Server, dispatching each request through the identical CallHandler that
serve() uses over WebSocket — one service implementation, reached two ways. The
paths match the OpenAPI 3.1 doc that `zapgen --emit=openapi` emits.
The JSON<->ZAP codec is schema-specific, so each method is supplied as an
HttpRoute {path, method ordinal, decode(json)->payloadBytes,
encode(bodyBytes)->json}; the generated zapgen bindings provide the struct
builders/views to fill those in. The runtime stays schema-agnostic. Auth reuses
the MintCap slot (null mint -> HTTP 401); ZAP error statuses map to HTTP 4xx/5xx.
httpServe owns `request` dispatch: it captures the app's existing listeners,
detaches them, and delegates unmatched paths back to them — guaranteeing exactly
one response writer per request even though route handling is async (mintCap,
body read). Node `http` only, no framework. Exported from @zap-proto/web/server.
Round-trip test: generate ts+openapi from a fixture .zap, validate every
components.schema under ajv 2020-12 (the dialect OpenAPI 3.1 mandates), spin
httpServe in-process, POST to the declared path, and assert the response
validates against the doc's 200 schema. Depends on @zap-proto/zap ^1.3.0.
85 lines
1.8 KiB
JSON
85 lines
1.8 KiB
JSON
{
|
|
"openapi": "3.1.0",
|
|
"info": {
|
|
"title": "EchoService",
|
|
"version": "1.0.0"
|
|
},
|
|
"servers": [
|
|
{
|
|
"url": "http://127.0.0.1/v1"
|
|
}
|
|
],
|
|
"paths": {
|
|
"/echo-service/echo": {
|
|
"post": {
|
|
"operationId": "echoService.echo",
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/EchoOut"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Bad request — payload failed validation."
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized — missing or invalid credentials."
|
|
},
|
|
"403": {
|
|
"description": "Forbidden — credentials lack the capability."
|
|
},
|
|
"404": {
|
|
"description": "Not found — unknown method."
|
|
},
|
|
"500": {
|
|
"description": "Internal server error."
|
|
}
|
|
},
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/EchoIn"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"components": {
|
|
"schemas": {
|
|
"EchoIn": {
|
|
"type": "object",
|
|
"properties": {
|
|
"msg": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"required": [
|
|
"msg"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"EchoOut": {
|
|
"type": "object",
|
|
"properties": {
|
|
"msg": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"required": [
|
|
"msg"
|
|
],
|
|
"additionalProperties": false
|
|
}
|
|
}
|
|
}
|
|
}
|