Skip to content

feat: apiGateway component - AWS API Gateway on LocalStack with imported OpenAPI specs - #71

Merged
martypitt merged 2 commits into
mainfrom
feat/aws-api-gateway
Sep 22, 2026
Merged

martypitt merged 2 commits into
mainfrom
feat/aws-api-gateway

Conversation

@martypitt

Copy link
Copy Markdown
Contributor

Adds an apiGateway { } component: LocalStack with API Gateway enabled, with OpenAPI documents imported as REST APIs and deployed to a stage. Orbital treats API Gateway as a schema registry (see vyne!2176), so this gives a stack something for it to browse and pull.

stack {
   apiGateway {
      restApi("pets", stage = "v1", openApi = petsOpenApi)
      restApiFromFile("orders", path = "/abs/orders.yaml")   // stage defaults to "prod"
   }
}

What's emitted

The component config is flat so Orbital exposes every value as an env variable:

Key Env var (default component name)
accessKey, secretKey, region, endpointOverride NEBULA_API_GATEWAY_ENDPOINT_OVERRIDE etc
<name>ApiId, <name>Stage, <name>InvokeUrl NEBULA_API_GATEWAY_PETS_API_ID etc

Dashed API names are camel-cased (pet-store -> petStoreApiId). The docs page shows a connections.conf + registries.conf pair wired to these.

Notes

  • REST APIs only: the community LocalStack image has no API Gateway v2 (HTTP APIs).
  • The imported API answers requests only if the spec carries x-amazon-apigateway-integration blocks, as on AWS. Without them it exists for schema export, which is what Orbital's registry sync needs.
  • restApiFromFile currently resolves on the Nebula server's filesystem, like s3 { file(path) }. Once feat(bundles): submit a stack together with the files it reads #70 (stack bundles) lands, it should resolve through resources.resolveFilePath(path) so files can ship with the stack.
  • STS is enabled alongside API Gateway because Orbital's AWS connection health check calls GetCallerIdentity.

Tests

ApiGatewayExecutorTest runs against LocalStack: imports a spec, checks the OpenAPI export contains the path and schema, and checks the emitted config carries the API id, stage and invoke URL.

🤖 Generated with Claude Code

https://claude.ai/code/session_011c7t8dqC37eQzTt9o44x9v

@netlify

netlify Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for orbital-nebula canceled.

Name Link
🔨 Latest commit 8ead2d1
🔍 Latest deploy log https://app.netlify.com/projects/orbital-nebula/deploys/6ab271a5af90fb00084c0940

…ted OpenAPI specs

Adds an `apiGateway { }` block that starts LocalStack with API Gateway
enabled, imports each declared OpenAPI document as a REST API and deploys
it to a stage. Orbital treats API Gateway as a schema registry, so this
gives a stack something for it to browse and pull.

    apiGateway {
       restApi("pets", stage = "v1", openApi = petsOpenApi)
       restApiFromFile("orders", path = "/abs/orders.yaml")
    }

The emitted config is flat (accessKey, secretKey, region, endpointOverride,
<name>ApiId, <name>Stage, <name>InvokeUrl) so every value reaches Orbital
as an env variable, eg NEBULA_API_GATEWAY_PETS_API_ID.

REST APIs only: the community LocalStack image has no API Gateway v2.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011c7t8dqC37eQzTt9o44x9v
@martypitt

Copy link
Copy Markdown
Contributor Author

Rebased onto main now that #70 (stack bundles) has merged. restApiFromFile(path) now resolves through resources.resolveFilePath(path), so a relative path reads a spec shipped with the stack, and an absolute path keeps reading the Nebula server's filesystem. Added a test covering the bundle case, and updated the docs examples to use a bundle-relative path.

🤖 — Claude

…reach the Nebula host

A spec deployed to the gateway can carry x-amazon-apigateway-integration
blocks that proxy to an http { } stub running where Nebula runs. The
LocalStack container needs a route back to that host; on Linux Docker
doesn't provide host.docker.internal by default, so add it explicitly
with the host-gateway alias.

Verified with the api-gateway-registry demo: 14 APIs imported from a
bundle, a call through a stage's invoke URL is proxied to the stub with
path and query parameters intact.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011c7t8dqC37eQzTt9o44x9v
@martypitt
martypitt merged commit 0b51ec3 into main Sep 22, 2026
8 checks passed
@martypitt

Copy link
Copy Markdown
Contributor Author

Added stable API ids (070017c). importRestApi minted a fresh id on every stack start, which broke anything that had recorded one, such as an Orbital registry selection. The executor now creates the API with LocalStack's _custom_id_ tag, defaulting the id to the declared name in lower case, and imports the spec into it with putRestApi. restApi(..., apiId = "...") overrides it. Verified on LocalStack 3.0.2; tests cover the default and the explicit id.

Also documented that response schemas must be named models under components/schemas, since API Gateway drops inline schemas on import.

🤖 — Claude

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant