- Add HOST, PORT, LOG_LEVEL, and OAuth2 settings to example.env - Update README to reference example.env for complete configuration - Ensure users have all required variables for production deployment |
||
|---|---|---|
| app | ||
| docs | ||
| examples | ||
| .gitignore | ||
| example.env | ||
| install.sh | ||
| LICENSE | ||
| main.py | ||
| README.md | ||
| requirements.txt | ||
| uninstall.sh | ||
| wsgi.py | ||
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.
- Endpoint‑Level 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: Standards‑compliant 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: Session‑based admin authentication with bcrypt password hashing
- OAuth2: JWT‑based tokens with configurable scopes, client validation, and token revocation
- Frontend: Bootstrap 5 (CDN) for admin UI
Project Structure
mockapi/
├── main.py # Development entry point (uvicorn with reload)
├── wsgi.py # Production WSGI entry point (Waitress/Gunicorn)
├── app/ # Main application package
│ ├── core/ # Core application setup
│ │ ├── app.py # FastAPI application factory & lifespan
│ │ ├── config.py # Configuration (Pydantic Settings)
│ │ ├── database.py # SQLAlchemy async database setup
│ │ ├── dependencies.py # FastAPI dependencies
│ │ ├── middleware/ # Middleware (authentication, etc.)
│ │ └── observers/ # Observer pattern placeholder
│ ├── modules/ # Feature modules
│ │ ├── admin/ # Admin UI controllers & templates
│ │ ├── endpoints/ # Endpoint management (models, repositories, services, schemas)
│ │ └── oauth2/ # OAuth2 provider (controllers, models, repositories, schemas)
│ ├── static/ # Static assets (CSS, etc.)
│ └── templates/ # Jinja2 HTML templates
│ ├── base.html # Base layout
│ └── admin/ # Admin interface templates
├── requirements.txt # Python dependencies
├── example.env # Example environment variables
├── .env # Local environment variables (create from example.env)
├── docs/ # Project documentation
├── examples/ # API testing collections and examples
├── 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
├── LICENSE # MIT License
└── README.md # This file
Installation
-
Navigate to project directory:
cd ~/GitLab/customer-engineering/mockapi -
Create a virtual environment (recommended):
python3 -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate -
Install dependencies:
pip install -r requirements.txt -
Configure environment variables:
cp example.env .env # Edit .env with your settings (see example.env for all available variables)Minimal
.envexample: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 productionThe
example.envfile includes additional configuration options for OAuth2, logging, and server settings. -
Initialize the database (tables are created automatically on first run).
For production deployment, consider using the automated install.sh script which handles virtual environment creation, dependency installation, secure credential generation, and systemd service setup. See Production Deployment with install.sh for details.
Running the Application
Development (with auto‑reload)
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 main.py (development entry point)
python main.py
# Or directly with uvicorn
uvicorn main: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 main.py
# Or directly with uvicorn
uvicorn main: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
.brufile 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 server‑side components.
- Client Credentials: For machine‑to‑machine 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) |
/.well‑known/openid‑configuration |
GET | OpenID Connect discovery document |
Scope Management
Default scopes include:
openid– OpenID Connect supportprofile– Basic profile informationemail– Email address claimapi:read– Read access to protected endpointsapi:write– Write access to protected endpoints
Admin OAuth2 Management
Access OAuth2 management via the admin interface navigation (OAuth dropdown):
- 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
Admin UI Navigation: The admin interface now includes an "OAuth" dropdown menu in the top navigation bar with direct access to Clients, Tokens, and Users management pages.
Production Deployment Considerations
1. Environment Configuration
- Set
DEBUG=Falsein production - Use strong, unique values for
ADMIN_PASSWORDandSECRET_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"
EnvironmentFile=/path/to/mockapi/.env
# HOST and PORT are read from .env file at runtime
ExecStart=/path/to/mockapi/venv/bin/waitress-serve --host=$HOST --port=$PORT wsgi:wsgi_app
Restart=always
RestartSec=10
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/path/to/mockapi
[Install]
WantedBy=multi-user.target
Note: The install.sh script automatically creates an optimized systemd service file with dynamic port configuration, security hardening, and proper environment variable loading from .env.
3. Production Deployment with install.sh
For production deployments, use the provided install.sh script which handles all setup automatically:
cd /opt/mockapi
sudo ./install.sh
The install script will:
- Check Python version and handle Python 3.13+ compatibility
- Create Python virtual environment with required dependencies
- Generate secure credentials (admin password, secret key)
- Create
.envconfiguration file with all required variables - Initialize the database
- Create and configure systemd service with dynamic port configuration
- Start and enable the service
Key Features:
- Python 3.13.5+ compatibility: Automatically handles SQLAlchemy 2.0.27+ requirements
- Dynamic port configuration: Service reads HOST/PORT from
.envfile at runtime - Secure credential generation: Random admin password and secret key
- Missing variable protection: Automatically adds required environment variables if missing
4. Changing Port Configuration
Port configuration is now simplified - all settings are read from the .env file:
-
Edit the
.envfile:sudo nano /opt/mockapi/.envUpdate these lines:
PORT=8080 # Change to your desired port HOST=0.0.0.0 # Or change host if needed OAUTH2_ISSUER=http://localhost:8080 # Update to match new port -
Restart the service:
sudo systemctl restart mockapi -
Verify the change:
curl http://localhost:8080/health
Important Notes:
- The systemd service automatically reads HOST and PORT from
.envfile at runtime - No need to edit the service file when changing ports
- After changing port, update any reverse proxy configurations
- OAuth2 clients may need reconfiguration if issuer URL changes
5. Reverse Proxy (Recommended)
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;
}
}
6. 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
- Navigate to Endpoints → Create New.
- 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)
- Route:
- 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
SandboxedEnvironmentandStrictUndefined. - 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 |
your‑secret‑key‑here‑change‑me |
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 ready‑to‑run 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:
- Start the FastAPI app (via TestClient)
- Log in as admin
- Create a mock endpoint with template variables
- Call the endpoint and verify the response
- Report success or failure
This is a great way to verify that the API is working correctly after installation.
Troubleshooting
Common Issues
-
"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())"
-
Login fails even with correct credentials
- Check that
DEBUG=Trueis set in.env(or provide unique credentials) - The default credentials only work when
DEBUG=True - In production, you must set unique
ADMIN_PASSWORDandSECRET_KEY
- Check that
-
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
- Check that the endpoint is marked as active (
-
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
- Ensure you're using double curly braces:
-
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 multi‑user support)
- No request logging/history
- OAuth2 protection fields (requires_oauth, oauth_scopes) for endpoints not exposed in admin UI (though OAuth client/token/user management is available via navigation dropdown)
- OAuth2 user authentication uses placeholder user IDs (integration with external identity providers pending)
- SQLite only (but can be extended to PostgreSQL via
-
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
- Built with FastAPI, SQLAlchemy, and Jinja2.
- Admin UI uses Bootstrap 5 via CDN.
- OAuth2 implementation follows RFC 6749, RFC 7662, and OpenID Connect standards.