alepha@docs:~/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(z.object({12 id: z.text(),13 name: z.text(),14 email: z.text()15 })),16 total: z.number()17 })18 },19 handler: async ({ query }) => {20 const users = await this.userService.findUsers(query);21 return { users: users.items, total: users.total };22 }23 });24 25 createUser = $action({26 method: "POST",27 path: "/users",28 schema: {29 body: z.object({30 name: z.text(),31 email: z.text({ format: "email" })32 }),33 response: z.object({ id: z.text(), name: z.text() })34 },35 handler: async ({ body }) => {36 return await this.userService.create(body);37 }38 });39}