Skip to content

API Gateway

12 min read · main part only; folded sections are optional

After this you can answer: When would API Gateway improve our API design, and which checks must remain in the application?

This proposed scanner API is separate from the existing browser application. A JWT is a signed JSON Web Token containing identity claims. The proposed identity provider issues it; API Gateway validates it before invoking the handler.

Our existing ticket uses HMAC, a keyed message authentication code. A proposed ticket verifier must therefore read the same signing secret; the operator’s JWT and the ticket’s HMAC are separate checks.

flowchart LR
scan["Check-in scanner (designed, not built)"] -->|"submits scan - HTTPS, JWT and route scope"| gateway["API Gateway HTTP API (designed, not built)"]
gateway -->|"validates token - configured issuer, audience and public keys"| auth["JWT authorizer; Cognito issuer (designed, not built)"]
gateway -->|"invokes - lambda:InvokeFunction; apigateway.amazonaws.com, SourceArn"| lambda["Check-in Lambda (designed, not built)"]
lambda -->|"admits once - proposed role dynamodb:UpdateItem on tickets table"| db["minitickets-dev-tickets DynamoDB"]
lambda -->|"verifies HMAC - proposed role secretsmanager:GetSecretValue on one secret"| secret["minitickets/dev/ticket-signing"]
class gateway service
class gateway designed
class scan,lambda app
class scan,lambda designed
class auth security
class auth designed
class db aws
class secret security

Legend: highlighted = API Gateway; app = proposed scanner code; security = authorizer; dashed = designed, not built; the tickets table is implemented.

Open the existing ALB entry point in the map → · Open the existing tickets table →. No API Gateway map piece is deployed or defined.

  1. The scanner obtains an access token from the proposed identity provider and calls POST /check-ins. A route is a method and path that selects request handling. The token identifies an operator, while the request contains the ticket and a stable scan request ID.
  2. API Gateway selects the stage and route. A stage is a named API deployment endpoint with settings such as logging and throttling. A deployment captures the API configuration used by that endpoint.
  3. A JWT authorizer verifies the signature, issuer, audience, time claims, and required route scope. A scope is a named permission carried in an access token, such as the proposed tickets:check-in. Valid authentication does not prove access to every event.
  4. A Lambda proxy integration wraps the request and identity context into the function’s event. Proxy integration means the backend handles most request and response details, rather than a large set of gateway transformations.
  5. The handler validates input, checks the operator’s event access, verifies the ticket signature, and performs one conditional DynamoDB update. The condition allows admission only while the ticket is in its expected state.
  6. The handler returns a result such as admitted or already checked in. The gateway returns it to the scanner. A lost response can be retried with the same request ID to recover the result without treating it as a new admission.
sequenceDiagram
participant Scan as Scanner (designed, not built)
box rgb(237,233,254) API Gateway
participant GW as API Gateway (designed, not built)
end
participant Auth as JWT authorizer (designed, not built)
participant Fn as Check-in Lambda (designed, not built)
participant DB as tickets DynamoDB
Scan->>GW: POST /check-ins with token and requestId
GW->>Auth: Validate signature, claims and route scope
Auth-->>GW: Verified identity
GW->>Fn: Request and verified identity context
Fn->>Fn: Validate ticket and authorize event
Fn->>DB: Conditional UpdateItem with scan requestId
DB-->>Fn: Won admission or condition failed
Fn-->>GW: Structured result
GW-->>Scan: Admission decision

Legend: proposed request sequence; the DynamoDB table exists in code, while the scanner endpoint and update behavior are designed, not built.

API Gateway manages request handling and connections; it does not run our business logic by itself. The public API configuration and its backend integration are distinct resources. A deployed route can exist while its Lambda invocation permission or backend configuration is wrong.

API typeWhy choose itImportant distinction
REST APIAPI keys and usage plans, request validation, response caching, or other API management featuresMore features and configuration; compare current cost against HTTP APIs.
HTTP APIA simpler HTTP/Lambda API with native JWT authorizationNo REST usage plans or gateway response cache.
WebSocket APIPersistent two-way messaging between clients and backendRoutes handle messages and connection lifecycle, rather than independent HTTP requests only.

REST and HTTP are product names; both can expose REST-style endpoints. The AWS comparison lists exact feature support. A WebSocket connection lets a backend send later messages; the application still manages which connection may receive which event. AWS WebSocket overview

