Part 2: An HTTP API
Continue from Part 1. The Project exists, but it has no public endpoint yet. Add a Compute service that runs an Effect HTTP handler on Prisma’s Bun runtime.
Define the Compute service
Section titled “Define the Compute service”Create src/Api.ts:
import * as Prisma from "alchemy/Prisma";import * as Effect from "effect/Effect";import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse";import { Project } from "./Database.ts";
export default class Api extends Prisma.Compute<Api>()( "Api", Effect.gen(function* () { const project = yield* Project; return { project, main: import.meta.filename, regionId: "eu-west-3", branchGitName: "main", port: 3000, destroyOldDeployment: true, }; }), Effect.gen(function* () { return { fetch: Effect.succeed(HttpServerResponse.text("Hello from Prisma")) }; }),) {}Prisma.Compute bundles the handler into a Bun archive and deploys it without
a Dockerfile. main points to the file that default-exports this class.
The Project already owns the main branch, so select it by branchGitName.
Register the API
Section titled “Register the API”import Api from "./src/Api.ts";
Effect.gen(function* () { const project = yield* Project; const api = yield* Api; return { projectId: project.projectId }; return { projectId: project.projectId, apiUrl: api.url }; }),The API depends on the same Project definition. Yielding it from both files still creates only one Project in this Stack.
Read the incoming request
Section titled “Read the incoming request”import { HttpServerRequest } from "effect/unstable/http/HttpServerRequest";
Effect.gen(function* () { return { fetch: Effect.succeed(HttpServerResponse.text("Hello from Prisma")) }; return { fetch: Effect.gen(function* () { const request = yield* HttpServerRequest; return HttpServerResponse.text(`Requested ${request.url}`); }), }; }),Each HTTP request receives its own Effect request context.
Restrict the HTTP method
Section titled “Restrict the HTTP method” const request = yield* HttpServerRequest; if (request.method !== "GET") { return HttpServerResponse.text("Method not allowed", { status: 405, headers: { allow: "GET" }, }); } return HttpServerResponse.text(`Requested ${request.url}`);This read-only API rejects writes with HTTP 405.
Add a health route
Section titled “Add a health route” return HttpServerResponse.text(`Requested ${request.url}`); if (request.url === "/api/health") { return yield* HttpServerResponse.json({ ok: true }); } return HttpServerResponse.text("Not found", { status: 404 });/api/health returns JSON; every other path returns HTTP 404.
Configure the health check
Section titled “Configure the health check” port: 3000, healthCheck: { path: "/api/health" }, destroyOldDeployment: true,Prisma checks this route when starting the service. It verifies that the HTTP process is responding, independently of the database added in Part 3.
Deploy the API
Section titled “Deploy the API”bun alchemy deploynpx alchemy deploypnpm exec alchemy deployyarn alchemy deployThe deployment prints apiUrl for the Compute service.
Check the response
Section titled “Check the response”curl https://YOUR_API_HOST/api/healthReplace the host with apiUrl. The response should be {"ok":true}.
Request /missing to check the 404 response, or use curl -X POST to check
the 405 response.
Part 3: Query Postgres binds a database connection to the API and runs a real SQL query.