Rohas uses a declarative schema language (.ro files) to define your application's structure. Schemas define models, APIs, events, cron jobs, and inputs in a type-safe, code-generatable format.
Schema files use the .ro extension and are organized by type:
schema/ ├── models/ # Data models ├── api/ # API endpoints ├── events/ # Event definitions ├── cron/ # Scheduled jobs └── websockets/ # WebSocket endpoints
Models define reusable data structures used throughout your application.
Location: schema/models/
Syntax:
model User { id Int @id @auto name String email String @unique createdAt DateTime @default(now) posts Post[] }
Field Types:
String - Text dataInt - Integer numbersFloat - Floating-point numbersBoolean - True/false valuesDateTime - Date and timeJson - JSON dataModel[] - Arrays of modelsAttributes:
@id - Primary key@auto - Auto-increment@unique - Unique constraint@default(value) - Default value@optional - Optional fieldExample:
model Post { id Int @id @auto title String content String authorId Int author User createdAt DateTime @default(now) published Boolean @default(false) }
Inputs define Data Transfer Objects for API requests.
Location: schema/api/ (alongside API definitions)
Syntax:
input CreateUserInput { name: String email: String password: String }
Usage:
api CreateUser { method: POST path: "/users" body: CreateUserInput response: User }
APIs define HTTP endpoints with request/response types.
Location: schema/api/
Syntax:
api GetUser { method: GET path: "/users/:id" response: User } api CreateUser { method: POST path: "/users" body: CreateUserInput response: User triggers: [UserCreated] }
HTTP Methods:
GET - Retrieve dataPOST - Create dataPUT - Update data (full)PATCH - Update data (partial)DELETE - Delete dataPath Parameters:
Use :param syntax for path parameters:
api GetUser { method: GET path: "/users/:id" response: User }
Query Parameters: Query parameters are automatically extracted and passed to handlers.
Request Body:
Use body to specify the request body type:
api CreateUser { method: POST path: "/users" body: CreateUserInput response: User }
Response Types:
response: Userresponse: { id: Int, name: String }Event Triggers: APIs can trigger events after execution:
api CreateUser { method: POST path: "/users" body: CreateUserInput response: User triggers: [UserCreated, WelcomeEmailSent] }
Middlewares: Specify middleware functions:
api ProtectedAPI { method: GET path: "/protected" response: Data middlewares: ["auth", "rateLimit"] }
Events define event types that can be published and consumed.
Location: schema/events/
Syntax:
event UserCreated { payload: User handler: [send_welcome_email, update_analytics] triggers: [UserRegistered] }
Payload Types:
payload: Userpayload: { userId: Int, name: String }Handlers: Specify handler functions that process the event:
event UserCreated { payload: User handler: [send_welcome_email, update_analytics, log_event] }
Event Chaining: Events can trigger other events:
event UserCreated { payload: User handler: [send_welcome_email] triggers: [UserRegistered, WelcomeEmailSent] }
Example:
event OrderPlaced { payload: Order handler: [process_payment, send_confirmation, update_inventory] triggers: [PaymentProcessed] } event PaymentProcessed { payload: Payment handler: [fulfill_order] }
Cron jobs define scheduled tasks that run on a schedule.
Location: schema/cron/
Syntax:
cron DailyCleanup { schedule: "0 0 * * *" triggers: [CleanupStarted] }
Schedule Format: Cron expressions use standard format:
┌───────────── minute (0 - 59) │ ┌───────────── hour (0 - 23) │ │ ┌───────────── day of month (1 - 31) │ │ │ ┌───────────── month (1 - 12) │ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday) │ │ │ │ │ * * * * *
Examples:
"0 0 * * *" - Daily at midnight"0 */6 * * *" - Every 6 hours"0 0 * * 0" - Weekly on Sunday"0 0 1 * *" - Monthly on the 1st"*/5 * * * *" - Every 5 minutesEvent Triggers: Cron jobs can trigger events:
cron DailyReport { schedule: "0 9 * * *" triggers: [ReportGenerated] }
WebSockets define real-time communication endpoints.
Location: schema/websockets/
Syntax:
ws Chat { path: "/ws/chat" message: ChatMessage onConnect: [on_connect_handler] onMessage: [on_message_handler] onDisconnect: [on_disconnect_handler] }
Message Types: Define the message structure:
input ChatMessage { type: String content: String userId: Int timestamp: DateTime }
Handlers:
onConnect - Called when client connectsonMessage - Called when message receivedonDisconnect - Called when client disconnectsString - Text dataInt - 32-bit integersFloat - Floating-point numbersBoolean - True/falseDateTime - Date and timeJson - JSON dataModel[] - Arrays of modelsString[] - Arrays of stringsUse ? to mark optional fields:
model User { id: Int name: String email: String? phone: String? }
Schema files should be named descriptively:
schema/api/user_api.roschema/events/user_events.roschema/models/user.roOrganize schemas logically:
schema/ ├── models/ │ ├── user.ro │ ├── post.ro │ └── comment.ro ├── api/ │ ├── user_api.ro │ └── post_api.ro ├── events/ │ ├── user_events.ro │ └── post_events.ro └── cron/ └── cleanup.ro
Validate schemas before generating code:
rohas validate
What's validated:
After defining schemas, generate code:
rohas codegen
This generates:
rohas validate frequently// schema/models/user.ro model User { id Int @id @auto name String email String @unique createdAt DateTime @default(now) } // schema/api/user_api.ro input CreateUserInput { name: String email: String } api CreateUser { method: POST path: "/users" body: CreateUserInput response: User triggers: [UserCreated] } api GetUser { method: GET path: "/users/:id" response: User } // schema/events/user_events.ro event UserCreated { payload: User handler: [send_welcome_email] }