MantisBase v0.3.4
Loading...
Searching...
No Matches
REST API Reference Guide

MantisBase provides auto-generated RESTful APIs for interacting with database entities. This document covers the entity endpoints, schema management, realtime (SSE) API for live database change notifications (SQLite and PostgreSQL), and request handling.


🌐 Base URL

When MantisBase is running locally:

http://localhost:7070/api/v1/

You can configure the port and host using command-line arguments:

mantisbase serve -p 8000 -h 127.0.0.1

📄 Entity Endpoints

MantisBase automatically exposes CRUD endpoints for each entity (table or view):

Method Endpoint Description
GET /api/v1/entities/<entity> List all records
GET /api/v1/entities/<entity>/:id Get a specific record
POST /api/v1/entities/<entity> Create a new record
PATCH /api/v1/entities/<entity>/:id Update partial fields
DELETE /api/v1/entities/<entity>/:id Delete a record

Example Requests

# List all users
curl http://localhost:7070/api/v1/entities/users
# Get specific user
curl http://localhost:7070/api/v1/entities/users/123
# Create a new user
curl -X POST http://localhost:7070/api/v1/entities/users \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"name": "John Doe", "email": "john@example.com"}'
# Update user
curl -X PATCH http://localhost:7070/api/v1/entities/users/123 \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"name": "Jane Doe"}'
# Delete user
curl -X DELETE http://localhost:7070/api/v1/entities/users/123 \
-H "Authorization: Bearer <token>"

🔐 Authentication

All entity endpoints require authentication via JWT tokens. Include the token in the Authorization header:

Authorization: Bearer <token>

For authentication endpoints, see Authentication API.


🛡️ Middlewares

Middlewares are functions that run before your route handler, allowing you to add authentication, authorization, and request processing logic.

Default Middlewares

Every endpoint automatically has two middlewares applied globally:

  1. **getAuthToken()** - Extracts JWT token from Authorization header and stores it in request context
  2. **hydrateContextData()** - Validates token, fetches user data from database, and populates request context with user information

Additionally, entity endpoints automatically have:

  1. **hasAccess(entity_name)** - Evaluates entity access rules to determine if the authenticated user can perform the requested operation. Called automatically by entity endpoints to confirm access rules before data query.

Available Middlewares

You can use these middlewares when creating custom endpoints:

Middleware Description Usage
getAuthToken() Extract token from Authorization header Applied globally to all routes
hydrateContextData() Validate token and load user data Applied globally to all routes
hasAccess(entity_name) Check entity access rules Applied automatically to entity endpoints
requireAdminAuth() Require admin authentication Blocks non-admin users
requireEntityAuth(entity_name) Require authentication from specific entity Only allows users from specified entity table
requireAdminOrEntityAuth(entity_name) Require admin OR entity auth Allows admins or users from specified entity
requireGuestOnly() Require no authentication Blocks authenticated users, only allows guests
requireExprEval(expr) Evaluate custom expression Custom expression-based access control
rateLimit(max_requests, window_seconds, use_user_id) Rate limiting middleware Limits requests per time window by IP or user ID

Using Middlewares

When creating custom endpoints, you can specify middlewares as the third parameter:

