Skip to content

Instant REST API with halfORM

Think of the implications of these few lines of Python:

import sys
from half_orm.model import Model
dbname = sys.argv[1]
schemaname = sys.argv[2] 
relationname = sys.argv[3]
if __name__ == '__main__':
    Model(dbname).get_relation_class(f"{schemaname}.{relationname}")

We could use them to build an efficient universal REST API using FastAPI and halfORM. Let's begin!

The Concept

halfORM's database-first approach makes it trivial to create APIs. Since halfORM automatically discovers your database structure and generates relation classes on-the-fly, you can build a universal REST API that works with any PostgreSQL database.

From Concept to Production-Ready API

Let's see how the simple concept evolves into a secure, production-ready solution:

1. The Core Concept (3 lines)

# The essence: dynamic relation class creation
from half_orm.model import Model
relation_class = Model(db_name).get_relation_class(f"{schema}.{table}")
# Now you have a fully functional ORM class!

2. Add Security (Configuration Required)

# Security first: explicit configuration required
class SecureAPI:
    def __init__(self, db_name, config_file):
        if not Path(config_file).exists():
            raise ValueError("Configuration file required - no accidental exposure")
        self.config = self._load_config(config_file)
        self.model = Model(db_name)

3. Read-Only by Design

# Only safe operations exposed
@app.get("/{schema}/{relation}")
async def list_records(...):  # ✅ Safe read operation

@app.post("/{schema}/{relation}")  
async def create_record_not_allowed(...):  # ❌ Disabled for security
    raise HTTPException(405, "POST operations not allowed")

Security Model

🔒 Security-First Design

  • No configuration = No access - API refuses to expose any data without explicit configuration
  • Read-only by design - Only GET endpoints. No POST, PUT, or DELETE operations
  • Explicit column control - You must list exactly which columns to expose
  • No default exposures - Nothing is exposed unless explicitly configured

This approach makes the API safe for production environments where you need to expose specific database views to external consumers.

Quick Start

1. Install Dependencies

pip install half_orm fastapi uvicorn pyyaml

2. Generate Configuration by Database Introspection

The key innovation of this approach is automatic configuration generation. Instead of manually writing YAML, let halfORM discover your entire database schema:

# Introspect your database and generate complete configuration
python instant_api.py your_database --create-config

This creates a configuration file with every table and column in your database, all safely commented out:

# Configuration for your_database database
# Generated by introspection - uncomment lines to expose data

# blog:
#   author:
#     - id
#     - first_name
#     - last_name
#     - email
#     - bio
#     - created_at
#   post:
#     - id
#     - title
#     - content
#     - author_id
#     - published_at
#     - is_published

Real-world example:

# GitLab database introspection
python instant_api.py gitlab --create-config
# Result: 879 relations, 10,436 lines of configuration generated!

3. Configure What to Expose (Uncomment Lines)

Edit the generated file and uncomment only what you want to expose:

# Uncomment to expose specific data
blog:
  author:
    - id
    - first_name
    - last_name
    - email
    # - password_hash  # Keep sensitive data commented!
  post:
    - id
    - title
    - excerpt
    - published_at
    - view_count
    # - author_id      # Hide internal references

4. Start Your Secure API

python instant_api.py your_database

Output:

🚀 Starting Universal REST API for database: your_database
📋 Config directory: /etc/half_orm/instant_api
📋 Looking for: your_database.yml
🌐 API will be available at: http://127.0.0.1:8000
📖 API documentation at: http://127.0.0.1:8000/docs
✅ Read-only API starting...

Usage Examples

Explore Available Data

curl http://localhost:8000/

Response:

{
  "database": "blog_tutorial",
  "exposed_relations": ["blog.author", "blog.post"],
  "available_endpoints": [
    "GET /{schema}/{relation} - List records (read-only)",
    "GET /{schema}/{relation}/{id} - Get one record (read-only)"
  ],
  "note": "Only read operations are available for security reasons"
}

List Records with Filtering

# Basic listing
curl http://localhost:8000/blog/author

# Advanced filtering with halfORM operators
curl "http://localhost:8000/blog/author?first_name=Alice"
curl "http://localhost:8000/blog/post?view_count__gt=50&is_published=true"
curl "http://localhost:8000/blog/author?email__like=gmail"

# Pagination and ordering
curl "http://localhost:8000/blog/post?limit=5&offset=10&order_by=published_at DESC"

Supported filter operators: - field=value - Exact match - field__gt=value - Greater than - field__gte=value - Greater than or equal - field__lt=value - Less than - field__lte=value - Less than or equal - field__ne=value - Not equal - field__like=value - Pattern matching (case-insensitive) - field__isnull=true/false - NULL/NOT NULL checks

