Documentation
Everything you need to integrate with CrudApi โ laymen-friendly explanations, copy-paste examples, and zero jargon when we can avoid it.
๐ Quickstart (5 minutes)
Goal: register your first database and call it from curl.
Step 1 โ Open the admin console
Visit /admin and log in with the default credentials:
/admin/adminusers after first login.Step 2 โ Register your database
- Click Databases โ + Register Database
- Pick engine: MySQL (only MySQL today; SQL Server / PostgreSQL on roadmap)
- Fill in host, port, db name, user, password
- Click ๐ Test Connection โ green = ready, red shows the real error
- Click Register โ your db is live
Step 3 โ Create an API key
- Go to API Clients โ + Create API Client
- Bind it to the database you just registered
- Pick a role: Reader (read-only), Editor (full CRUD), or any custom role
- Copy the API key โ you only see it once. Format:
drk_abc123...
Step 4 โ Call your data
You'll get back the table contents as JSON. That's it โ no boilerplate, no schemas to define.
๐ Architecture (the big picture)
CrudApi is built from independent packages. Each does one thing well:
| Package | What it does |
|---|---|
| SqlConnector | Talks to your databases (MySQL today; pluggable for others). Handles CRUD, bulk import, transactions. |
| CrudAdmin | Identity & access control: users, roles, permissions, audit, sessions, CORS. Ships the admin UI. |
| SqliteAdmin | Standalone SQLite browser for your .db files. |
| CrudApi (this host) | The web app you're running. Wires the packages together with your own routes. |
| CrudApi.Docs | This help system and the landing page. |
Request flow: Your call hits /api/v1/{db}/crud/{table} โ CORS check โ Auth (API key/Basic/JWT) โ Tenant resolution โ Permission check โ Row policy filter โ SqlConnector queries your database โ JSON response. Audited at every step.
๐ Authentication โ pick one
Every API request must authenticate. You have three options. Pick based on your use case:
| Method | Best for | How to send |
|---|---|---|
| API Key Recommended | Server-to-server, mobile apps, scripts | X-API-Key: drk_abc123... |
| Basic Auth | Quick testing, legacy clients | Authorization: Basic base64(user:pass) |
| JWT | Web apps, user-specific tokens with claims | Authorization: Bearer eyJhbG... |
How to get them
- API Key: /admin/apiclients โ Create
- Basic Auth: /admin/basicauth โ Create user
- JWT: /admin โ click Generate Test JWT on the dashboard
๐บ URL structure
All API URLs follow this pattern:
| Part | Example | What it means |
|---|---|---|
{database} | master | The db_key you set when registering the database in Admin. |
{table} | customers | Any table that exists in that database. |
{id} (optional) | 42 | For GET/PUT/DELETE of a specific row. |
HTTP verbs
| Verb | What it does |
|---|---|
GET /crud/customers | List rows (filterable, paginated) |
GET /crud/customers/id/42 | Get one row |
POST /crud/customers | Insert a row |
PUT /crud/customers/id/42 | Update a row |
DELETE /crud/customers/id/42 | Delete a row |
๐ก Sample requests (copy-paste)
List rows
Filter and sort
Insert a row
Update a row
Delete a row
๐ Filters & sorting (OData syntax)
The filter language is a subset of OData. Pass it via the ?filter= query parameter.
Operators
| Operator | Meaning | Example |
|---|---|---|
eq | equals | status eq 'active' |
ne | not equals | status ne 'deleted' |
gt / ge | greater / greater-or-equal | age gt 21 |
lt / le | less / less-or-equal | price le 100 |
and / or | combine conditions | age gt 21 and country eq 'India' |
contains | substring match | contains(name, 'John') |
Sorting
Pagination
Joins (for related tables)
๐ฅ Bulk import
Upload CSV files to insert thousands of rows at once. Three modes:
- File upload โ multipart form, ideal for one-off imports
- Filter source โ copy rows from another table using a filter
- API source โ pull rows from a 3rd-party API
File upload example
CSV format (smart)
The CSV header can use annotations for advanced features:
Country|CountryId (map:Country.Id=Name)โ looks up "India" inCountrytable and stores the matchingIdStatus (enum:Active,Inactive)โ rejects any other value
Errors
Failed rows are returned as a downloadable CSV โ fix and re-upload.
โ Error reference
All errors return JSON in this shape:
Common error codes
| Code | HTTP | What it means / how to fix |
|---|---|---|
unauthorized | 401 | No credential sent. Add X-API-Key or Authorization header. |
credential_invalid | 401 | Wrong API key / password / token. Re-copy it from Admin. |
credential_inactive | 401 | The key was revoked in Admin โ API Clients. Reactivate or recreate. |
credential_expired | 401 | Key passed its expiry date. Recreate. |
database_forbidden | 403 | Credential not allowed for this database. Bind it or mark Global. |
forbidden_action | 403 | Role doesn't grant this permission (e.g. trying to delete with Reader role). |
row_policy_forbidden | 403 | Row-level policy denies this operation on this specific row. |
database_unreachable | 503 | The target database server is down. Check Admin โ Databases โ Test. |
๐งฐ Admin tasks (typical workflow)
- Day 1: Change default admin password at /admin/adminusers
- Register databases: /admin/databases
- Add CORS origins: Click CORS on each database card
- Create users (or just API keys): /admin/users or /admin/apiclients
- Assign roles: /admin/roles โ start with built-in Owner / Editor / Writer / Reader
- Set policies: Optional row-level filters at /admin/policies
- Watch audit logs: /admin/auditlogs
๐ CORS (when your frontend is on a different domain)
If your web app calls CrudApi from app.example.com and your API is on api.example.com, the browser blocks it unless you allow that origin.
To allow an origin
- Go to /admin/databases
- Click CORS on the database card
- Add origin:
https://app.example.com
Wildcards work too:
https://*.example.comโ any subdomain*โ any origin (dangerous; OSS / public read-only APIs only)
๐ก Row-level policies
Filter what rows a user can see/touch. Common example: "users in role 'IndiaTeam' can only see customers where country = India".
Configure at /admin/policies
- Pick a role
- Pick a table
- Pick an action (read / create / update / delete)
- Enter a filter JSON:
{"country": "India"}
Now every request from that role automatically gets country='India' appended to its WHERE clause. Server-enforced, can't be bypassed.
๐ Audit logs
Every API call is logged with: timestamp, actor (which API key / user), resource, action, outcome, IP, and request details.
View at /admin/auditlogs โ filter by event type, severity, or actor.
Configure retention at /admin/settings โ Audit Configuration.
โ Runtime settings
Most behaviors are tunable from /admin/settings without restarting. Examples:
- JWT expiry time
- API key default lifetime
- Password policy
- Audit log retention
- Max concurrent admin sessions
Host-app settings (bulk size, GitHub token, AI key) live at /admin/hostsettings.
๐ณ Run with Docker
Easiest way to run CrudApi:
Or with docker-compose.yml:
Then visit http://localhost:8080.
๐ Environment variables
Override appsettings.json using env vars. Use double underscore __ for nesting.
| Variable | Default | Notes |
|---|---|---|
ASPNETCORE_URLS | http://+:80 | Port the app listens on |
Docs__ProductName | CrudApi | Branding |
Docs__GithubUrl | โ | Shown in nav + footer |
Docs__EnableLanding | true | Set false to redirect / to admin |
๐ HTTPS & reverse proxies
In production, run CrudApi behind a reverse proxy (nginx, Caddy, Traefik) that terminates TLS and forwards HTTP internally. CrudApi auto-trusts X-Forwarded-* headers so URLs in responses reflect the public hostname.
Sample Caddy config: