ESC

Type to search...

Quick Start

Build a working EVOID API in 5 minutes.

Prerequisites

  • Python 3.13 or higher
  • uv (recommended) or pip

Step 1: Create a Project

uv add evoid
evo init my-api
cd my-api

Step 2: Add a Service

evo service new api

This creates services/api/main.py.

Step 3: Write Your First Endpoint

Edit services/api/main.py:

from evoid.web.route import Service, get, post

app = Service("my-api")

@get("/")
async def home() -> dict:
    return {"message": "Hello from EVOID!"}

@get("/users/{user_id}")
async def get_user(user_id: int) -> dict:
    return {"id": user_id, "name": f"User {user_id}"}

@post("/users")
async def create_user(name: str, email: str) -> dict:
    return {"status": "created", "name": name}

Step 4: Run the Server

evo service run api

You should see:

Starting my-api on http://0.0.0.0:8000

Step 5: Test It

# Home
curl http://localhost:8000/
# {"message": "Hello from EVOID!"}

# Get user
curl http://localhost:8000/users/123
# {"id": 123, "name": "User 123"}

# Create user
curl -X POST http://localhost:8000/users?name=Ali&email=ali@example.com
# {"status": "created", "name": "Ali"}

Behind the scenes, EVOID:

  1. Created Intents — Each decorator (@get, @post) created an Intent automatically. @get("/users/{user_id}") became Intent(name="GET:/users/{user_id}", level=Level.STANDARD)
  2. Registered Processors — Your functions were wrapped as processors and registered by intent name
  3. Set Up ASGI — An ASGI server was started to handle HTTP requests
  4. Configured Routing — URLs were mapped to Intents. When a request arrives, EVOID resolves the intent, builds a pipeline, and executes it

Three decorators handled all of that. That’s IOP — you declare what you want, EVOID handles how.

Adding Protection Levels

Change the protection level per route:

@get("/public/data", level="ephemeral")
async def public_data() -> dict:
    return {"data": "cache me"}

@get("/users/{id}", level="standard")
async def get_user(id: int) -> dict:
    return {"id": id}

@post("/payments", level="critical")
async def process_payment(amount: float) -> dict:
    return {"status": "paid"}

Each level maps to a different pipeline — ephemeral gets fast validation only, critical gets full audit and protection.