mockapi/README.md
2026-03-16 09:00:26 +00:00

20 KiB
Raw Blame History

Configurable Mock API with Admin Interface and OAuth2 Provider

A lightweight, configurable mock API application in Python that allows dynamic endpoint management via an admin interface. The API serves customizable responses stored in a SQLite database with template variable support. Includes a full OAuth2 provider for securing endpoints with token-based authentication.

Features

  • Dynamic Endpoint Configuration: Create, read, update, and delete API endpoints through a web-based admin interface.
  • Template Variable Support: Response bodies can include Jinja2 template variables (e.g., {{ user_id }}, {{ timestamp }}) populated from path parameters, query strings, headers, request body, system variables, and endpoint defaults.
  • Dynamic Route Registration: Endpoints are registered/unregistered at runtime without restarting the server.
  • Admin Interface: Secure web UI with session-based authentication for managing endpoints.
  • OAuth2 Provider: Full OAuth2 implementation supporting authorization code, client credentials, and refresh token grant types.
  • EndpointLevel OAuth Protection: Individual endpoints can require OAuth2 tokens with configurable scopes.
  • Admin OAuth2 Management: Web UI for managing OAuth clients, tokens, and users.
  • OpenID Connect Discovery: Standardscompliant discovery endpoint.
  • Production Ready: Uses Waitress WSGI server, SQLAlchemy async, and FastAPI with proper error handling and security measures.

Technology Stack

  • Framework: FastAPI (with automatic OpenAPI documentation)
  • Server: Waitress (production WSGI server)
  • Database: SQLite with SQLAlchemy 2.0 async ORM
  • Templating: Jinja2 with sandboxed environment
  • Authentication: Sessionbased admin authentication with bcrypt password hashing
  • OAuth2: JWTbased tokens with configurable scopes, client validation, and token revocation
  • Frontend: Bootstrap 5 (CDN) for admin UI

Project Structure

mockapi/
├── app.py                 # FastAPI application factory & lifespan
├── config.py              # Configuration (Pydantic Settings)
├── database.py            # SQLAlchemy async database setup
├── dependencies.py        # FastAPI dependencies
├── example_usage.py       # Integration test & demonstration script
├── middleware/
│   └── auth_middleware.py # Admin authentication middleware
├── models/
│   ├── endpoint_model.py  # Endpoint SQLAlchemy model
│   └── oauth_models.py    # OAuth2 client, token, and user models
├── observers/
│   └── __init__.py        # Observer pattern placeholder
├── repositories/
│   ├── endpoint_repository.py # Repository pattern for endpoints
│   └── oauth2/            # OAuth2 repositories
├── run.py                 # Development runner script (with auto-reload)
├── services/
│   ├── route_service.py   # Dynamic route registration/management
│   └── template_service.py # Jinja2 template rendering
├── controllers/
│   ├── admin_controller.py # Admin UI routes
│   └── oauth2/            # OAuth2 controllers and services
├── schemas/
│   ├── endpoint_schema.py # Pydantic schemas for validation
│   └── oauth2/            # OAuth2 schemas
├── templates/             # Jinja2 HTML templates
│   ├── base.html          # Base layout
│   └── admin/
│       ├── login.html     # Login page
│       ├── dashboard.html # Admin dashboard
│       ├── endpoints.html # Endpoint list
│       ├── endpoint_form.html # Create/edit endpoint
│       └── oauth/         # OAuth2 management pages
├── static/
│   └── css/               # Static CSS (optional)
├── tests/                 # Test suite
│   ├── test_admin.py      # Admin authentication tests
│   ├── test_endpoint_repository.py
│   ├── test_route_manager_fix.py
│   ├── test_oauth2_controller.py
│   └── integration/       # Integration tests
├── utils/                 # Utility modules
│   └── __init__.py
├── requirements.txt       # Python dependencies
├── .env.example           # Example environment variables
├── .env                   # Local environment variables (create from .env.example)
├── run_example.sh         # Script to run the integration test
├── LICENSE                # MIT License
└── README.md              # This file

