1import * as ApiGateway from "@/AWS/ApiGateway";
2import * as Lambda from "@/AWS/Lambda";
3import * as Effect from "effect/Effect";
4import * as HttpServerResponse from "effect/http/HttpServerResponse";
5
6export class RestApiEventSourceFunction extends Lambda.Function<RestApiEventSourceFunction>()(
7 "RestApiEventSourceFunction",
8) {}
9
10/**
11 * Fixture: a Lambda that owns a REST API and serves two routes through the
12 * `RestApiEventSource` (`onRestApiRoute`) binding. The event source
13 * materializes the `Resource` chain, `AWS_PROXY` `Method`s, and the invoke
14 * `Permission`; the `Deployment`/`Stage` below are ordered after them via
15 * the API's binding contract.
16 *
17 * Deliberately does NOT `yield*` any `api.*`/`stage.*` outputs: the API's
18 * full `create` settles only after every bound child (including the
19 * `Method`s that reference `host.functionArn`), so awaiting those outputs
20 * inside the host's own effect would deadlock the plan. The test discovers
21 * the REST API id out-of-band by its stack, stage, and logical-id tags.
22 */
23export default RestApiEventSourceFunction.make(
24 {
25 main: import.meta.url,
26 functionUrl: true,
27 },
28 Effect.gen(function* () {
29 const api = yield* ApiGateway.RestApi("AgEsApi", {
30 endpointConfiguration: { types: ["REGIONAL"] },
31 });
32
33 // GET /items — static JSON response.
34 yield* ApiGateway.onRestApiRoute(
35 api,
36 { path: "/items", httpMethod: "GET" },
37 () =>
38 Effect.succeed({
39 statusCode: 200,
40 headers: { "content-type": "application/json" },
41 body: JSON.stringify({ items: ["alpha", "beta"] }),
42 }),
43 );
44
45 // POST /echo — proves the proxy event (method, resource, body) reaches
46 // the handler intact.
47 yield* ApiGateway.onRestApiRoute(
48 api,
49 { path: "/echo", httpMethod: "POST" },
50 (event) =>
51 Effect.sync(() => ({
52 statusCode: 200,
53 headers: { "content-type": "application/json" },
54 body: JSON.stringify({
55 method: event.httpMethod,
56 resource: event.resource,
57 echoed: event.body === null ? null : JSON.parse(event.body),
58 }),
59 })),
60 );
61
62 const deployment = yield* ApiGateway.Deployment("AgEsDep", {
63 restApi: api,
64 });
65 yield* ApiGateway.Stage("AgEsStage", {
66 restApi: api,
67 stageName: "test",
68 deploymentId: deployment.deploymentId,
69 });
70
71 return {
72 // Readiness probe only — the REST routes are served via the event
73 // source, not the function URL.
74 fetch: Effect.succeed(HttpServerResponse.text("ok")),
75 };
76 }).pipe(Effect.provide(Lambda.RestApiEventSource)),
77);