1---
2title: "Part 2: An HTTP API"
3description: Deploy an Effect-native Prisma Compute service and add an HTTP health endpoint.
4sidebar:
5 order: 2
6---
7
8import { Code, Tabs, TabItem } from "@astrojs/starlight/components";
9
10Continue from [Part 1](/prisma/tutorial/part-1). The Project exists, but it
11has no public endpoint yet. Add a Compute service that runs an Effect HTTP
12handler on Prisma's Bun runtime.
13
14## Define the Compute service
15
16Create `src/Api.ts`:
17
18```typescript
19import * as Prisma from "alchemy/Prisma";
20import * as Effect from "effect/Effect";
21import * as HttpServerResponse from "effect/http/HttpServerResponse";
22import { Project } from "./Database.ts";
23
24export default class Api extends Prisma.Compute<Api>()(
25 "Api",
26 Effect.gen(function* () {
27 const project = yield* Project;
28 return {
29 project,
30 main: import.meta.filename,
31 regionId: "eu-west-3",
32 branchGitName: "main",
33 port: 3000,
34 destroyOldDeployment: true,
35 };
36 }),
37 Effect.gen(function* () {
38 return { fetch: Effect.succeed(HttpServerResponse.text("Hello from Prisma")) };
39 }),
40) {}
41```
42
43`Prisma.Compute` bundles the handler into a Bun archive and deploys it without
44a Dockerfile. `main` points to the file that default-exports this class.
45The Project already owns the `main` branch, so select it by `branchGitName`.
46
47## Register the API
48
49```diff lang="typescript"
50// alchemy.run.ts
51+import Api from "./src/Api.ts";
52
53 Effect.gen(function* () {
54 const project = yield* Project;
55+ const api = yield* Api;
56- return { projectId: project.projectId };
57+ return { projectId: project.projectId, apiUrl: api.url };
58 }),
59```
60
61The API depends on the same Project definition. Yielding it from both files
62still creates only one Project in this Stack.
63
64## Read the incoming request
65
66```diff lang="typescript"
67// src/Api.ts
68+import { HttpServerRequest } from "effect/http/HttpServerRequest";
69
70 Effect.gen(function* () {
71- return { fetch: Effect.succeed(HttpServerResponse.text("Hello from Prisma")) };
72+ return {
73+ fetch: Effect.gen(function* () {
74+ const request = yield* HttpServerRequest;
75+ return HttpServerResponse.text(`Requested ${request.url}`);
76+ }),
77+ };
78 }),
79```
80
81Each HTTP request receives its own Effect request context.
82
83## Restrict the HTTP method
84
85```diff lang="typescript"
86// src/Api.ts
87 const request = yield* HttpServerRequest;
88+ if (request.method !== "GET") {
89+ return HttpServerResponse.text("Method not allowed", {
90+ status: 405,
91+ headers: { allow: "GET" },
92+ });
93+ }
94 return HttpServerResponse.text(`Requested ${request.url}`);
95```
96
97This read-only API rejects writes with HTTP 405.
98
99## Add a health route
100
101```diff lang="typescript"
102// src/Api.ts
103- return HttpServerResponse.text(`Requested ${request.url}`);
104+ if (request.url === "/api/health") {
105+ return yield* HttpServerResponse.json({ ok: true });
106+ }
107+ return HttpServerResponse.text("Not found", { status: 404 });
108```
109
110`/api/health` returns JSON; every other path returns HTTP 404.
111
112## Configure the health check
113
114```diff lang="typescript"
115// src/Api.ts
116 port: 3000,
117+ healthCheck: { path: "/api/health" },
118 destroyOldDeployment: true,
119```
120
121Prisma checks this route when starting the service. It verifies that the HTTP
122process is responding, independently of the database added in Part 3.
123
124## Deploy the API
125
126<Tabs syncKey="pkgManager">
127 <TabItem label="bun" icon="bun"><Code code="bun alchemy deploy" lang="sh" /></TabItem>
128 <TabItem label="npm" icon="npm"><Code code="npx alchemy deploy" lang="sh" /></TabItem>
129 <TabItem label="pnpm" icon="pnpm"><Code code="pnpm exec alchemy deploy" lang="sh" /></TabItem>
130 <TabItem label="yarn" icon="seti:yarn"><Code code="yarn alchemy deploy" lang="sh" /></TabItem>
131</Tabs>
132
133The deployment prints `apiUrl` for the Compute service.
134
135## Check the response
136
137```sh
138curl https://YOUR_API_HOST/api/health
139```
140
141Replace the host with `apiUrl`. The response should be `{"ok":true}`.
142Request `/missing` to check the 404 response, or use `curl -X POST` to check
143the 405 response.
144
145## Next
146
147[Part 3: Query Postgres](/prisma/tutorial/part-3) binds a database connection
148to the API and runs a real SQL query.