feat: initial release of Quick API

Express server that automatically generates REST endpoints from JSON files.
This commit is contained in:
MasterAcnolo
2026-05-30 23:20:25 +02:00
commit 1a5a7fa7e1
19 changed files with 2040 additions and 0 deletions

206
README.md Normal file
View File

@@ -0,0 +1,206 @@
# Quick API
Serve any JSON file as a REST API — filtering, sorting, and pagination included.
Drop a file in `data/`, start the server, your API is ready.
---
## Why this exists
During development, you often need to consume JSON data through an HTTP API before the real backend is ready — or simply to inspect, filter, and paginate a dataset quickly without writing any server code.
Quick API was built out of that need. Drop a JSON file in a folder, start the server, and you immediately have a filterable, sortable, paginated REST API on top of your data. No configuration required to get started.
It can also serve as a starting point for a more complete Express API, since the project is already structured with routes, controllers, services, and middleware.
---
## Getting started
```bash
npm install
npm run dev
```
The server starts on `http://localhost:3000`.
---
## Adding a resource
Place a JSON file in the `data/` directory:
```
data/
users.json -> GET /users
products.json -> GET /products
orders.json -> GET /orders
```
Restart the server. The route is created automatically.
The JSON file must be an **array of objects**:
```json
[
{ "id": 1, "name": "Half-Life 3", "status": "rumored", "studio": "Valve", "genre": "fps", "released": false, "year": null },
{ "id": 2, "name": "Portal 3", "status": "rumored", "studio": "Valve", "genre": "puzzle", "released": false, "year": null },
{ "id": 3, "name": "Silksong", "status": "released", "studio": "Team Cherry", "genre": "metroidvania", "released": true, "year": 2025 },
{ "id": 4, "name": "Elder Scrolls VI", "status": "rumored", "studio": "Bethesda", "genre": "rpg", "released": false, "year": null }
]
```
---
## Available routes
### System routes
| Route | Description |
|-------------------------|---------------------------------------------------|
| `GET /` | Full documentation and list of loaded resources |
| `GET /health` | Health check (status, uptime) |
| `GET /resources` | Lists all available resources |
| `GET /schema/:resource` | Inferred schema (unique field names) of a resource|
### Dynamic resource routes
| Route | Description |
|-----------------------|---------------------------------------------------|
| `GET /:resource` | All records (query param filtering supported) |
| `GET /:resource/:id` | Single record by `id` |
| `POST /:resource` | Replace the in-memory dataset (not persisted) |
---
## Query params
### Field filtering
```
GET /users?role=admin # contains (string) or equals (number)
GET /users?role_ne=admin # not equal
GET /users?age_gte=18 # greater than or equal
GET /users?age_lte=65 # less than or equal
GET /users?age_gt=17 # strictly greater than
GET /users?age_lt=66 # strictly less than
```
Filters are combinable:
```
GET /users?role=admin&active=true
```
### Full-text search
```
GET /users?_q=alice # searches "alice" across all fields
```
### Sorting
```
GET /users?_sort=name
GET /users?_sort=name&_order=desc
```
Dot notation is supported for nested fields:
```
GET /users?_sort=address.city
```
### Pagination
```
GET /users?_limit=10
GET /users?_limit=10&_page=2
```
Pagination metadata is available in the response headers:
```
X-Total-Count: 42
X-Page: 2
X-Limit: 10
```
### Field projection
```
GET /users?_fields=id,name,role
```
---
## Configuration
All environment variables are optional:
| Variable | Default | Description |
|---------------|----------|------------------------------------------------|
| `PORT` | `3000` | Server listening port |
| `DATA_DIR` | `./data` | Path to the JSON files directory |
| `BODY_LIMIT` | `10mb` | Maximum POST request body size |
| `LOG_ENABLED` | `true` | Enable HTTP request logging in the console |
```bash
PORT=8080 DATA_DIR=./my-data npm run dev
```
All defaults are centralized in `src/config/config.js`.
---
## Project structure
```
quick-api/
├── data/ # JSON files -> automatic routes
│ └── users.json # Example file
├── src/
│ ├── index.js # Entry point — bootstrap
│ ├── app.js # Express factory (middleware + routes)
│ ├── config/
│ │ └── config.js # Centralized configuration
│ ├── controllers/
│ │ ├── resource.controller.js # getAll / getById / replaceAll
│ │ └── system.controller.js # getDocs / getHealth / getResources / getSchema
│ ├── middleware/
│ │ ├── requestLogger.middleware.js # Colored HTTP logs with response time
│ │ ├── resourceGuard.middleware.js # 404 if resource does not exist
│ │ ├── errorHandler.middleware.js # Global error handler
│ │ └── notFoundHandler.middleware.js # Catch-all 404
│ ├── routes/
│ │ ├── resource.routes.js # Dynamic routes /:resource
│ │ └── system.routes.js # Fixed routes (/, /health, /schema...)
│ ├── services/
│ │ ├── datasetRegistry.service.js # In-memory dataset store
│ │ └── filter.service.js # Filtering, sorting, pagination engine
│ └── utils/
│ └── response.utils.js # HTTP response helpers
└── package.json
```
---
## Adding a custom endpoint
1. Create your controller in `src/controllers/`
2. Create your route file in `src/routes/`
3. Mount it in `src/app.js` **before** `resourceRouter`
```js
// src/app.js
const myRouter = require('./routes/my.routes');
app.use('/custom', myRouter); // must come before resourceRouter
```
---
## Notes
- Data is loaded **into memory** at startup. A `POST /:resource` updates the in-memory dataset but **does not write back** to the JSON file on disk.
- Restarting the server reloads files from disk.
- The `maxLimit` value in `config.js` caps the `_limit` param to avoid oversized responses (default: 500).