// Require admin authentication
router.Get("/api/v1/admin/stats", [](MantisRequest& req, MantisResponse& res) {
res.sendJSON(200, {{"stats", "data"}});
// Require authentication from specific entity
router.Get("/api/v1/users/profile", [](MantisRequest& req, MantisResponse& res) {
auto auth = req.getOr<json>("auth", json::object());
std::string userId = auth["id"];
// ... return user profile
}, {requireEntityAuth("users")});
// Allow admins OR users from specific entity
router.Get("/api/v1/posts/draft", [](MantisRequest& req, MantisResponse& res) {
// ... return draft posts
}, {requireAdminOrEntityAuth("users")});
// Guest-only endpoint (no authentication required)
router.Get("/api/v1/public/info", [](MantisRequest& req, MantisResponse& res) {
res.sendJSON(200, {{"info", "public data"}});
// Custom expression evaluation
router.Get("/api/v1/restricted", [](MantisRequest& req, MantisResponse& res) {
// ... handler
}, {requireExprEval("auth.id != \"\" && auth.user.verified == true")});
// Rate limiting by IP address (100 requests per minute)
router.Get("/api/v1/data", [](MantisRequest& req, MantisResponse& res) {
res.sendJSON(200, {{"data", "response"}});
}, {rateLimit(100, 60, false)});
// Rate limiting by user ID (10 requests per second)
router.Post("/api/v1/upload", [](MantisRequest& req, MantisResponse& res) {
// ... handler
}, {rateLimit(10, 1, true)});
// Multiple middlewares (executed in order)
router.Post("/api/v1/sensitive", [](MantisRequest& req, MantisResponse& res) {
// ... handler
}, {
requireExprEval("req.body.priority <= 5")
});
std::function< HandlerResponse(MantisRequest &, MantisResponse &)> rateLimit(int max_requests, int window_seconds, bool use_user_id=false)
Rate limiting middleware to prevent abuse.
Definition middlewares.cpp:404
std::function< HandlerResponse(MantisRequest &, MantisResponse &)> requireAdminOrEntityAuth(const std::string &entity_name)
Require admin OR entity authentication.
Definition middlewares.cpp:371
std::function< HandlerResponse(MantisRequest &, MantisResponse &)> requireGuestOnly()
Require guest-only access (no authentication).
Definition middlewares.cpp:282
std::function< HandlerResponse(MantisRequest &, MantisResponse &)> requireExprEval(const std::string &expr)
Require expression evaluation to pass.
Definition middlewares.cpp:274
std::function< HandlerResponse(MantisRequest &, MantisResponse &)> requireAdminAuth()
Require admin authentication.
Definition middlewares.cpp:299
std::function< HandlerResponse(MantisRequest &, MantisResponse &)> requireEntityAuth(const std::string &entity_name)
Require entity-specific authentication.
Definition middlewares.cpp:381
nlohmann::json json
Shorten JSON namespace.
Definition context_store.h:18

Accessing User Data in Handlers

After middlewares run, you can access authenticated user data from the request context:

router.Get("/api/v1/me", [](MantisRequest& req, MantisResponse& res) {
// Get auth data from context (set by middlewares)
auto auth = req.getOr<json>("auth", json::object());
if (auth["type"] == "guest") {
res.sendJSON(401, {{"error", "Not authenticated"}});
return;
}
// Access user information
std::string userId = auth["id"];
std::string userEntity = auth["entity"];
json userData = auth["user"]; // Full user record from database
res.sendJSON(200, {{"user", userData}});
});

Note: Middlewares execute in the order they are specified. If a middleware returns HandlerResponse::Handled, subsequent middlewares and the handler are skipped.

</blockquote>

🗃️ Schema Management API

Schema management endpoints allow you to create, read, update, and delete entity schemas. These endpoints require admin authentication only.

Method Endpoint Description
GET /api/v1/schemas List all schemas
GET /api/v1/schemas/:schema_name_or_id Get a specific schema
POST /api/v1/schemas Create a new schema
PATCH /api/v1/schemas/:schema_name_or_id Update a schema
DELETE /api/v1/schemas/:schema_name_or_id Delete a schema

Example: Create a Schema

Base Entity (Standard Table):

curl -X POST http://localhost:7070/api/v1/schemas \
-H "Authorization: Bearer <admin_token>" \
-H "Content-Type: application/json" \
-d '{
"name": "posts",
"type": "base",
"fields": [
{"name": "title", "type": "string", "required": true},
{"name": "content", "type": "string"},
{"name": "author_id", "type": "string", "required": true}
],
"rules": {
"list": {"mode": "public", "expr": "auth.id != \"\""},
"get": {"mode": "auth", "expr": ""},
"add": {"mode": "auth", "expr": ""},
"update": {"mode": "auth", "expr": ""},
"delete": {"mode": "custom", "expr": "auth.entity == \"mb_admins\""}
}
}'

View Entity (SQL View):

curl -X POST http://localhost:7070/api/v1/schemas \
-H "Authorization: Bearer <admin_token>" \
-H "Content-Type: application/json" \
-d '{
"name": "published_posts",
"type": "view",
"view_query": "SELECT * FROM posts WHERE status = '\''published'\''",
"rules": {
"list": {"mode": "public", "expr": ""},
"get": {"mode": "public", "expr": ""}
}
}'

Auth Entity (Authentication Table):

curl -X POST http://localhost:7070/api/v1/schemas \
-H "Authorization: Bearer <admin_token>" \
-H "Content-Type: application/json" \
-d '{
"name": "users",
"type": "auth",
"fields": [
{"name": "email", "type": "string", "required": true, "is_unique": true},
{"name": "full_name", "type": "string"}
],
"rules": {
"list": {"mode": "auth", "expr": ""},
"get": {"mode": "auth", "expr": ""},
"add": {"mode": "public", "expr": ""},
"update": {"mode": "custom", "expr": "auth.id == req.body.id"},
"delete": {"mode": "", "expr": ""}
}
}'

Entity Types

MantisBase supports three entity types:

Type Description Fields Special Properties
base Standard database table Yes Standard CRUD operations
auth Authentication entity Yes Includes password, email, and user management fields automatically
view SQL view (read-only) No Requires view_query instead of fields

Entity Name Validation

Entity names must follow these rules:

  • Alphanumeric and underscores only - Only letters, numbers, and _ characters allowed
  • Maximum 64 characters - Names cannot exceed 64 characters
  • Not empty - Names must contain at least one character

Invalid names will be rejected with a 400 error.

Updating Schemas

When updating a schema, you can add, update, or remove fields:

curl -X PATCH http://localhost:7070/api/v1/schemas/posts \
-H "Authorization: Bearer <admin_token>" \
-H "Content-Type: application/json" \
-d '{
"fields": [
{"name": "new_field", "type": "string"}, // Add new field
{"id": "field_id_123", "type": "text"}, // Update existing field by ID
{"id": "old_field_id", "op": "delete"} // Remove field
]
}'

