| app | ||
| docs | ||
| examples | ||
| test_fix | ||
| .gitignore | ||
| change_port.sh | ||
| check_port_config.sh | ||
| cookies.txt | ||
| example.env | ||
| fix_env_port_dynamic.sh | ||
| fix_missing_port.sh | ||
| fix_port_immediate.sh | ||
| fix_remove_backslashes.sh | ||
| fix_service_env_vars.sh | ||
| fix_service_port.sh | ||
| fix_vps_complete.sh | ||
| fix_vps_issues.sh | ||
| fix_waitress_port.sh | ||
| install.sh | ||
| LICENSE | ||
| main.py | ||
| README.md | ||
| requirements.txt | ||
| run_dev.py | ||
| test_run.py | ||
| 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 settingsExample
.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 -
Initialize the database (tables are created automatically on first run).
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:
- 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=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"
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
3. Changing Port Configuration
If you need to change the port MockAPI runs on (e.g., due to port conflicts), you have two options:
Option A: Using the Change Port Script (Recommended)
# Download the script if not already present
cd /opt/mockapi
sudo wget -O change_port.sh https://raw.githubusercontent.com/your-repo/main/change_port.sh
sudo chmod +x change_port.sh
# Run the script
sudo bash change_port.sh
The script will:
- Show current port configuration
- Ask for new port number
- Update
.envfile - Update systemd service file
- Update OAuth2 issuer URL
- Restart the service
Option B: Manual Port Change
If you prefer to change the port manually:
-
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 -
Edit the systemd service file:
sudo nano /etc/systemd/system/mockapi.serviceUpdate the
ExecStartline:ExecStart=/opt/mockapi/venv/bin/waitress-serve --host=0.0.0.0 --port=8080 wsgi:wsgi_app -
Reload systemd and restart:
sudo systemctl daemon-reload sudo systemctl restart mockapi sudo systemctl status mockapi -
Verify the change:
curl http://localhost:8080/health
Important Notes:
- The port in
.envand service file must match - After changing port, update any reverse proxy configurations
- OAuth2 clients may need reconfiguration if issuer URL changes
Checking Current Configuration: To verify your port configuration is consistent, use the check script:
cd /opt/mockapi
sudo wget -O check_port_config.sh https://raw.githubusercontent.com/your-repo/main/check_port_config.sh
sudo chmod +x check_port_config.sh
sudo bash check_port_config.sh
The script will:
- Show current port settings from
.envand service file - Check for consistency between files
- Verify service is running and listening on correct port
- Test health endpoint
- Provide recommendations if issues are found
4. 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;
}
}
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
- 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) not exposed in admin UI
- 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.