alepha@docs:~/framework/docs/reference/primitives$
cat $action.md | pretty2 min read
#$action
#Import
typescript
1import { $action } from "alepha/server";
#Overview
Creates a server action primitive for defining type-safe HTTP endpoints.
Server actions are the core building blocks for REST APIs in Alepha, providing declarative HTTP endpoints with full type safety, automatic validation, and OpenAPI documentation.
Key Features
- Full TypeScript inference for request/response types
- Automatic schema validation using Zod
- An explicit method and path on every action, no convention to remember
- Direct invocation (
run()) or HTTP requests (fetch()) - Built-in authentication and authorization support
- Automatic content-type handling (JSON, form-data, plain text)
URL Generation
Important: All $action paths are automatically prefixed with /api.
ts
1$action({ method: "GET", path: "/users" }); // → GET /api/users2$action({ method: "GET", path: "/users/:id" }); // → GET /api/users/:id3$action({ method: "POST", path: "/hello" }); // → POST /api/hello
This prefix is configurable via the serverApiOptions atom
(alepha.store.mut(serverApiOptions, (o) => ({ ...o, prefix: "/v1" }))).
method and path are both required: a read declares method: "GET", and
renaming the property never moves the URL.
Common Use Cases
- CRUD operations with type safety
- File upload and download endpoints
- Microservice communication
#Options
| Option | Type | Required | Description |
|---|---|---|---|
name |
string |
No | Name of the action |
group |
string |
No | Group actions together |
path |
string |
Yes | Pathname of the route, below the API prefix (/api by default) |
method |
RouteMethod |
Yes | The route method |
schema |
TConfig |
No | The config schema of the route |
description |
string |
No | A short description of the action |
disabled |
boolean |
No | Disable the route |
use |
TUse |
No | Middlewares wrapping the handler, outermost first |
errors |
TErrors |
No | The errors this action answers with: $error constants or built-in HttpError classes (NotFoundError) |
timeout |
DurationLike | false |
No | How long the action may run before it answers 503 with a TimeoutError |
handler |
ServerActionHandler<TConfig, TUse> |
Yes | Main route handler |
#Examples
ts
1class UserController { 2 getUsers = $action({ 3 method: "GET", 4 path: "/users", 5 schema: { 6 query: z.object({ 7 page: z.number().default(1).optional(), 8 limit: z.number().default(10).optional(), 9 }),10 response: z.object({11 users: z.array(12 z.object({13 id: z.text(),14 name: z.text(),15 email: z.text(),16 }),17 ),18 total: z.number(),19 }),20 },21 handler: async ({ query }) => {22 const users = await this.userService.findUsers(query);23 return { users: users.items, total: users.total };24 },25 });26 27 createUser = $action({28 method: "POST",29 path: "/users",30 schema: {31 body: z.object({32 name: z.text(),33 email: z.text({ format: "email" }),34 }),35 response: z.object({ id: z.text(), name: z.text() }),36 },37 handler: async ({ body }) => {38 return await this.userService.create(body);39 },40 });41}