Installation

  1. Navigate to project directory:

    cd ~/GitLab/customer-engineering/mockapi
    
  2. Create a virtual environment (recommended):

    python3 -m venv venv
    source venv/bin/activate  # On Windows: venv\Scripts\activate
    
  3. Install dependencies:

    pip install -r requirements.txt
    
  4. Configure environment variables:

    cp .env.example .env
    # Edit .env with your settings
    

    Example .env:

    DATABASE_URL=sqlite+aiosqlite:///./mockapi.db
    ADMIN_USERNAME=admin
    ADMIN_PASSWORD=admin123           # Change this in production!
    SECRET_KEY=your-secret-key-here   # Change this!
    DEBUG=True                        # Set to False in production
    
  5. Initialize the database (tables are created automatically on first run).

Running the Application

Development (with autoreload)

Make sure your virtual environment is activated:

source venv/bin/activate  # Linux/macOS
# venv\Scripts\activate   # Windows

Then run with auto-reload for development:

# Using run.py (convenience script)
python run.py

# Or directly with uvicorn
uvicorn app:app --reload --host 0.0.0.0 --port 8000

Production (with Waitress)

For production deployment, use Waitress WSGI server with the provided WSGI adapter (a2wsgi):

waitress-serve --host=0.0.0.0 --port=8000 --threads=4 wsgi:wsgi_app

The server will start on http://localhost:8000 (or your configured host/port).

Note: Waitress is a WSGI server, but FastAPI is an ASGI framework. The wsgi.py file uses a2wsgi to wrap the ASGI application into a WSGI-compatible interface. Routes are automatically refreshed from the database on server startup.

Quick Start

1. Start the Server

# Development (auto-reload)
python run.py

# Or directly with uvicorn
uvicorn app:app --reload --host 0.0.0.0 --port 8000

# Production (with Waitress)
waitress-serve --host=0.0.0.0 --port=8000 --threads=4 wsgi:wsgi_app

The server will start on http://localhost:8000 (or your configured host/port).

2. Test Basic Functionality

# Health check
curl http://localhost:8000/health

# Access Swagger UI (auto-generated docs)
open http://localhost:8000/docs

3. Use API Testing Collections

Ready-to-use API collections are available in the examples/ directory:

Collection Format Description
Bruno mockapi-collection.bru Bruno collection with scripting support
Postman mockapi-postman-collection.json Postman Collection v2.1

Both collections include:

  • Global variables (base URL, credentials, tokens)
  • Full OAuth2 flow testing (client credentials, authorization code, refresh)
  • Mock endpoint CRUD operations
  • Admin authentication
  • Protected endpoint examples

Setup:

# Create test OAuth client
./examples/setup.sh

# Or manually
python examples/setup-test-client.py

Import:

  • Bruno: Drag and drop .bru file or use "Import Collection"
  • Postman: Use "Import" button and select JSON file

See examples/README.md for detailed usage.

4. Basic cURL Examples (Quick Reference)

# Admin login (sets session cookie)
curl -c cookies.txt -X POST http://localhost:8000/admin/login \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=admin&password=admin123"

# Create a simple mock endpoint
curl -b cookies.txt -X POST http://localhost:8000/admin/endpoints \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "route=/api/test&method=GET&response_body={\"message\":\"test\"}&response_code=200&content_type=application/json&is_active=true"

# Call the endpoint
curl http://localhost:8000/api/test

# OAuth2 client credentials grant (using test client)
curl -X POST http://localhost:8000/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=test_client&client_secret=test_secret&scope=api:read"

For comprehensive testing with all OAuth2 flows and examples, use the provided API collections.

OAuth2 Authentication

The application includes a full OAuth2 provider implementing RFC 6749 and OpenID Connect Discovery.

Supported Grant Types

  • Authorization Code: For web applications with serverside components.
  • Client Credentials: For machinetomachine communication.
  • Refresh Token: To obtain new access tokens without user interaction.

Endpoints

Endpoint Method Description
/oauth/authorize GET, POST Authorization endpoint (interactive user consent)
/oauth/token POST Token issuance and refresh
/oauth/userinfo GET OpenID Connect user claims
/oauth/introspect POST Token introspection (RFC 7662)
/oauth/revoke POST Token revocation (RFC 7009)
/.wellknown/openidconfiguration GET OpenID Connect discovery document

Scope Management