An HTTP API can integrate with Lambda, a reachable HTTP endpoint, supported AWS APIs, or private resources through a VPC link. A VPC link gives API Gateway network connectivity into a VPC. It does not replace backend permissions or application authentication. An AWS service integration can send a request to SQS without a pass-through Lambda when transformation and authorization requirements fit. AWS HTTP integrations

Authorization options solve different problems. IAM authorization requires a request signed with AWS credentials and permission such as execute-api:Invoke. A Lambda authorizer calls custom code to allow or deny a caller. Native HTTP API JWT authorizers validate tokens from compatible issuers, including Cognito. REST APIs support Cognito user-pool authorizers and Lambda authorizers; a custom Lambda authorizer can validate other JWTs. AWS authorizer types

Cognito is an identity service that can issue tokens; API Gateway does not issue a login token merely because a route uses JWT authorization. Configure the expected issuer and audience, meaning the token’s issuer and intended recipient. Require access-token scopes where appropriate so an ID token intended for login identity is not mistaken for API access. AWS JWT authorization

API keys identify clients for REST usage plans. A usage plan attaches best-effort request-rate and quota targets to those keys. Keys are not user authentication, and quotas are not exact billing caps. Throttling limits accepted traffic when request rates exceed configured targets; clients may see 429 Too Many Requests. AWS usage plans

Response caching and authorizer caching are different. REST response caching reuses backend answers; authorizer caching reuses an access decision. Cache keys determine which requests share a result. Never cache a state-changing check-in, and do not let one operator’s authorization result authorize another route or event unintentionally. AWS response caching, AWS authorizer caching

At the time of writing; check the AWS docs. No API Gateway quota has been read from our live account because this service is explain-only here.

PropertyCurrent documented valueSource
HTTP API integration timeoutMaximum 30 secondsAWS HTTP quotas
REST buffered integration timeoutDefault maximum 29 seconds; increases available for Regional/private APIs, potentially reducing regional throttle quotaAWS REST quotas
WebSocket integration timeoutMaximum 29 secondsAWS WebSocket quotas
HTTP API payload sizeMaximum 10 MBAWS HTTP quotas
Shared API request-rate quotaDefault 10,000 requests/s in us-east-1, burst capacity 5,000; verify account quotaAWS account quotas
REST response-cache TTLDefault 300 seconds, maximum 3,600 secondsAWS caching
REST response streamingSupported proxy integrations can stream up to 15 minutes; separate idle timeouts applyAWS response streaming

The effective request limit also depends on the backend. A Lambda proxy request must fit Lambda’s synchronous invocation limit, including its event wrapper and any base64 expansion; a 10 MB gateway ceiling does not promise a 10 MB Lambda request. AWS Lambda payload limits.

Do not memorize “all API Gateway requests stop at 29 seconds.” API type, endpoint type, quota increases, and buffered versus streaming responses matter. REST now supports response streaming for HTTP_PROXY and AWS_PROXY integrations; HTTP APIs do not. Streaming can exceed the normal buffered response-size and duration limits but disables features that require the full response, including endpoint caching. AWS response streaming

Explain-only: designed, not built. There are no API Gateway routes, Cognito user pools, API keys, usage plans, check-in authorizers, or check-in Lambda functions in our infrastructure.

