aion-cli
v1.0.0
Published
Zero-boilerplate API development platform
Maintainers
Readme
AION CLI
Zero-Boilerplate API Development Platform
Write your API once. Get everything else free.
AION is a schema-first API development platform that generates TypeScript types, API routes, client SDKs, documentation, mock servers, and more from a single .aion file.
✨ Features
- 🚀 Zero Boilerplate - Write schema once, generate everything
- 📝 Type-Safe - Full TypeScript support with auto-generated types
- 🔄 Auto-Generated Code - Routes, clients, validators, docs
- 🎯 Mock Server - Instant backend with realistic fake data
- 📚 Interactive Docs - Beautiful API documentation with playground
- 🔗 Relationships - First-class support for entity relationships
- ✅ Validation - Built-in request/response validation with Zod
- 🎨 Developer Experience - Simple, intuitive schema language
🚀 Quick Start
Installation
npm install -g aion-cliCreate Your First API
# Initialize a new project
aion init my-api
# Navigate to the project
cd my-api
# Start the mock server
aion mock schema.aion
# Visit http://localhost:3000/docsExample Schema
Create a file called schema.aion:
api UserService(version: 1.0.0) {
entity User {
id: @uuid(generated)
email: @email(unique, indexed)
name: @string(min: 2, max: 100)
age: @int(min: 18, optional)
role: @enum("admin", "user", "guest") default: "user"
created_at: @timestamp(auto)
}
endpoints {
POST /users {
body: User(email, name, age?, role?)
returns: User
}
GET /users {
returns: User[]
}
GET /users/:id {
returns: User
}
}
}Generate Code
# Generate TypeScript code
aion generate schema.aion -o ./generated
# What you get:
# ✓ TypeScript types
# ✓ Express routes
# ✓ Client SDK
# ✓ Zod validators
# ✓ All fully typed!📖 CLI Commands
aion init
Initialize a new AION project with a template.
aion init <project-name> [options]
Options:
-t, --template <name> Template to use (basic, blog, ecommerce)
Examples:
aion init my-api
aion init blog-api --template blogaion generate
Generate code from an AION schema.
aion generate <schema> [options]
Options:
-o, --output <dir> Output directory (default: ./generated)
-t, --target <target> Target language (typescript)
--no-validators Skip generating validators
--no-docs Skip generating documentation
Examples:
aion generate schema.aion
aion generate schema.aion -o ./src/generatedaion mock
Start a mock API server with realistic fake data.
aion mock <schema> [options]
Options:
-p, --port <port> Port number (default: 3000)
-d, --delay <ms> Response delay in ms (default: 0)
--no-cors Disable CORS
Examples:
aion mock schema.aion
aion mock schema.aion --port 8080 --delay 500The mock server includes:
- ✓ Realistic fake data with Faker.js
- ✓ Full CRUD operations
- ✓ Relationship population
- ✓ Interactive documentation at
/docs - ✓ Schema introspection at
/api/schema
aion docs
Generate static API documentation.
aion docs <schema> [options]
Options:
-o, --output <file> Output HTML file (default: docs.html)
-s, --serve Serve documentation locally
-p, --port <port> Port for local server (default: 8080)
-b, --base-url <url> Base URL for API
Examples:
aion docs schema.aion
aion docs schema.aion --serve
aion docs schema.aion -o api-docs.htmlaion validate
Validate an AION schema file.
aion validate <schema> [options]
Options:
--verbose Show detailed validation info
Examples:
aion validate schema.aion
aion validate schema.aion --verbose📚 AION Language Reference
File Structure
Every .aion file follows this structure:
api ServiceName(version: X.Y.Z) {
// Entity definitions
entity EntityName {
// fields...
}
// API endpoints
endpoints {
// routes...
}
}Type System
| Type | Description | Example |
|------|-------------|---------|
| @string | UTF-8 text | @string(min: 2, max: 100) |
| @int | 32-bit integer | @int(min: 0, max: 100) |
| @float | 64-bit float | @float(precision: 2) |
| @bool | Boolean | @bool |
| @uuid | UUID v4 | @uuid(generated) |
| @email | Validated email | @email(unique, indexed) |
| @url | Validated URL | @url(protocol: "https") |
| @date | ISO 8601 date | @date |
| @timestamp | ISO 8601 datetime | @timestamp(auto) |
| @enum | Enumeration | @enum("active", "inactive") |
| @currency | Money with currency | @currency("USD", precision: 2) |
Field Modifiers
| Modifier | Description | Example |
|----------|-------------|---------|
| optional | Field is not required | age: @int(optional) |
| unique | Unique constraint | email: @email(unique) |
| indexed | Create index | email: @email(indexed) |
| generated | Auto-generated | id: @uuid(generated) |
| auto | Auto-timestamp | created_at: @timestamp(auto) |
Constraints
| Constraint | Applies To | Example |
|------------|------------|---------|
| min | string, int, float | @string(min: 2) |
| max | string, int, float | @string(max: 100) |
| precision | float, currency | @float(precision: 2) |
| pattern | string | @string(pattern: "^[A-Z]") |
Relationships
Belongs To (Many-to-One)
entity Post {
id: @uuid(generated)
title: @string(max: 200)
author: -> User // Post belongs to User
}Generates:
interface Post {
id: UUID;
title: string;
author_id: UUID; // Foreign key
author?: User; // Populated object
}Has Many (One-to-Many)
entity User {
id: @uuid(generated)
name: @string(max: 100)
posts: <- Post[] // User has many Posts
}Generates:
interface User {
id: UUID;
name: string;
posts?: Post[]; // Related posts
}Endpoints
endpoints {
// Create
POST /users {
body: User(email, name, age?)
returns: User
errors: {
400: "Invalid input"
409: "Email already exists"
}
@rate_limit("10/minute")
@auth("required")
}
// Read all
GET /users {
returns: User[]
}
// Read one
GET /users/:id {
returns: User
}
// Update
PUT /users/:id {
body: User(name, age)
returns: User
}
// Delete
DELETE /users/:id {
returns: User
}
}🎯 Complete Examples
Simple Task API
api TaskAPI(version: 1.0.0) {
entity Task {
id: @uuid(generated)
title: @string(min: 1, max: 200)
completed: @bool default: false
created_at: @timestamp(auto)
}
endpoints {
POST /tasks {
body: Task(title)
returns: Task
}
GET /tasks {
returns: Task[]
}
PATCH /tasks/:id {
body: Task(title?, completed?)
returns: Task
}
DELETE /tasks/:id {
returns: Task
}
}
}Blog API with Relationships
api BlogAPI(version: 1.0.0) {
entity User {
id: @uuid(generated)
email: @email(unique, indexed)
name: @string(min: 2, max: 100)
role: @enum("admin", "author", "reader") default: "reader"
created_at: @timestamp(auto)
posts: <- Post[]
comments: <- Comment[]
}
entity Post {
id: @uuid(generated)
title: @string(min: 5, max: 200)
content: @string(min: 10)
published: @bool default: false
created_at: @timestamp(auto)
author: -> User
comments: <- Comment[]
}
entity Comment {
id: @uuid(generated)
content: @string(min: 1, max: 500)
created_at: @timestamp(auto)
post: -> Post
author: -> User
}
endpoints {
POST /users {
body: User(email, name, role?)
returns: User
}
POST /posts {
body: Post(title, content, author_id, published?)
returns: Post
@auth("required")
}
GET /posts {
returns: Post[]
}
GET /posts/:id {
returns: Post
}
POST /posts/:postId/comments {
body: Comment(content, author_id)
returns: Comment
@auth("required")
}
GET /posts/:postId/comments {
returns: Comment[]
}
}
}E-commerce API
api EcommerceAPI(version: 1.0.0) {
entity Product {
id: @uuid(generated)
name: @string(min: 2, max: 200)
description: @string(max: 1000)
price: @float(min: 0, precision: 2)
stock: @int(min: 0)
category: @enum("electronics", "clothing", "food", "other")
created_at: @timestamp(auto)
}
entity Order {
id: @uuid(generated)
total: @float(min: 0, precision: 2)
status: @enum("pending", "processing", "shipped", "delivered")
customer_email: @email
created_at: @timestamp(auto)
}
endpoints {
GET /products {
returns: Product[]
}
POST /products {
body: Product(name, description, price, stock, category)
returns: Product
@auth("admin")
}
POST /orders {
body: Order(total, status, customer_email)
returns: Order
}
GET /orders/:id {
returns: Order
@auth("required")
}
}
}🔧 Integration with Existing Projects
Using Generated Code
// Import generated types and routes
import { User, CreateUserInput } from './generated/types';
import { router } from './generated/routes';
import { UserSchema } from './generated/validators';
// Use in your Express app
import express from 'express';
const app = express();
app.use('/api', router);
app.listen(3000);Using the Client SDK
import { UserServiceClient } from './generated/client';
const client = new UserServiceClient({
baseURL: 'http://localhost:3000',
headers: {
'Authorization': 'Bearer token'
}
});
// Fully typed API calls
const user = await client.createUser({
email: '[email protected]',
name: 'John Doe'
});
const users = await client.getUsers();🎨 What Gets Generated
From a single .aion file, you get:
1. TypeScript Types (types.ts)
export interface User {
id: UUID;
email: Email;
name: string;
age?: number;
role: UserRole;
created_at: Timestamp;
}
export type UserRole = "admin" | "user" | "guest";2. Express Routes (routes.ts)
router.post('/users', async (req, res) => {
const body = req.body as CreateUserRequest;
const validationResult = UserSchema.safeParse(body);
if (!validationResult.success) {
return res.status(400).json({
error: 'Validation failed',
details: validationResult.error.errors
});
}
// Your handler logic here
});3. Client SDK (client.ts)
export class UserServiceClient {
async createUser(data: CreateUserInput): Promise<User> {
return this.request('POST', '/users', data);
}
async getUsers(): Promise<User[]> {
return this.request('GET', '/users');
}
}4. Validators (validators.ts)
export const UserSchema = z.object({
email: z.string().email(),
name: z.string().min(2).max(100),
age: z.number().int().min(18).optional(),
role: z.enum(["admin", "user", "guest"]).optional()
});🏗️ Best Practices
1. Use Auto-Generated Fields
entity User {
id: @uuid(generated) // Auto-generate UUID
created_at: @timestamp(auto) // Auto-set on creation
updated_at: @timestamp(auto) // Auto-update on modification
}2. Set Reasonable Constraints
entity User {
name: @string(min: 2, max: 100) // Prevent empty or excessive names
age: @int(min: 0, max: 150) // Reasonable age range
email: @email(unique) // Ensure valid, unique emails
}3. Use Enums for Fixed Values
// Bad
status: @string
// Good
status: @enum("draft", "published", "archived")4. Define Clear Relationships
entity Post {
author: -> User // Post belongs to User
}
entity User {
posts: <- Post[] // User has many Posts
}5. Document with Comments
entity Order {
// Total includes tax and shipping
total: @float(min: 0, precision: 2)
// Status workflow: pending -> processing -> shipped -> delivered
status: @enum("pending", "processing", "shipped", "delivered")
}🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
MIT © AION Team
🔗 Links
🙏 Acknowledgments
Built with:
- Commander.js - CLI framework
- Chalk - Terminal styling
- Zod - Schema validation
- Faker.js - Mock data generation
- Express - Web framework
Made with ❤️ by the AION Team
Write your API once. Get everything else free.