Default scopes include:

  • openid OpenID Connect support
  • profile Basic profile information
  • email Email address claim
  • api:read Read access to protected endpoints
  • api:write Write access to protected endpoints

Admin OAuth2 Management

Access OAuth2 management via the admin interface:

  • Clients: http://localhost:8000/admin/oauth/clients Register and manage OAuth clients
  • Tokens: http://localhost:8000/admin/oauth/tokens View and revoke issued tokens
  • Users: http://localhost:8000/admin/oauth/users Manage OAuth user records

Production Deployment Considerations

1. Environment Configuration

  • Set DEBUG=False in production
  • Use strong, unique values for ADMIN_PASSWORD and SECRET_KEY
  • Consider using a more robust database (PostgreSQL) by changing DATABASE_URL
  • Store sensitive values in environment variables or a secrets manager

2. Process Management

Use a process manager like systemd (Linux) or Supervisor to keep the application running:

Example systemd service (/etc/systemd/system/mockapi.service):

[Unit]
Description=Mock API Service
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/mockapi
Environment="PATH=/path/to/mockapi/venv/bin"
ExecStart=/path/to/mockapi/venv/bin/waitress-serve --host=0.0.0.0 --port=8000 wsgi:wsgi_app
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Use Nginx or Apache as a reverse proxy for SSL termination, load balancing, and static file serving:

Example Nginx configuration:

