Quick Start¶
This guide will walk you through creating your first RestMachine application and deploying it with various servers.
Create Your First API¶
1. Install RestMachine¶
2. Create app.py¶
from restmachine import RestApplication
app = RestApplication()
@app.get('/')
def home():
return {"message": "Welcome to RestMachine!"}
@app.get('/hello/{name}')
def hello(path_params):
name = path_params['name']
return {"message": f"Hello, {name}!"}
@app.post('/echo')
def echo(json_body):
return {"you_sent": json_body}
3. Test Locally¶
You can test your application directly without a server:
from restmachine import Request, HTTPMethod
# Test GET
request = Request(method=HTTPMethod.GET, path='/')
response = app.execute(request)
print(response.body) # {"message": "Welcome to RestMachine!"}
# Test with path params
request = Request(method=HTTPMethod.GET, path='/hello/World')
response = app.execute(request)
print(response.body) # {"message": "Hello, World!"}
Deploy with ASGI Servers¶
RestMachine includes built-in ASGI support for production deployment.
Option 1: Uvicorn (Recommended)¶
Add ASGI adapter to app.py:
from restmachine import RestApplication, ASGIAdapter
app = RestApplication()
@app.get('/')
def home():
return {"message": "Welcome to RestMachine!"}
# Create ASGI application
asgi_app = ASGIAdapter(app)
Run with Uvicorn:
# Development (with auto-reload)
uvicorn app:asgi_app --reload --host 0.0.0.0 --port 8000
# Production
uvicorn app:asgi_app --host 0.0.0.0 --port 8000 --workers 4
Test it:
curl http://localhost:8000/
# {"message": "Welcome to RestMachine!"}
curl http://localhost:8000/hello/RestMachine
# {"message": "Hello, RestMachine!"}
Option 2: Hypercorn (HTTP/2 Support)¶
Install:
Run with Hypercorn:
# Development
hypercorn app:asgi_app --reload --bind 0.0.0.0:8000
# Production with HTTP/2
hypercorn app:asgi_app --bind 0.0.0.0:8000 --workers 4
Option 3: Gunicorn + Uvicorn Workers¶
For production deployments with process management:
gunicorn app:asgi_app \
-w 4 \
-k uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:8000 \
--access-logfile - \
--error-logfile -
Deploy to AWS Lambda¶
RestMachine provides first-class support for AWS Lambda deployment.
1. Install AWS Package¶
2. Create lambda_handler.py¶
from restmachine import RestApplication
from restmachine_aws import AwsApiGatewayAdapter
app = RestApplication()
@app.get('/')
def home():
return {"message": "Welcome to RestMachine on Lambda!"}
@app.get('/hello/{name}')
def hello(path_params):
name = path_params['name']
return {"message": f"Hello, {name}!"}
# Create AWS Lambda adapter
adapter = AwsApiGatewayAdapter(app)
def lambda_handler(event, context):
return adapter.handle_event(event, context)
3. Package for Deployment¶
Create a deployment package:
# Create a virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install restmachine restmachine-aws
# Package the code
mkdir package
pip install --target ./package restmachine restmachine-aws
cd package
zip -r ../lambda_function.zip .
cd ..
zip lambda_function.zip lambda_handler.py
4. Deploy to AWS Lambda¶
Using AWS CLI:
# Create Lambda function
aws lambda create-function \
--function-name restmachine-api \
--runtime python3.11 \
--role arn:aws:iam::YOUR_ACCOUNT:role/lambda-execution-role \
--handler lambda_handler.lambda_handler \
--zip-file fileb://lambda_function.zip \
--timeout 30 \
--memory-size 512
5. Connect to API Gateway¶
Create API Gateway REST API:
aws apigatewayv2 create-api \
--name restmachine-api \
--protocol-type HTTP \
--target arn:aws:lambda:REGION:ACCOUNT:function:restmachine-api
Or create Function URL (simpler):
Supported Event Sources¶
The AWS adapter automatically detects and handles:
| Event Source | Format | Notes |
|---|---|---|
| API Gateway REST API | v1 (1.0) | Traditional REST APIs |
| API Gateway HTTP API | v2 (2.0) | Lower latency, cheaper |
| Application Load Balancer | ALB | Multi-value headers, mTLS |
| Lambda Function URLs | v2 | Simplest setup |
Add Startup & Shutdown Handlers¶
RestMachine supports lifecycle hooks for resource management:
from restmachine import RestApplication, ASGIAdapter
app = RestApplication()
# Startup handler (runs once when app starts)
@app.on_startup
def database():
print("Opening database connection...")
return create_db_connection()
# Use dependency injection
@app.get('/users')
def list_users(database): # 'database' injected from startup
return database.query("SELECT * FROM users")
# Shutdown handler (runs when app stops)
@app.on_shutdown
def close_database(database): # Can also inject dependencies
print("Closing database connection...")
database.close()
asgi_app = ASGIAdapter(app)
ASGI Deployment: Startup/shutdown handlers work automatically.
AWS Lambda: Startup handlers run during cold start. For shutdown handlers, see Lambda Extensions.
Generate OpenAPI Documentation¶
RestMachine automatically generates OpenAPI 3.0 specifications from your code:
from restmachine import RestApplication
from pydantic import BaseModel, EmailStr
app = RestApplication()
class UserCreate(BaseModel):
name: str
email: EmailStr
@app.validates
def user_create(json_body) -> UserCreate:
return UserCreate.model_validate(json_body)
@app.post('/users')
def create_user(user_create: UserCreate):
"""Create a new user account."""
return {"created": user_create.model_dump()}, 201
# Generate OpenAPI spec
openapi_json = app.generate_openapi_json(
title="My API",
version="1.0.0",
description="My awesome API"
)
# Or save to file
app.save_openapi_json(
filename="openapi.json",
docs_dir="docs"
)
Add Interactive Documentation¶
Serve Swagger UI for interactive API documentation:
@app.get('/openapi.json')
def openapi_spec():
"""OpenAPI specification endpoint."""
import json
return json.loads(app.generate_openapi_json(
title="My API",
version="1.0.0"
))
@app.get('/docs')
def swagger_ui():
"""Interactive API documentation."""
return """
<!DOCTYPE html>
<html>
<head>
<title>API Documentation</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css">
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js"></script>
<script>
SwaggerUIBundle({
url: '/openapi.json',
dom_id: '#swagger-ui',
});
</script>
</body>
</html>
"""
Visit http://localhost:8000/docs to see your interactive API documentation.
See the OpenAPI Guide for advanced features including client SDK generation.
Observability & Metrics¶
RestMachine includes built-in metrics collection to help you monitor your application's performance.
Default Behavior¶
AWS Lambda: Metrics are automatically enabled and published to CloudWatch Logs in EMF (Embedded Metric Format). No configuration required!
from restmachine_aws import AwsApiGatewayAdapter
# Metrics automatically enabled for CloudWatch
adapter = AwsApiGatewayAdapter(app)
ASGI/Other Platforms: Metrics collection is available but requires a custom publisher. See the Metrics documentation for details.
Adding Custom Metrics¶
Inject the metrics dependency to track business metrics:
@app.get('/orders')
def list_orders(metrics):
# Track request count
metrics.add_metric("orders.listed", 1, unit="Count")
# Track timing
metrics.start_timer("db.query")
orders = db.query("SELECT * FROM orders")
metrics.stop_timer("db.query")
return {"orders": orders}
What Gets Logged¶
All requests automatically include: - Total request time - Application execution time - Response conversion time - HTTP method and path - Status code
For more details: - Core Metrics Guide - Platform-agnostic metrics features - AWS CloudWatch Metrics - CloudWatch EMF configuration
Next Steps¶
Now that you have a running application:
- Basic Application → - Learn fundamental concepts
- Dependency Injection → - Master DI patterns
- Request Validation → - Add Pydantic validation
- Deployment Guide → - Production deployment strategies
Common Issues¶
Import Error: No module named 'restmachine'
Make sure you've installed RestMachine:
ASGI server not working
Ensure you've created the ASGI adapter:
And you're running the correct module:uvicorn app:asgi_app
Lambda function timing out
Increase the timeout in your Lambda configuration:
404 Not Found for all routes
Check that your API Gateway integration is configured correctly to proxy all requests to Lambda:
- Use {proxy+} as the resource path
- Enable "Lambda Proxy Integration"