Get Single Record

curl http://localhost:8000/blog/author/1

Response:

{
  "id": 1,
  "first_name": "Alice",
  "last_name": "Johnson",
  "email": "alice@example.com"
}

Write Operations Are Blocked

# All write operations return HTTP 405
curl -X POST http://localhost:8000/blog/author -d '{"name":"Test"}'
# → {"detail": "POST operations are not allowed. This is a read-only API for security reasons."}

curl -X PUT http://localhost:8000/blog/author/1 -d '{"email":"new@email.com"}'
# → {"detail": "PUT operations are not allowed. This is a read-only API for security reasons."}

curl -X DELETE http://localhost:8000/blog/author/1
# → {"detail": "DELETE operations are not allowed. This is a read-only API for security reasons."}

Real-World Use Cases

1. Exploring Complex Existing Databases

Perfect for large, existing databases where you don't know the full schema:

# Discover what's in that legacy database
python instant_api.py legacy_erp --create-config
# Result: Complete overview of hundreds of tables

# Expose only safe, read-only data
vim /etc/half_orm/instant_api/legacy_erp.yml
# Uncomment only public-facing tables

python instant_api.py legacy_erp --port 8001
# Safe API for legacy data exploration

2. GitLab Database Analysis

Real example with GitLab's complex schema:

$ python instant_api.py gitlab --create-config
# ✅ 879 relations discovered automatically
# ✅ 10,436 lines of configuration generated  
# ✅ Every table and column catalogued

# Edit to expose only what you need:
$ vi gitlab.yml
$ grep -v '^#' gitlab.yml 

public:
  members:
    - source_id
    - source_type
    - user_id
  projects:
    - id
    - name
    - path
    - description
    - creator_id
  users:
    - id
    - name
    - admin

# Run the service
$ python install_api.py gitlab

API Features

Automatic Documentation

Visit http://localhost:8000/docs for interactive OpenAPI documentation with: - Description of all available routes - Try it out functionality for all endpoints - Request/response schemas - Filter parameter documentation - Example requests and responses

Error Handling

Clear, helpful error messages:

curl http://localhost:8000/blog/nonexistent
# → {"detail": "Relation blog.nonexistent not exposed"}

curl http://localhost:8000/blog/author/999
# → {"detail": "Record 999 not found"}

Performance Features

  • Efficient queries using halfORM's lazy evaluation
  • Pagination to handle large datasets gracefully
  • Column selection to minimize data transfer
  • Database connection pooling support

Why This Approach Works

halfORM's Introspection Power

  1. Database-First: Your PostgreSQL schema drives everything
  2. Complete Discovery: Uses halfORM's model._relations() and relation._ho_fields
  3. Zero Errors: All table and column names are exactly correct
  4. No Guesswork: See your entire database structure instantly

Security Model

  1. Everything Hidden by Default: All 10,000+ lines start commented
  2. Explicit Exposure: You must actively uncomment to expose data
  3. Granular Control: Column-level precision - expose only what you need
  4. Audit Trail: Configuration file shows exactly what's exposed
  5. No Accidents: Impossible to accidentally expose sensitive data

Practical Benefits

  1. Works with Any PostgreSQL Database: Legacy, modern, complex - doesn't matter
  2. Handles Scale: GitLab's 879 relations processed effortlessly
  3. Maintenance Friendly: Regenerate config when schema changes
  4. Developer Friendly: See everything, choose what to expose
  5. Production Safe: Battle-tested security-first approach

Example: E-commerce Database

Imagine you have an existing e-commerce database with 50+ tables:

-- Complex existing database
CREATE SCHEMA inventory;
CREATE SCHEMA orders;
CREATE SCHEMA users;
CREATE SCHEMA analytics;

-- 50+ tables with sensitive data
CREATE TABLE users.customers (id, email, password_hash, credit_card, ...);
CREATE TABLE orders.transactions (id, amount, payment_details, ...);
CREATE TABLE inventory.products (id, name, cost, profit_margin, supplier_info, ...);

Traditional approach: Write hundreds of lines of endpoint code, worry about security

halfORM approach:

# 1. Create secure configuration (expose only public data)
echo "
inventory:
  products:
    - id
    - name
    - category
    - public_price
analytics:
  daily_stats:
    - date
    - total_sales
    - order_count
" > api_config.yml

# 2. Start secure API
python instant_api.py ecommerce_db

Result: Secure read-only API exposing only the public product catalog and aggregate statistics from 50+ tables!

Advanced Configuration

Environment-Specific Configs

# production_api_config.yml - Minimal exposure
public:
  products:
    - id
    - name
    - price

