Files
galaxy-game/gateway/openapi.yaml
T
2026-04-02 19:18:42 +02:00

463 lines
16 KiB
YAML

openapi: 3.0.3
info:
title: Galaxy Edge Gateway Public REST API
version: v1
description: |
This specification documents the implemented `galaxy/gateway` v1 public
REST surface.
Implemented endpoints:
- `GET /healthz`
- `GET /readyz`
- `POST /api/v1/public/auth/send-email-code`
- `POST /api/v1/public/auth/confirm-email-code`
This specification intentionally excludes the private operational admin
listener and its `GET /metrics` endpoint. That endpoint is documented in
`README.md` because it is not part of the public REST contract.
Common runtime behavior:
- requests are unauthenticated;
- unknown routes return `404` with the JSON error envelope;
- unsupported methods on implemented routes and browser-shaped public paths
return `405` with the same JSON error envelope and an `Allow` header;
- request classification happens before route handling and depends on the
incoming method, path, and selected headers;
- the only stable public route classes are `public_auth`,
`browser_bootstrap`, `browser_asset`, and `public_misc`;
- any unsupported or empty classifier result is normalized to
`public_misc`;
- public REST policy derives its base bucket namespace from the normalized
class as `public_rest/class=<class>`;
- per-IP public REST rate limits use only `RemoteAddr`; `X-Forwarded-For`
and `Forwarded` are intentionally ignored;
- `public_auth` additionally applies normalized identity buckets by
`email` for `send-email-code` and by `challenge_id` for
`confirm-email-code`;
- oversized request bodies are rejected with `413 request_too_large`;
- public REST rate limits reject with `429 rate_limited` and a
`Retry-After` header;
- public auth routes delegate through `AuthServiceClient`;
- the default `cmd/gateway` wiring keeps the auth routes mounted and
returns `503 service_unavailable` until a concrete upstream auth adapter
is configured;
- injected public auth adapters may also project client-safe `4xx/5xx`
`AuthServiceError` envelopes, which the gateway preserves after
normalizing blank or invalid fields.
servers:
- url: http://localhost:8080
description: |
Example local public REST listener. The actual address is configured by
`GATEWAY_PUBLIC_HTTP_ADDR`.
tags:
- name: Probes
description: Unauthenticated public probe endpoints served by the gateway.
- name: PublicAuth
description: |
Unauthenticated public auth endpoints delegated to the Auth / Session
Service through `AuthServiceClient`.
paths:
/healthz:
get:
tags:
- Probes
operationId: getHealthz
summary: Public liveness probe
description: |
Returns a deterministic JSON payload confirming that the public REST
listener is alive and able to answer requests.
security: []
x-public-route-classification-note: |
Typical probe requests are classified as `public_misc`.
Requests that match browser bootstrap rules, for example because they
advertise `Accept: text/html`, are classified as `browser_bootstrap`
before the route handler runs.
responses:
"200":
description: Public REST listener is alive.
content:
application/json:
schema:
$ref: "#/components/schemas/HealthzResponse"
examples:
ok:
value:
status: ok
"413":
$ref: "#/components/responses/RequestTooLargeError"
"429":
$ref: "#/components/responses/RateLimitedError"
"500":
$ref: "#/components/responses/InternalError"
/readyz:
get:
tags:
- Probes
operationId: getReadyz
summary: Public readiness probe
description: |
Returns a deterministic JSON payload confirming that the process is
ready to accept public REST traffic. Readiness is local-process only
and does not reflect downstream dependencies.
security: []
x-public-route-classification-note: |
Typical probe requests are classified as `public_misc`.
Requests that match browser bootstrap rules, for example because they
advertise `Accept: text/html`, are classified as `browser_bootstrap`
before the route handler runs.
responses:
"200":
description: Public REST listener is ready to accept traffic.
content:
application/json:
schema:
$ref: "#/components/schemas/ReadyzResponse"
examples:
ready:
value:
status: ready
"413":
$ref: "#/components/responses/RequestTooLargeError"
"429":
$ref: "#/components/responses/RateLimitedError"
"500":
$ref: "#/components/responses/InternalError"
/api/v1/public/auth/send-email-code:
post:
tags:
- PublicAuth
operationId: sendEmailCode
summary: Start a public e-mail login challenge
description: |
Accepts a single client e-mail address and delegates the command to the
Auth / Session Service. The response returns an opaque `challenge_id`
that must later be confirmed through
`POST /api/v1/public/auth/confirm-email-code`.
This route is unauthenticated and classified as `public_auth`.
Public REST anti-abuse applies a per-IP bucket derived from
`RemoteAddr` and an additional normalized identity bucket derived from
`email`.
In the default `cmd/gateway` process wiring the upstream auth adapter
is intentionally absent, so this route returns `503
service_unavailable` until a concrete `AuthServiceClient` is injected.
When an injected adapter returns a client-safe `AuthServiceError`, the
gateway preserves that projected `4xx/5xx` status and serialized error
envelope after normalizing blank or invalid fields.
security: []
x-public-route-classification-note: |
This route is always classified as `public_auth`.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/SendEmailCodeRequest"
examples:
default:
value:
email: pilot@example.com
responses:
"200":
description: The login challenge was accepted by the Auth / Session Service.
content:
application/json:
schema:
$ref: "#/components/schemas/SendEmailCodeResponse"
examples:
accepted:
value:
challenge_id: challenge-123
"400":
$ref: "#/components/responses/InvalidRequestError"
"413":
$ref: "#/components/responses/RequestTooLargeError"
"405":
$ref: "#/components/responses/MethodNotAllowedError"
"429":
$ref: "#/components/responses/RateLimitedError"
"500":
$ref: "#/components/responses/InternalError"
"503":
$ref: "#/components/responses/ServiceUnavailableError"
default:
$ref: "#/components/responses/ProjectedAuthServiceError"
/api/v1/public/auth/confirm-email-code:
post:
tags:
- PublicAuth
operationId: confirmEmailCode
summary: Confirm a public e-mail login challenge
description: |
Completes a previously issued `challenge_id`, sends the verification
`code`, and registers the standard base64-encoded raw 32-byte Ed25519
`client_public_key` for the new device session. The response returns
the created `device_session_id`.
This route is unauthenticated and classified as `public_auth`.
Public REST anti-abuse applies a per-IP bucket derived from
`RemoteAddr` and an additional normalized identity bucket derived from
`challenge_id`.
In the default `cmd/gateway` process wiring the upstream auth adapter
is intentionally absent, so this route returns `503
service_unavailable` until a concrete `AuthServiceClient` is injected.
When an injected adapter returns a client-safe `AuthServiceError`, the
gateway preserves that projected `4xx/5xx` status and serialized error
envelope after normalizing blank or invalid fields.
security: []
x-public-route-classification-note: |
This route is always classified as `public_auth`.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ConfirmEmailCodeRequest"
examples:
default:
value:
challenge_id: challenge-123
code: "123456"
client_public_key: base64-encoded-raw-ed25519-public-key
responses:
"200":
description: The device session was created by the Auth / Session Service.
content:
application/json:
schema:
$ref: "#/components/schemas/ConfirmEmailCodeResponse"
examples:
accepted:
value:
device_session_id: device-session-123
"400":
$ref: "#/components/responses/InvalidRequestError"
"413":
$ref: "#/components/responses/RequestTooLargeError"
"405":
$ref: "#/components/responses/MethodNotAllowedError"
"429":
$ref: "#/components/responses/RateLimitedError"
"500":
$ref: "#/components/responses/InternalError"
"503":
$ref: "#/components/responses/ServiceUnavailableError"
default:
$ref: "#/components/responses/ProjectedAuthServiceError"
components:
schemas:
HealthzResponse:
type: object
additionalProperties: false
required:
- status
properties:
status:
type: string
description: Deterministic liveness marker.
enum:
- ok
ReadyzResponse:
type: object
additionalProperties: false
required:
- status
properties:
status:
type: string
description: Deterministic readiness marker.
enum:
- ready
SendEmailCodeRequest:
type: object
additionalProperties: false
required:
- email
properties:
email:
type: string
description: Single client e-mail address that should receive the login code.
format: email
SendEmailCodeResponse:
type: object
additionalProperties: false
required:
- challenge_id
properties:
challenge_id:
type: string
description: Opaque challenge identifier returned by the Auth / Session Service.
ConfirmEmailCodeRequest:
type: object
additionalProperties: false
required:
- challenge_id
- code
- client_public_key
properties:
challenge_id:
type: string
description: Opaque challenge identifier previously returned by send-email-code.
code:
type: string
description: Verification code delivered to the client.
client_public_key:
type: string
description: Standard base64-encoded raw 32-byte Ed25519 public key registered for the new device session.
ConfirmEmailCodeResponse:
type: object
additionalProperties: false
required:
- device_session_id
properties:
device_session_id:
type: string
description: Stable identifier of the created device session.
ErrorResponse:
type: object
additionalProperties: false
required:
- error
properties:
error:
$ref: "#/components/schemas/ErrorBody"
ErrorBody:
type: object
additionalProperties: false
required:
- code
- message
properties:
code:
type: string
description: |
Stable gateway-generated or client-safe auth-adapter-projected
error code. Gateway-generated values include `invalid_request`,
`not_found`, `method_not_allowed`, `request_too_large`,
`rate_limited`, `internal_error`, and `service_unavailable`.
message:
type: string
description: Human-readable client-safe error description.
headers:
Allow:
description: Comma-separated list of allowed methods for the target route.
schema:
type: string
example: GET
Retry-After:
description: Seconds until the client should retry a rejected rate-limited request.
schema:
type: string
example: "3600"
responses:
InvalidRequestError:
description: Request body or field values are invalid for the target public auth route.
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
invalidRequest:
value:
error:
code: invalid_request
message: email must be a single valid email address
NotFoundError:
description: Request path is not implemented on the current public REST surface.
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
notFound:
value:
error:
code: not_found
message: resource was not found
MethodNotAllowedError:
description: Request method is not allowed for an implemented route.
headers:
Allow:
$ref: "#/components/headers/Allow"
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
methodNotAllowed:
value:
error:
code: method_not_allowed
message: request method is not allowed for this route
RequestTooLargeError:
description: Request body exceeds the configured public REST body limit for the route class.
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
requestTooLarge:
value:
error:
code: request_too_large
message: request body exceeds the configured limit
RateLimitedError:
description: Request is rejected by the public REST anti-abuse rate limiter.
headers:
Retry-After:
$ref: "#/components/headers/Retry-After"
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
rateLimited:
value:
error:
code: rate_limited
message: request rate limit exceeded
InternalError:
description: Internal gateway error while processing the request.
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
internalError:
value:
error:
code: internal_error
message: internal server error
ServiceUnavailableError:
description: |
The public route is mounted, but the configured or default auth adapter
cannot currently serve the request.
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
unavailable:
value:
error:
code: service_unavailable
message: auth service is unavailable
ProjectedAuthServiceError:
description: |
Client-safe `4xx/5xx` error envelope projected by an injected public
auth adapter through `AuthServiceError`. The gateway preserves the
projected status and serialized envelope after normalizing blank or
invalid fields.
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
projectedRateLimit:
value:
error:
code: upstream_rate_limited
message: too many attempts for this email