Field Operations:

  • Add: Include a field with a name that doesn't exist
  • Update: Include a field with an existing id
  • Delete: Include a field with an existing id and "op": "delete" or "op": "remove"

‍⚠️ Admin Only: All schema endpoints require admin authentication. Regular users cannot access these endpoints.

</blockquote>

🎛️ Query Parameters [PENDING]

Future support for filtering, sorting, and pagination:

GET /api/v1/entities/tasks?status=done&limit=10&offset=20&sort=-created_at

⚙️ Custom Endpoints

You can create custom API endpoints using the router:

router.Get("/api/v1/custom", [](MantisRequest& req, MantisResponse& res) {
res.sendJSON(200, {{"message", "Custom endpoint"}});

Check the Embedding Guide for more details.


📁 File Handling

Files uploaded via multipart/form-data are stored and can be accessed at:

GET /api/files/<entity>/<filename>

See File Handling for more details.


🔍 Entity Types and Validation

Entity Types

MantisBase supports three types of entities:

Base Entities

Standard database tables with fields. Use for most data storage needs.

{
"name": "posts",
"type": "base",
"fields": [
{"name": "title", "type": "string", "required": true},
{"name": "content", "type": "string"}
]
}

Auth Entities

Authentication entities with built-in password and user management fields. Automatically includes:

  • password - Hashed password field
  • email - Email field (typically unique)
  • Standard user management fields
{
"name": "users",
"type": "auth",
"fields": [
{"name": "email", "type": "string", "required": true, "is_unique": true},
{"name": "full_name", "type": "string"}
]
}

View Entities

SQL views based on queries. Read-only, no fields defined. Use view_query instead of fields.

{
"name": "published_posts",
"type": "view",
"view_query": "SELECT * FROM posts WHERE status = 'published'"
}

Entity Name Validation

All entity names are automatically validated to prevent SQL injection and ensure consistency:

Validation Rules:

  • ✅ Alphanumeric characters and underscores only (a-z, A-Z, 0-9, _)
  • ✅ Maximum 64 characters
  • ✅ Not empty

Invalid Examples:

  • my-table (contains hyphen)
  • my table (contains space)
  • my@table (contains special character)
  • Names longer than 64 characters

Invalid names will result in a 400 Bad Request error with a descriptive message.

Foreign Key Relationships

Foreign keys allow you to establish relationships between entities. When creating or updating schemas with foreign key fields, MantisBase automatically validates the relationships.

Foreign Key Structure

Foreign keys are defined using a foreign_key object in the field definition:

{
"name": "post_id",
"type": "string",
"foreign_key": {
"entity": "posts",
"field": "id",
"on_update": "CASCADE",
"on_delete": "CASCADE"
}
}

Foreign Key Properties

Property Type Required Default Description
entity string Yes - Name of the referenced entity (table)
field string No "id" Column name in the referenced entity
on_update string No "RESTRICT" Action when referenced record is updated
on_delete string No "RESTRICT" Action when referenced record is deleted

Foreign Key Policies

Both on_update and on_delete support the following policies:

Policy Description
CASCADE Automatically update/delete related records
SET NULL Set foreign key field to NULL when referenced record is updated/deleted
RESTRICT Prevent update/delete if related records exist (default)
NO ACTION Similar to RESTRICT, but checked after the operation
SET DEFAULT Set foreign key field to its default value

Foreign Key Validation

When creating or updating schemas with foreign keys, MantisBase automatically validates:

  1. Referenced Entity Exists - The entity referenced by foreign_key.entity must exist
  2. Referenced Field Exists - The field specified in foreign_key.field must exist in the referenced entity
  3. Type Compatibility - Field types should be compatible (warnings issued for mismatches)

Note: If the referenced entity doesn't exist yet, a warning is issued but the schema is still created. The database will enforce the constraint when the DDL is executed.

Examples

Example 1: Comments with Post Reference

{
"name": "comments",
"type": "base",
"fields": [
{"name": "content", "type": "string", "required": true},
{
"name": "post_id",
"type": "string",
"required": true,
"foreign_key": {
"entity": "posts",
"field": "id",
"on_delete": "CASCADE"
}
}
]
}

Example 2: User Profile with User Reference

{
"name": "profiles",
"type": "base",
"fields": [
{"name": "bio", "type": "string"},
{
"name": "user_id",
"type": "string",
"required": true,
"foreign_key": {
"entity": "users",
"field": "id",
"on_update": "CASCADE",
"on_delete": "CASCADE"
}
}
]
}

Example 3: Removing a Foreign Key

To remove a foreign key constraint, set foreign_key to null:

PATCH /api/v1/schemas/comments
{
"fields": [
{
"id": "post_id_field_id",
"foreign_key": null
}
]
}

Constraint Naming

Foreign key constraints are automatically named using the pattern: fk_<table_name>_<field_name>

For example, a foreign key on post_id in the comments table would create a constraint named fk_comments_post_id.


📊 System Endpoints

Logs Endpoint

The logs endpoint provides access to system logs with filtering, pagination, and sorting capabilities. Requires admin authentication.

Method Endpoint Description
GET /api/v1/sys/logs Get system logs with filtering and pagination

Query Parameters

Parameter Type Default Description
page integer 1 Page number (1-based)
page_size integer 50 Number of records per page (max 1000)
level string - Filter by exact log level: trace, debug, info, warn, critical
min_level string - Filter by minimum log level (includes that level and above)
search string - Search in log messages
start_date string - Start date filter (ISO 8601 format)
end_date string - End date filter (ISO 8601 format)
sort_by string "timestamp" Sort field: level, origin, message, timestamp, created_at
sort_order string "desc" Sort order: asc or desc

Example Requests

# Get recent logs (default: page 1, 50 records)
curl -H "Authorization: Bearer <admin_token>" \
http://localhost:7070/api/v1/sys/logs
# Get logs with pagination
curl -H "Authorization: Bearer <admin_token>" \
"http://localhost:7070/api/v1/sys/logs?page=2&page_size=100"
# Filter by log level
curl -H "Authorization: Bearer <admin_token>" \
"http://localhost:7070/api/v1/sys/logs?level=warn"
# Get all errors and warnings (min_level)
curl -H "Authorization: Bearer <admin_token>" \
"http://localhost:7070/api/v1/sys/logs?min_level=warn"
# Search in log messages
curl -H "Authorization: Bearer <admin_token>" \
"http://localhost:7070/api/v1/sys/logs?search=database"
# Filter by date range
curl -H "Authorization: Bearer <admin_token>" \
"http://localhost:7070/api/v1/sys/logs?start_date=2024-01-01T00:00:00Z&end_date=2024-01-31T23:59:59Z"
# Sort by level, ascending
curl -H "Authorization: Bearer <admin_token>" \
"http://localhost:7070/api/v1/sys/logs?sort_by=level&sort_order=asc"
# Combined filters
curl -H "Authorization: Bearer <admin_token>" \
"http://localhost:7070/api/v1/sys/logs?min_level=warn&search=error&page=1&page_size=20&sort_by=timestamp&sort_order=desc"

Response Format

{
"logs": [
{
"id": "log_id_123",
"timestamp": "2024-01-15T10:30:45Z",
"level": "warn",
"origin": "entitySchema",
"message": "Foreign key validation warning",
"details": "Additional details about the log entry",
"data": {},
"created_at": "2024-01-15T10:30:45Z"
}
],
"pagination": {
"page": 1,
"page_size": 50,
"total": 1250,
"total_pages": 25
}
}

Log Levels

Log levels in order of severity (lowest to highest):

  1. trace - Detailed debugging information
  2. debug - General debugging information
  3. info - Informational messages
  4. warn - Warning messages
  5. critical - Critical errors

When using min_level, all logs at that level and above are included. For example, min_level=warn includes warn and critical logs.

Error Responses

503 Service Unavailable - Log database not initialized:

{
"error": "Log database not initialized",
"status": 503,
"data": {}
}

500 Internal Server Error - Server error:

{
"error": "Failed to fetch logs: <error message>",
"status": 500,
"data": {}
}

📡 Realtime API

MantisBase provides realtime database change notifications over Server-Sent Events (SSE) for both SQLite and PostgreSQL backends. Clients subscribe to topics (entity names and optionally specific row IDs) and receive live insert, update, and delete events as they occur.

Endpoints

Method Endpoint Description
GET /api/v1/realtime Open an SSE connection. Requires topics query parameter.
POST /api/v1/realtime Update topics for an existing session or clear topics to disconnect. Requires JSON body.

GET /api/v1/realtime — Open SSE connection

Establishes a long-lived SSE stream. Pass a comma-separated list of topics in the query string.

Query parameters

Parameter Type Required Description
topics string Yes Comma-separated list of topics. Each topic is an entity name (e.g. posts) or entity:row_id (e.g. posts:019c1b81-364b-7000-8120-b5416b2c42c2) for a specific row.

Example

curl -N -H "Authorization: Bearer <token>" \
"http://localhost:7070/api/v1/realtime?topics=posts,users,posts:019c1b81-364b-7000-8120-b5416b2c42c2"

Response

  • Content-Type: text/event-stream
  • Connection: keep-alive

The stream sends events in SSE format. Each event has an event type and a data line (JSON).

POST /api/v1/realtime — Update or disconnect session

Updates the list of topics for an existing SSE session, or clears topics to effectively disconnect. Requires the client_id (session identifier) returned in the connected event from the GET request.

Request body (JSON)

Field Type Required Description
client_id string Yes Session ID returned when the SSE connection was established.
topics array Yes New list of topics. Each topic is an entity name or entity:row_id. Pass an empty array to clear subscriptions and disconnect.

Example: Update topics

curl -X POST http://localhost:7070/api/v1/realtime \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"client_id": "sse_1769987962000_0abc1",
"topics": ["posts", "comments"]
}'

Example: Clear topics (disconnect)

curl -X POST http://localhost:7070/api/v1/realtime \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"client_id": "sse_1769987962000_0abc1", "topics": []}'

SSE event types

Event Description
connected Sent once when the SSE connection is established. Contains client_id, topics, and timestamp.
ping Keep-alive sent periodically (e.g. every ~30 s). Contains timestamp.
change A database change (insert, update, or delete) for a subscribed topic.

Event data format

connected

{
"client_id": "sse_1769987962000_0abc1",
"topics": ["posts", "users"],
"timestamp": 1769987962
}

ping

{"timestamp": 1769988043}

change

Field Type Description
action string One of insert, update, delete.
entity string Entity (table) name.
row_id string ID of the affected row.
topic string Topic that matched (entity or entity:row_id).
timestamp number Unix timestamp of the change.
data object | null For insert and update, the row payload; for delete, null.

Example change (insert)

{
"action": "insert",
"data": {
"created": "2026-02-02T02:19:38",
"id": "019c1b81-364b-7000-8120-b5416b2c42c2",
"updated": "2026-02-02T02:19:38"
},
"entity": "test",
"row_id": "019c1b81-364b-7000-8120-b5416b2c42c2",
"timestamp": 1769988013,
"topic": "test"
}

Example change (delete)

{
"action": "delete",
"data": null,
"entity": "test",
"row_id": "019c1b81-1501-7000-9d65-1541c14f99b7",
"timestamp": 1769988013,
"topic": "test"
}

Access control

Realtime endpoints use the same access rules as entity list and get:

  • Subscribing to an entity (e.g. posts) requires list access on that entity.
  • Subscribing to a specific row (e.g. posts:&lt;id&gt;) requires get access.

Invalid or unauthorized topics result in 400 or 403 responses.

Backend support

Realtime is supported for:

  • SQLite — Change detection via polling.
  • PostgreSQL — Change detection via LISTEN/NOTIFY and triggers.

🎛️ Admin Dashboard

The MantisBase Admin Dashboard is a comprehensive web-based interface accessible at /mb (e.g., http://localhost:7070/mb). It provides a visual alternative to the REST API for managing your backend.

Dashboard Features

Entity Management

  • Browse Entities - View all entities (tables) in your database
  • View Records - Browse, search, and filter records in any entity
  • Create Records - Add new records through intuitive forms
  • Edit Records - Update existing records inline
  • Delete Records - Remove records with confirmation

Schema Management

  • Schema Builder - Create and configure entity schemas visually
  • Field Management - Add, edit, and remove fields with type selection
  • Access Rules Configuration - Set up access control rules with a user-friendly interface
  • Foreign Key Setup - Configure relationships between entities
  • View Entity Support - Create and manage SQL view entities

Data Exploration

  • Search & Filter - Quickly find records with built-in search
  • Pagination - Navigate through large datasets
  • Sorting - Sort records by any column
  • Real-time Updates - See changes reflected immediately

User Management

  • Authentication Entities - Manage auth-type entities
  • User Accounts - View and manage user accounts
  • Admin Accounts - Manage admin users

System Management

  • Logs Viewer - Access system logs directly from the dashboard
  • Health Status - Monitor system health
  • Configuration - View and manage system settings

Accessing the Dashboard

  1. Create an Admin Account (if not already created):
    ./mantisbase admins add admin@example.com your_password
  2. Navigate to Dashboard:
    http://localhost:7070/mb
  3. Login with your admin credentials

Dashboard Requirements

  • Admin Authentication Required - Only users authenticated as admins can access the dashboard
  • Modern Browser - Works best with Chrome, Firefox, Safari, or Edge (latest versions)
  • JavaScript Enabled - The dashboard requires JavaScript to function