Part 2: Run a Program
Run a program in its own Archil sandbox, with PUT /:key and GET /:key
routes that store files on the disk from Part 1.
The finished code is
examples/archil-sandbox.
Create the program
Section titled “Create the program”An Archil.Sandbox with main runs your program.
main: import.meta.url makes this file both the bundle and the program,
and the program listens on port 3000:
import * as Archil from "@alchemy.run/archil";import * as Effect from "effect/Effect";import * as HttpServerResponse from "effect/http/HttpServerResponse";
export default class Api extends Archil.Sandbox<Api>()( "Api", { main: import.meta.url, port: 3000 }, Effect.gen(function* () { return { fetch: Effect.succeed(HttpServerResponse.text("hello")), }; }),) {}Bind the disk
Section titled “Bind the disk”Archil.ReadWriteDisk(Files) gives the program its own S3 user on that
disk, so it can read and write that disk and nothing else:
import * as Archil from "@alchemy.run/archil";import * as Effect from "effect/Effect";import * as HttpServerResponse from "effect/http/HttpServerResponse";import { Files } from "./Storage.ts";
export default class Api extends Archil.Sandbox<Api>()( "Api", { main: import.meta.url, port: 3000 }, Effect.gen(function* () { const files = yield* Archil.ReadWriteDisk(Files); return { fetch: Effect.succeed(HttpServerResponse.text("hello")), }; }), }).pipe(Effect.provide(Archil.ReadWriteDiskHttp)),) {}Write files with PUT /:key
Section titled “Write files with PUT /:key”Read the key from the path and put the request body on the disk:
import { HttpServerRequest } from "effect/http/HttpServerRequest";
return { fetch: Effect.succeed(HttpServerResponse.text("hello")), fetch: Effect.gen(function* () { const request = yield* HttpServerRequest; const key = new URL(request.url, "http://api").pathname.slice(1); if (request.method === "PUT") { const body = yield* request.text; yield* files.put(key, body); return HttpServerResponse.empty({ status: 201 }); } const text = yield* files.getText(key); return HttpServerResponse.text(text); }), };Answer 404 for missing files
Section titled “Answer 404 for missing files”head returns undefined when the file doesn’t exist:
return HttpServerResponse.empty({ status: 201 }); } const file = yield* files.head(key); if (file === undefined) { return HttpServerResponse.text("not found", { status: 404 }); } const text = yield* files.getText(key);Turn other errors into 500s
Section titled “Turn other errors into 500s” return HttpServerResponse.text(text); }), }).pipe( Effect.catch((error) => Effect.succeed(HttpServerResponse.text(String(error), { status: 500 })), ), ),Wire the program into the Stack
Section titled “Wire the program into the Stack”import Api from "./src/Api.ts";import { Files } from "./src/Storage.ts";
Effect.gen(function* () { const files = yield* Files; return { diskId: files.diskId }; const api = yield* Api; return { diskId: files.diskId, url: api.url }; }),Deploy
Section titled “Deploy”pnpm alchemy deploybun alchemy deploynpx alchemy deployyarn alchemy deployurl is https://3000-<id>.<region>.archil.app.
Try it out
Section titled “Try it out”curl -X PUT --data "hello archil" "$URL/notes/first.txt"curl "$URL/notes/first.txt"The second command prints hello archil. Leave the program alone for a
few minutes and the sandbox stops; the next request starts it again.
The sandbox runs your Effect program and reads and writes the disk through its own S3 user. In Part 3 you’ll test it.