About Microapi
Microapi is an MCP server published by fernandezvara in the RAG category: schema-less JSON Storage REST API.
The repository has 2 stars and 0 forks, with the last commit a year ago. Six months or more without a commit doesn't mean the server is broken, but check the open issues before depending on it in production.
Install
git clone https://github.com/fernandezvara/microapiThis server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.
Ask AI
Ask AI about Microapi
Powered by Claude · Grounded in docs
Security checks
- ✓README presentThe repository ships documentation.
5 checks have not been run yet.
README
MicroAPI
A lightweight, zero-ops JSON micro-database and API server. Store schemaless JSON documents in named sets and collections, query them with filters, optionally validate against JSON Schema, and add JSON-path indexes for speed. Ships with a built-in dashboard and an MCP interface.
- Storage: SQLite with WAL, one physical table per set:
data_<set>storing{id, collection, data JSON, created_at, updated_at}. - API: Clean REST endpoints for documents, collections, sets, indexing, and schemas.
- Query: JSON where filters with rich operators ($eq, $ne, $gt, $gte, $lt, $lte, $like, $ilike, $startsWith, $istartsWith, $endsWith, $iendsWith, $contains, $icontains, $in, $nin, $between, $isNull, $notNull), plus order, limit/offset, and pagination header.
- Indexes: Async JSON-path indexes tracked in metadata and usage-counted for observability.
- Validation: Optional per-collection JSON Schema validation on create/update/replace.
- Dashboard: Single-page UI served from
/for exploring data and testing APIs. - MCP: Two flavors: HTTP endpoints at
/mcpand a standalone stdio MCP server (cmd/micro-api-mcp).
Quick start
Run with Docker
# Persist DB to ./data.db and expose on 8080
docker run --rm -p 8080:8080 \
-v "$(pwd)":/data \
-e DB_PATH=/data/data.db \
ghcr.io/fernandezvara/microapi:latest
- Health:
curl http://localhost:8080/health - Dashboard: open http://localhost:8080/
Docker Compose (includes optional n8n)
See docker-compose.yaml. Start both services:
docker compose up --build
The Compose file mounts a community n8n node from ../n8n-nodes-microapi for convenience.
Local dev
make run # builds and runs ./cmd/micro-api
make test # run tests
make css # builds web/static/style.css via Tailwind (requires Node + npx)
Go 1.24+ recommended. Config is read from environment and optional .env.
Configuration
Defined in internal/config/config.go.
- PORT (default
8080): HTTP port. - DB_PATH (default
./data.db): SQLite file path. - MAX_REQUEST_SIZE (default
1048576): Max request body bytes. - ALLOW_DELETE_SETS (default
false): EnableDELETE /{set}. - ALLOW_DELETE_COLLECTIONS (default
false): EnableDELETE /{set}/{collection}. - CORS (default empty): CSV of allowed Origins. Empty means reflect any Origin.
- DEV (default
false): Dev mode flag (currently used for minor toggles).
CORS exposes the X-Total-Items header to browsers.
Data model
- Set: Top-level namespace. Backed by table
data_<set>. - Collection: Logical group inside a set. Stored in the
collectioncolumn. - Document: Arbitrary JSON in
datacolumn plus generated metadata timestamps.
SQLite is opened with WAL mode, foreign keys ON, busy timeout, and synchronous NORMAL (internal/database/connection.go). Per-set tables have helpful indexes on collection and (collection, created_at).
Response envelope
Every response uses internal/models.APIResponse:
{ "success": true, "data": ..., "error": null }
- Errors return
success:falsewitherrormessage and appropriate HTTP status. - Document responses include
_metaunless suppressed (see below).
REST API
Base path is /. Names ({set}, {collection}) must match ^[a-zA-Z0-9_]+$.
Health
- GET
/health→{ status: "ok", version: <string> }
Dashboard
- GET
/serves the UI. Assets:/style.css,/favicon.ico,/logo.svg.
Sets
- GET
/_sets→ summary of sets with collection/doc counts. - GET
/{set}→ per-collection stats for the set. - DELETE
/{set}→ drops the set table and metadata. RequiresALLOW_DELETE_SETS=true.
Example:
curl http://localhost:8080/_sets
curl http://localhost:8080/myset
Collections & Documents
- POST
/{set}/{collection}→ create document. - GET
/{set}/{collection}→ query documents (see Query section). - GET
/{set}/{collection}/{id}→ fetch one. - PUT
/{set}/{collection}/{id}→ replace document (full body). - PATCH
/{set}/{collection}/{id}→ merge patch. - DELETE
/{set}/{collection}/{id}→ delete by id. - DELETE
/{set}/{collection}→ delete all or filtered (requiresALLOW_DELETE_COLLECTIONS=true).
Metadata in responses:
_meta.id,_meta.created_at,_meta.updated_atare added by default.- Suppress with
?meta=0on GET/Query endpoints.
Querying
Endpoint: GET /{set}/{collection} with query params:
where: JSON string. Example:{"user.name": {"$eq": "Alice"}}order_by:created_at,updated_at, or a JSON path like$.user.agelimit: integer > 0offset: integer ≥ 0debug=1: addsX-Query-Planheader withEXPLAIN QUERY PLANsummary
Pagination:
- Response header
X-Total-Itemsincludes the total count ignoring limit/offset.
Supported operators in where:
- Comparisons:
$eq,$ne,$gt,$gte,$lt,$lte - Text pattern:
$like(SQL LIKE pattern e.g. "%foo%")$ilike(case-insensitive LIKE)$startsWith,$istartsWith$endsWith,$iendsWith$contains,$icontains(wraps value with%...%)
- Sets:
$in,$nin(expects an array of values) - Range:
$between(expects[min, max]) - Null checks:
$isNull,$notNull(value ignored)
Notes:
$inwith an empty array matches no rows;$ninwith an empty array matches all rows.- Case-insensitive operators use
LOWER(...)under the hood. - In
where, you can use dot paths likeuser.ageor JSONPath (e.g.$.user.age). - For
order_byand index endpoints, JSONPath is accepted (e.g.$.user.age).
Paths:
wherekeys can use dot notation (user.age) or JSONPath ($.user.age).order_byand index endpoints accept JSONPath (e.g.$.user.age).
Errors and edge-cases
- Malformed
wherereturns HTTP 400 with a friendly message:"malformed where clause: expected a JSON object where keys are field paths and values are operator objects"
- Unsupported operator returns HTTP 400, e.g.
"unsupported operator: $foo". - Empty results always return an empty array
[](nevernull). - Multi-argument expectations:
$in/$ninrequire an array value.$betweenrequires a two-element array[min, max].
Examples of bad requests:
# Malformed JSON
curl "http://localhost:8080/myset/users?where=not-json"
# Unsupported operator
curl "http://localhost:8080/myset/users?where={\"age\":{\"$foo\":1}}"
# Wrong shape for $between (should be [min,max])
curl "http://localhost:8080/myset/users?where={\"age\":{\"$between\":42}}"
Examples:
# All docs where user.age >= 18, newest first, first page of 10
curl "http://localhost:8080/myset/users?where={\"user.age\":{\"$gte\":18}}&order_by=created_at&limit=10&offset=0"
# Suppress metadata
curl "http://localhost:8080/myset/users?where={}&meta=0"
# Text pattern matching
curl "http://localhost:8080/myset/users?where={\"user.name\":{\"$contains\":\"Ada\"}}"
curl "http://localhost:8080/myset/users?where={\"user.name\":{\"$icontains\":\"ada\"}}" # case-insensitive
curl "http://localhost:8080/myset/users?where={\"user.name\":{\"$startsWith\":\"An\"}}"
curl "http://localhost:8080/myset/users?where={\"user.name\":{\"$istartsWith\":\"an\"}}" # case-insensitive
curl "http://localhost:8080/myset/users?where={\"user.email\":{\"$endsWith\":\"@example.com\"}}"
curl "http://localhost:8080/myset/users?where={\"user.email\":{\"$iendsWith\":\"@EXAMPLE.COM\"}}" # case-insensitive
# Set membership
curl "http://localhost:8080/myset/orders?where={\"status\":{\"$in\":[\"new\",\"processing\"]}}"
curl "http://localhost:8080/myset/orders?where={\"status\":{\"$nin\":[\"cancelled\"]}}"
# Range
curl "http://localhost:8080/myset/products?where={\"price\":{\"$between\":[10,20]}}"
# Null checks
curl "http://localhost:8080/myset/users?where={\"archivedAt\":{\"$isNull\":true}}"
curl "http://localhost:8080/myset/users?where={\"archivedAt\":{\"$notNull\":true}}"
# Order by JSON path
curl "http://localhost:8080/myset/users?order_by=$.user.age"
# Pagination and debug header
curl -i "http://localhost:8080/myset/users?limit=5&offset=5&debug=1"
Index management
Create, inspect, and remove JSON-path indexes per collection. Index creation is asynchronous.
- POST
/{set}/{collection}/_index- Body:
{ "path": "$.user.age" }or{ "paths": ["$.user.age", "$.country"] } - Response:
202 Accepted,{ name, status: "creating" }
- Body:
- GET
/{set}/{collection}/_indexes→ list index metadata. - GET
/{set}/{collection}/_index/{path}→ status for an index.pathis URL-encoded JSONPath. Example for$.user.age:%24.user.age
- DELETE
/{set}/{collection}/_index/{path}orDELETE .../_index/{path}?paths=p1,p2→ drops index and metadata.
Index metadata fields (internal/database/index.go):
paths(CSV),status(creating|ready|error),error,usage_count,last_used_at,created_at.
Schema management
- PUT
/{set}/{collection}/_schema- Body: JSON Schema to enable validation, or
null/empty to remove schema. - Response:
{ schema: <echoed-or-null> }
- Body: JSON Schema to enable validation, or
- GET
/{set}/{collection}/_info- Response:
{ schema, indexes, stats: { count, created_at? } }
- Response:
Documents are validated on create/replace/update when a schema is set.
Validation, limits, and CORS
- Name validation: set/collection must match
^[a-zA-Z0-9_]+$. - Reserved fields: top-level keys starting with
_are reserved in documents._metain request bodies is ignored/validated and never stored. - Body limit:
MAX_REQUEST_SIZEenforced via middleware. - CORS: Allow list via
CORSenv var;X-Total-Itemsis exposed for pagination.
Build & release
- Multi-stage
Dockerfilebuilds a static binary and exposes port 8080. - Published images:
ghcr.io/fernandezvara/microapi:<tag>with multi-arch manifest (latesttag points to the newest release). Makefiletargets:build,run,test,css.
Examples
# Create a document
curl -X POST http://localhost:8080/myset/users \
-H 'Content-Type: application/json' \
-d '{"user":{"name":"Ada","age":37}}'
# Get it back (replace <id>)
curl http://localhost:8080/myset/users/<id>
# Query (age >= 30), order by JSON path
curl "http://localhost:8080/myset/users?where={\"user.age\":{\"$gte\":30}}&order_by=$.user.age"
# Create an index
curl -X POST http://localhost:8080/myset/users/_index \
-H 'Content-Type: application/json' \
-d '{"path":"$.user.age"}'
# Set a JSON Schema
curl -X PUT http://localhost:8080/myset/users/_schema \
-H 'Content-Type: application/json' \
-d '{"type":"object","properties":{"user":{"type":"object","properties":{"name":{"type":"string"},"age":{"type":"number"}}}},"required":["user"]}'
Project structure
cmd/micro-api/: HTTP server main.cmd/micro-api-mcp/: MCP stdio server main.internal/server/server.go: router and middleware wiring.internal/handlers/: REST and MCP handlers.internal/query/: where parser and SQL builder.internal/database/: connection, migrations, indexes, per-set table helpers.internal/validation/: JSON Schema persistence and validation.web/static/: dashboard (dashboard.html,style.css).docker-compose.yaml: local stack with optional n8n.
n8n integration
n8n integration is provided via the n8n-nodes-microapi community node. repo: https://github.com/fernandezvara/n8n-nodes-microapi
License
MIT. See LICENSE.
README copy captured when this server was indexed; it may lag the repository. The original is authoritative.