The existing entry layer uses an Application Load Balancer, or ALB, which routes HTTP requests to container targets. infra/src/entry/https-listener.ts routes /trpc/* to the API target group and other paths to the web target group in ALB-only mode. infra/src/entry/target-groups.ts targets API port 4000 and web port 3000. The optional CloudFront mode has its separate listener configuration.

apps/api/src/app.ts mounts the Fastify tRPC adapter at /trpc. tRPC shares typed procedure contracts with our TypeScript web client. apps/api/src/trpc/context.ts reads the sid session cookie and looks up the session in Redis. apps/api/src/trpc/init.ts enforces login and reads current roles for admin procedures. A managed JWT authorizer would not understand this opaque cookie automatically.

ALB plus tRPC fits two existing container services and a browser client on the same origin. Adding API Gateway in front of every request would introduce another configuration and failure surface without eliminating those services. A separate HTTP API could make sense for short scanner requests, independent deployment, and token-based mobile clients. Existing tRPC could also implement check-in; API Gateway is a choice, not a requirement for safe admission.

ConnectionWhat allows itBoundary to keep
Proposed scanner → HTTP APIHTTPS and JWT authorizer with issuer, audience, route scopesA valid token still needs event-specific authorization.
API Gateway → proposed LambdaFunction resource policy allowing apigateway.amazonaws.com to lambda:InvokeFunction, constrained by source API ARNThis does not grant the function datastore access.
Proposed Lambda → tickets tableNew function role with the required dynamodb:GetItem / dynamodb:UpdateItem grantsExisting API role has Query only; do not silently reuse it.
Proposed Lambda → ticket-signing secretNew function role: secretsmanager:GetSecretValue on the existing signing secretOur current ticket token uses HMAC, so verification needs that shared secret; a holder can also sign tokens. This proposed grant needs a deliberate trust decision; public-key verification would require a different token design.
Proposed HTTP API → private containerVPC link, supported integration target, network rulesA private integration is not the same as a private client-facing API.
Existing ALB → API task/trpc/* listener rule and inbound TCP 4000 from ALB security group to API security groupThat network rule does not authenticate the user.

Lambda proxy event and response formats are documented in AWS HTTP Lambda integration; the invocation grant uses the function resource policy as shown in AWS invocation permissions. Private integration capabilities have evolved: REST VPC links V2 can now target ALBs; old advice that REST always needs an NLB is outdated. AWS REST private integrations

CORS means cross-origin resource sharing: browser rules controlling which origins may read responses. It is separate from authentication and does not restrict ordinary non-browser clients. HTTP APIs can answer preflight OPTIONS requests from configured CORS settings. Allow the scanner web origin and required headers; ensure preflight does not require the access token it is asking permission to send. AWS HTTP CORS

flowchart TB
request["Scanner request"] --> auth{"Authentication and route access"}
auth -->|"Invalid token or denied scope"| reject["401 or 403; inspect authorizer result"]
auth -->|"Allowed"| backend["Check-in Lambda"]
backend -->|"Slow or response lost"| timeout["504 or client timeout"]
timeout --> retry["Retry same scan requestId"]
retry --> condition["Read prior result or conditionally admit"]
class request,backend,retry app
class request,backend,retry designed
class auth security
class auth designed
class reject,timeout failure
class condition service
class condition designed

Legend: proposed failure path; red = rejected or uncertain result; retry preserves the operation identity.

What you seeWhyFix
401 Unauthorized or 403 ForbiddenMissing/expired token, wrong issuer/audience, denied route, or backend event denialCompare the access log, token claims, route configuration, and application decision. Do not remove authorization to test success.
429 Too Many RequestsRoute, stage, usage-plan, or shared account throttlingIdentify the applicable layer; apply client backoff and adjust capacity deliberately.
500 before handler logsAPI Gateway cannot invoke the function or its authorizerCheck Lambda resource policy, source ARN, integration target, and authorizer errors.
502 Bad Gateway or malformed response errorLambda proxy output does not match the configured payload formatInspect safe error logs and return a supported response; test the actual event format.
504 or client timeout after admissionBackend was slow or the response did not arriveRecover using the same request ID; timeout does not prove the admission update failed.

Enable structured access logs with route, request ID, status, integration status, and latency. Do not log complete tokens or QR contents. Compare Latency, the total gateway response time, with IntegrationLatency, backend waiting time, where available. That separates slow integration work from other request overhead. AWS API Gateway metrics

At 10x, the bottleneck might be Lambda concurrency, an authorizer’s identity lookup, or a hot DynamoDB item. Set route throttles from backend capacity and expected latency. A gateway capable of accepting many requests can overload a smaller backend. Preserve enough capacity for other APIs sharing account quotas.

At 100x, arrival bursts and retries amplify each other. Use bounded retry with jitter, meaning a randomized delay, and show scanners a clear retryable state. Do not acknowledge “admitted” before the conditional update finishes. An asynchronous 202 Accepted means work was queued, which is insufficient to decide whether someone can enter now.

A venue outage creates a product decision: reject scans without connectivity or accept a defined offline risk. API Gateway cannot coordinate disconnected devices. Measure duplicate attempts, denied operators, backend latency, throttling, and unknown results, not just successful HTTP responses.

  • “An API key authenticates the operator.” It identifies a client for a usage plan. Use a real identity mechanism and event authorization.
  • “JWT verification means this ticket is valid.” The operator token and the ticket token represent different things. Verify both and check business state.
  • “A 504 means nothing happened.” The backend may have committed. Retry the same operation identity.
  • “CORS prevents unauthorized API calls.” It controls browser access to responses; scripts and other clients can still call the endpoint.
  • “The stage creates a separate backend database.” A stage selects deployment configuration. Separate data and roles must be configured explicitly.

Design a scanner endpoint for two entrances that may scan the same QR code simultaneously.

Use a short HTTP API request with a JWT authorizer for operator identity. The handler checks event access and ticket signature, then conditionally records admission and the scan request ID in DynamoDB. Return success only to the winning request. A retry of that request retrieves the stored result; a different scan receives already checked in. Keep authorization changes timely rather than hiding event access in a long-lived cached allow decision.

flowchart TB
a["Entrance A scanner (designed, not built)"] --> gw["HTTP API and JWT authorization (designed, not built)"]
b["Entrance B scanner (designed, not built)"] --> gw
gw --> fn["Authorize event and verify ticket (designed, not built)"]
fn --> db["Conditional check-in update (designed, not built)"]
db -->|"Winning requestId"| ok["Admit"]
db -->|"Different requestId"| no["Already checked in"]
class a,b,fn app
class a,b,fn designed
class gw service
class gw designed
class db aws
class db designed
class ok aws
class no failure

Legend: all check-in behavior is designed, not built; one conditional update resolves simultaneous scans.

HTTP API is sufficient unless REST-only management features are requirements. A WebSocket API is useful for later pushed updates, not necessary for one scan and response. If the main app stays on ALB, keep this endpoint’s identity, deployment, and operational costs explicit rather than migrating unrelated traffic.

Why not use an API key as scanner authentication?
A shared client key does not establish an operator’s identity or event access. Usage-plan quotas are best effort too.
What changes for a WebSocket API?
It maintains connections and routes messages. A Lambda authorizer is attached to the connect route; later messages still require application authorization and expiry handling.
Can API Gateway call SQS without Lambda?
Supported AWS service integrations can do that. Validate the mapping and permissions, and use it when queue acceptance is the required result, rather than immediate admission.
How do stages affect deployment?
A stage selects deployed API configuration. HTTP APIs can auto-deploy changes; REST configuration changes need a deployment. Neither creates independent data automatically.
Why keep ALB plus tRPC?
It fits our existing Next.js and Fastify containers and shared TypeScript contracts. API Gateway adds value when its request-management features or separate serverless endpoint justify another service.
  • Choose REST, HTTP, or WebSocket from the features the client actually needs.
  • Authorizers establish request identity and access; handlers enforce business rules.
  • API keys and usage plans are not authentication or exact spending limits.
  • A timeout leaves the operation outcome uncertain; preserve the same request ID.
  • MiniTickets uses ALB and tRPC today; API Gateway check-in is designed, not built.
Advanced: Stages, WebSocket authorization, and read-only inspection

Console: API Gateway → selected API → Routes or Resources → integration and authorization; then Stages → deployment, logs, throttling. Verify the invoked stage and actual Lambda version before blaming application code.

Terminal window
aws apigatewayv2 get-apis --region us-east-1
aws apigateway get-rest-apis --region us-east-1
aws apigatewayv2 get-stages --api-id "$API_ID" --region us-east-1
aws apigatewayv2 get-routes --api-id "$API_ID" --region us-east-1

These inspect existing APIs. They do not create the proposed endpoint, and this repository supplies no API ID. HTTP API stages may use automatic deployment; REST stages point to deployment snapshots. AWS HTTP stages, AWS REST deployments

For WebSocket APIs, Lambda authorizers run only on $connect. Changing authorization does not retroactively validate every connected message. The backend must enforce message access, handle token expiry and revoked access, and remove stale connection records. AWS WebSocket authorization

For a Lambda authorizer, choose cache identity sources carefully. If a cached response applies to only one route or event, include that distinction in the cache key or return a policy that is correct for every request sharing the key. Backend authorization remains useful when event membership changes faster than token or cache expiry.

With HTTP API’s $default route and an authorizer, configure unauthenticated preflight handling deliberately. Cross-origin cookie requests also need an exact allowed origin and credentials support; do not assume a wildcard origin is sufficient.

Answer these without scrolling up. If one feels hard, reread that section.

  1. Which required feature would make you choose REST over HTTP API?
  2. Which permission lets API Gateway invoke Lambda, and whose role accesses DynamoDB?
  3. Why must the handler check event access after the JWT is valid?
  4. What should a scanner retry after a timeout following a possible successful admission?
  5. Why does a second API stage not automatically isolate production data?

Redraw it from memory: the scanner, API Gateway, authorizer, Lambda and conditional DynamoDB update

Try this: compare the current sid-cookie context with the claims a proposed JWT integration would supply

Read this book online: https://book.theversehub.in/