mirror of
https://github.com/MasterAcnolo/Quick-API.git
synced 2026-07-29 18:05:46 +02:00
feat: initial release of Quick API
Express server that automatically generates REST endpoints from JSON files.
This commit is contained in:
206
README.md
Normal file
206
README.md
Normal 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).
|
||||
Reference in New Issue
Block a user