# development_api_config.yml - More detailed for testing  
public:
  products:
    - id
    - name
    - price
    - category
    - description
    - created_at

Schema-Level Security

# Only specific schemas exposed
partner_data:    # Partner-specific schema
  shared_products:
    - id
    - name
    - availability

# Internal schemas (users, orders, etc.) not listed = not accessible

Production Considerations

This example demonstrates the core concept of instant API generation with halfORM. For production use, you'll want to consider:

Basic Production Setup

# Environment variables for production
export INSTANT_API_CONF_DIR=/etc/instant-api
export INSTANT_API_PORT=8001
export INSTANT_API_HOST=127.0.0.1

# Run with custom port
python instant_api.py production_db --port 8001 --host 127.0.0.1

Community Contributions Welcome! 🤝

This instant API example shows halfORM's potential for rapid API development. The community could help evolve this into production-ready solutions:

🚀 Contribution Ideas

halfORM-API-Server - A dedicated project could include:

  • Authentication & Authorization - JWT, OAuth2, API keys
  • Rate limiting - Prevent abuse and ensure fair usage
  • Caching layer - Redis integration for high-performance APIs
  • API versioning - Support multiple API versions
  • Advanced filtering - GraphQL-style query capabilities
  • Batch operations - Bulk insert/update endpoints
  • Real-time features - WebSocket support for live data
  • Monitoring & metrics - Prometheus/Grafana integration
  • Auto-documentation - Enhanced OpenAPI specs with examples
  • Testing framework - Automated API testing tools

halfORM-CLI-Tools - Command-line utilities:

  • Database introspection - Generate API configs from existing schemas
  • Performance analysis - Query optimization suggestions
  • Migration helpers - Sync API configs with schema changes
  • Deployment tools - Docker, Kubernetes, systemd templates

halfORM-Admin - Web-based administration:

  • Visual configuration - GUI for creating API configurations
  • Real-time monitoring - Dashboard for API health and usage
  • User management - Role-based access control
  • API analytics - Usage patterns and performance metrics

🛠️ How to Contribute

  1. Fork the concept - Create your own enhanced version
  2. Share improvements - Submit PRs for core functionality
  3. Create integrations - Build plugins for popular frameworks
  4. Write documentation - Help others adopt halfORM for APIs
  5. Report use cases - Share your production experiences

💡 Project Ideas

  • halfORM-GraphQL - GraphQL server generator
  • halfORM-gRPC - Protocol Buffers / gRPC integration
  • halfORM-Serverless - AWS Lambda / Azure Functions deployment
  • halfORM-Streaming - Apache Kafka / message queue integration
  • halfORM-Microservices - Service mesh integration patterns

📞 Get Involved

The halfORM community thrives on practical, database-first solutions. Your contributions can help others build amazing APIs with minimal code!

Conclusion

This example demonstrates halfORM's core philosophy: let the database drive the application, but with security first. With minimal code, you get:

  • Secure read-only API for any PostgreSQL database
  • Mandatory configuration prevents accidental data exposure
  • Column-level control for precise data governance
  • Following halfORM conventions with INSTANT_API_CONF_DIR
  • Production basics - port configuration and security headers
  • Self-documenting with OpenAPI integration

The few lines mentioned at the beginning can power a secure API foundation that's ready for community enhancement!

Get Started

  1. Download the example: instant_api.py

  2. Discover your database structure:

    python instant_api.py your_database --create-config
    

  3. Configure what to expose (uncomment lines in the generated file):

    vim /etc/half_orm/instant_api/your_database.yml
    

  4. Start your secure API:

    python instant_api.py your_database --port 8001
    

  5. Test and iterate - Add more data by uncommenting more lines!

The power of halfORM: From any PostgreSQL database to a secure REST API in minutes, not hours! 🔒🚀


This example showcases halfORM's database introspection capabilities. The community can help evolve it into production-ready solutions for authentication, caching, monitoring, and more. Contributions welcome!

Conclusion

This example demonstrates halfORM's core philosophy: let the database drive the application, but with security first. With minimal code, you get:

  • Secure read-only API for any PostgreSQL database
  • Mandatory configuration prevents accidental data exposure
  • Column-level control for precise data governance
  • Production-ready FastAPI foundation with OpenAPI docs
  • Zero maintenance - works with schema changes automatically

The few lines mentioned at the beginning truly can power a secure, production-ready API infrastructure!

Get Started

  1. Download the complete code: instant_api.py
  2. Create your configuration to expose only what you need
  3. Test with your database: python instant_api.py your_database_name
  4. Deploy safely knowing write operations are disabled by design

Safe, simple, and effective - the halfORM way! 🔒🚀