server {
    listen 80;
    server_name api.yourdomain.com;
    
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

4. Database Backups

For SQLite, regularly backup the mockapi.db file. For production, consider migrating to PostgreSQL.

Usage

1. Access the Admin Interface

  • Open http://localhost:8000/admin/login
  • Log in with the credentials set in .env (default: admin / admin123)

2. Create a Mock Endpoint

  1. Navigate to EndpointsCreate New.
  2. Fill in the form:
    • Route: /api/greeting/{name} (supports path parameters)
    • Method: GET
    • Response Body: { "message": "Hello, {{ name }}!" }
    • Response Code: 200
    • Content-Type: application/json
    • Variables: { "server": "mock-api" } (optional defaults)
  3. Click Create.

3. Call the Mock Endpoint

curl http://localhost:8000/api/greeting/World

Response:

{ "message": "Hello, World!" }

4. Template Variables

The following variable sources are available in response templates:

Source Example variable Usage in template
Path parameters {{ name }} /users/{id}{{ id }}
Query parameters {{ query.page }} ?page=1{{ page }}
Request headers {{ header.authorization }} Authorization: Bearer token
Request body {{ body.user.email }} JSON request body
System variables {{ timestamp }}, {{ request_id }} Automatically injected
Endpoint defaults {{ server }} Defined in endpoint variables

5. Admin Functions

  • List endpoints with pagination and filtering
  • Edit existing endpoints (changes take effect immediately)
  • Activate/deactivate endpoints without deletion
  • Delete endpoints (removes route)
  • Dashboard with statistics (total endpoints, active routes, etc.)
  • OAuth2 management clients, tokens, users

Security Considerations

  • Admin authentication: Uses bcrypt password hashing. Store a strong password hash in production.
  • Session management: Signed cookies with configurable secret key.
  • Template sandboxing: Jinja2 environment restricted with SandboxedEnvironment and StrictUndefined.
  • Request size limits: Maximum body size of 1MB to prevent DoS.
  • Route validation: Prevents path traversal (..) and other unsafe patterns.
  • SQL injection protection: All queries use SQLAlchemy ORM.
  • OAuth2 security: Client secret hashing, token revocation, scope validation, secure token storage.

Configuration Options

See config.py for all available settings. Key environment variables:

Variable Default Description
DATABASE_URL sqlite+aiosqlite:///./mockapi.db SQLAlchemy database URL
ADMIN_USERNAME admin Admin login username
ADMIN_PASSWORD admin123 Admin login password (plaintext)
SECRET_KEY yoursecretkeyherechangeme Session signing secret
DEBUG False Enable debug mode (more logging, relaxed validation)
OAUTH2_ISSUER http://localhost:8000 OAuth2 issuer URL for discovery
OAUTH2_ACCESS_TOKEN_EXPIRE_MINUTES 30 Access token lifetime
OAUTH2_REFRESH_TOKEN_EXPIRE_DAYS 7 Refresh token lifetime
OAUTH2_SUPPORTED_SCOPES ["openid","profile","email","api:read","api:write"] Available OAuth2 scopes

Warning: In production (DEBUG=False), the default ADMIN_PASSWORD and SECRET_KEY will cause validation errors. You must set unique values via environment variables.

API Documentation

FastAPI automatically provides OpenAPI documentation at:

  • Swagger UI: http://localhost:8000/docs
  • ReDoc: http://localhost:8000/redoc

The root URL (/) automatically redirects to the Swagger documentation at /docs.

The dynamic mock endpoints are not listed in the OpenAPI schema (they are registered at runtime).

Development & Testing

API Testing Collections

Ready-to-use API collections are available in the examples/ directory:

Bruno Collection (mockapi-collection.bru)

  • Format: Bruno native format (.bru)
  • Features: Scripting support, environment variables, folder organization
  • Import: Drag and drop into Bruno or use "Import Collection"

Postman Collection (mockapi-postman-collection.json)

  • Format: Postman Collection v2.1
  • Features: Pre-request scripts, tests, environment variables
  • Import: Import into Postman via "Import" button

Quick setup:

# Create test OAuth client and view instructions
./examples/setup.sh

# Or import directly:
# examples/mockapi-collection.bru (Bruno)
# examples/mockapi-postman-collection.json (Postman)

Both collections include:

  • Global variables for base URL and credentials
  • Pre-configured requests for all endpoints
  • OAuth2 flow examples (client credentials, authorization code, refresh)
  • Admin authentication
  • Mock endpoint creation and testing
  • Protected endpoint examples

See examples/README.md for detailed usage instructions.

Running Tests

Run tests with pytest:

pytest tests/

The test suite includes:

  • Unit tests for repository and service layers
  • Integration tests for admin authentication
  • Template rendering tests
  • OAuth2 unit and integration tests (21+ tests)

Example Integration Test

A readytorun integration test demonstrates the core functionality:

# Make the script executable (Linux/macOS)
chmod +x run_example.sh

# Run the example
./run_example.sh

Or directly with Python:

python example_usage.py

The example script will:

  1. Start the FastAPI app (via TestClient)
  2. Log in as admin
  3. Create a mock endpoint with template variables
  4. Call the endpoint and verify the response
  5. Report success or failure

This is a great way to verify that the API is working correctly after installation.

Troubleshooting

Common Issues

  1. "no such table: endpoints" error

    • The database hasn't been initialized
    • Restart the application - tables are created on first startup
    • Or run python -c "from database import init_db; import asyncio; asyncio.run(init_db())"
  2. Login fails even with correct credentials

    • Check that DEBUG=True is set in .env (or provide unique credentials)
    • The default credentials only work when DEBUG=True
    • In production, you must set unique ADMIN_PASSWORD and SECRET_KEY
  3. Routes not being registered

    • Check that the endpoint is marked as active (is_active=True)
    • Refresh the page - routes are registered immediately after creation
    • Check application logs for errors
  4. Template variables not rendering

    • Ensure you're using double curly braces: {{ variable }}
    • Check variable names match the context (use path_, query_, header_ prefixes as needed)
    • View the rendered template in the admin edit form preview
  5. OAuth2 token validation fails

    • Verify the token hasn't expired
    • Check that the client is active
    • Confirm the token has required scopes for the endpoint
    • Ensure the token hasn't been revoked

Logging

Enable debug logging by setting DEBUG=True in .env. Check the console output for detailed error messages.

Limitations & Future Enhancements

  • Current limitations:

    • SQLite only (but can be extended to PostgreSQL via DATABASE_URL)
    • Single admin user (no multiuser support)
    • No request logging/history
    • OAuth2 protection fields (requires_oauth, oauth_scopes) not exposed in admin UI
    • OAuth2 user authentication uses placeholder user IDs (integration with external identity providers pending)
  • Possible extensions:

    • Import/export endpoints as JSON/YAML
    • Request logging and analytics
    • WebSocket notifications for admin actions
    • Multiple admin users with roles
    • Rate limiting per endpoint
    • CORS configuration
    • PKCE support for public OAuth2 clients
    • Integration with external identity providers (SAML, LDAP)

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments