One RESTful API for collaborative, schema-free document storage.
Restcol organises data into projects, collections, and documents:
- Project — a tenant boundary. Every request is scoped to one project.
- Collection — a set of documents with similar shape. Collections track schema evolution over time.
- Document — the actual payload (JSON today; CSV/XML/media on the roadmap). Schemas are inferred on write; no up-front definition required.
Restcol speaks gRPC natively and exposes the same service over HTTP/JSON via grpc-gateway. Swagger/OpenAPI is auto-generated from the proto.
┌────────────┐ HTTP/JSON ┌───────────────┐
│ client │ ───────────────▶ │ grpc-gateway │
└────────────┘ │ (port 50091) │
└───────┬───────┘
│ gRPC (internal)
▼
┌────────────┐ gRPC ┌───────────────┐ GORM ┌───────────┐
│ gRPC client│ ───────────────▶ │ restcol gRPC │ ─────────────▶│ Postgres │
└────────────┘ (port 50090) │ server │ └───────────┘
└───────────────┘
Server entrypoint: main.go → pkg/server/app wires auth middleware, storage (pkg/storage/...), schema inference (pkg/schema), and the RestColService handlers (pkg/app).
make run-postgres # or: ./run_postgres.shSpins up library/postgres:16-alpine3.18 on :5432 with user postgres, password password, database unittest.
make run-local # or: ./run_local.shServes gRPC on :50090 and HTTP/JSON on :50091. On first boot the default project (1001) is seeded so anonymous requests have a tenant.
Swagger UI: http://localhost:50091/swaggerui/ Per-project API doc: http://localhost:50091/v1/projects/1001/apidoc
All examples use the default project 1001. Replace with your own project ID as needed.
curl -X POST http://localhost:50091/v1/projects/1001/collections \
-H 'Content-Type: application/json' \
-d '{"description": "user events"}'curl -X POST http://localhost:50091/v1/projects/1001/collections/<COLLECTION_ID>:newdoc \
-H 'Content-Type: application/json' \
-d '{"data": {"user": "alice", "event": "login", "ts": 1714000000}}'Omit collections/<id>:newdoc to let the server auto-provision a collection:
curl -X POST http://localhost:50091/v1/projects/1001/newdoc \
-H 'Content-Type: application/json' \
-d '{"data": {"hello": "world"}}'curl http://localhost:50091/v1/projects/1001/collections/<COLLECTION_ID>/docs/<DOC_ID>Scope mismatch (wrong project or collection for the doc) returns 404 Not Found, not an empty body.
curl 'http://localhost:50091/v1/projects/1001/collections/<COLLECTION_ID>/docs?limitCount=10'curl -X DELETE http://localhost:50091/v1/projects/1001/collections/<COLLECTION_ID>/docs/<DOC_ID>By default, deleting a non-empty collection returns 409 Conflict:
curl -X DELETE http://localhost:50091/v1/projects/1001/collections/<COLLECTION_ID>
# {"code":2,"message":"collection ... contains N documents; pass force=true to cascade-delete"}Pass force=true to cascade-delete all documents first:
curl -X DELETE 'http://localhost:50091/v1/projects/1001/collections/<COLLECTION_ID>?force=true'The server ships with AnnonymousClaimParser + AllowEveryOne authorisation — every request is accepted and mapped to the default project. This is fine for local development and demos; configure a real JWT claim parser before exposing the service publicly. See pkg/server/app/app.go for the middleware wiring.
make build # compile server binary
make test # short tests only (no postgres required)
make test-race # short tests with -race
make test-full # full suite (requires run-postgres first)
make vet # go vet ./...
make tidy # go mod tidy
make gen-proto # regenerate api/pb/* from api/restcol.proto (requires buf)
make clean # remove build artifacts
make help # list all targets| Path | Purpose |
|---|---|
main.go |
entrypoint; parses flags and starts the server |
api/ |
proto definitions + generated gRPC / OpenAPI clients |
pkg/app/ |
gRPC service handlers (collections, documents) |
pkg/server/app/ |
server assembly: middleware + storage + handlers |
pkg/server/ |
swagger / OpenAPI route registration |
pkg/storage/ |
GORM-backed CRUD for projects, collections, documents |
pkg/models/ |
domain models (what the storage layer reads/writes) |
pkg/schema/ |
schema inference and field-path building |
pkg/bootstrap/ |
seeds the default project used for anonymous auth |
pkg/encoding/ |
JSON/CSV/XML payload decoders |
pkg/runtime/js/ |
goja-based JavaScript runtime for evaluating swagger |
pkg/authn/, authz/ |
anonymous auth + allow-all authorisation (dev default) |
integrationtest/ |
end-to-end tests against a live server |
The server reads Postgres connection settings from flags prefixed with --restcol_. See run_local.sh for a working example. Flags:
| Flag | Default |
|---|---|
--grpc_port |
50090 |
--http_port |
50091 |
--restcol_db_endpoint |
— |
--restcol_db_name |
— |
--restcol_db_user |
— |
--restcol_db_password |
— |
--restcol_auto_migrate |
false |
- Fork and create a feature branch.
make test-racebefore pushing.- Open a pull request against
main.
Apache License 2.0 — see LICENSE.