Skip to content

Commit 3e74640

Browse files
committed
feat: add _where filtering and new op separator
1 parent 83fbf30 commit 3e74640

File tree

13 files changed

+662
-566
lines changed

13 files changed

+662
-566
lines changed

README.md

Lines changed: 73 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,216 +1,156 @@
1-
# JSON-Server
1+
# JSON Server v1 (Beta)
22

3-
[![Node.js CI](https://github.com/typicode/json-server/actions/workflows/node.js.yml/badge.svg)](https://github.com/typicode/json-server/actions/workflows/node.js.yml)
3+
Fast mock REST API from a JSON file.
44

5-
> [!IMPORTANT]
6-
> Viewing beta v1 documentation – usable but expect breaking changes. For stable version, see [here](https://github.com/typicode/json-server/tree/v0.17.4)
5+
> Beta note: v1 can still change. For stable v0.17 docs, see:
6+
> https://github.com/typicode/json-server/tree/v0.17.4
77
8-
> [!NOTE]
9-
> Using React ⚛️ and tired of CSS-in-JS? See [MistCSS](https://github.com/typicode/mistcss) 👀
8+
## Quickstart (30s)
109

11-
## Install
10+
Install:
1211

13-
```shell
12+
```sh
1413
npm install json-server
1514
```
1615

17-
## Usage
18-
19-
Create a `db.json` or `db.json5` file
16+
Create `db.json`:
2017

2118
```json
2219
{
23-
"$schema": "./node_modules/json-server/schema.json",
2420
"posts": [
25-
{ "id": "1", "title": "a title", "views": 100 },
26-
{ "id": "2", "title": "another title", "views": 200 }
27-
],
28-
"comments": [
29-
{ "id": "1", "text": "a comment about post 1", "postId": "1" },
30-
{ "id": "2", "text": "another comment about post 1", "postId": "1" }
21+
{ "id": "1", "title": "Hello", "views": 100 },
22+
{ "id": "2", "title": "World", "views": 200 }
3123
],
32-
"profile": {
33-
"name": "typicode"
34-
}
24+
"comments": [{ "id": "1", "text": "Nice", "postId": "1" }],
25+
"profile": { "name": "typicode" }
3526
}
3627
```
3728

38-
<details>
29+
Run:
3930

40-
<summary>View db.json5 example</summary>
41-
42-
```json5
43-
{
44-
posts: [
45-
{ id: "1", title: "a title", views: 100 },
46-
{ id: "2", title: "another title", views: 200 },
47-
],
48-
comments: [
49-
{ id: "1", text: "a comment about post 1", postId: "1" },
50-
{ id: "2", text: "another comment about post 1", postId: "1" },
51-
],
52-
profile: {
53-
name: "typicode",
54-
},
55-
}
31+
```sh
32+
npx json-server db.json
5633
```
5734

58-
You can read more about JSON5 format [here](https://github.com/json5/json5).
35+
Try:
5936

60-
</details>
61-
62-
Pass it to JSON Server CLI
63-
64-
```shell
65-
$ npx json-server db.json
37+
```sh
38+
curl http://localhost:3000/posts/1
6639
```
6740

68-
Get a REST API
41+
Response:
6942

70-
```shell
71-
$ curl http://localhost:3000/posts/1
43+
```json
7244
{
7345
"id": "1",
74-
"title": "a title",
46+
"title": "Hello",
7547
"views": 100
7648
}
7749
```
7850

79-
Run `json-server --help` for a list of options
80-
81-
## Sponsors ✨
82-
83-
### Gold
84-
85-
| |
86-
| :--------------------------------------------------------------------------------------------------------------------------------------------------------: |
87-
| <a href="https://mockend.com/" target="_blank"><img src="https://jsonplaceholder.typicode.com/mockend.svg" height="100px"></a> |
88-
| <a href="https://zuplo.link/json-server-gh"><img src="https://github.com/user-attachments/assets/adfee31f-a8b6-4684-9a9b-af4f03ac5b75" height="100px"></a> |
89-
| <a href="https://www.mintlify.com/"><img src="https://github.com/user-attachments/assets/bcc8cc48-b2d9-4577-8939-1eb4196b7cc5" height="100px"></a> |
90-
91-
### Silver
92-
93-
| |
94-
| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
95-
| <a href="https://requestly.com?utm_source=githubsponsor&utm_medium=jsonserver&utm_campaign=jsonserver"><img src="https://github.com/user-attachments/assets/f7e7b3cf-97e2-46b8-81c8-cb3992662a1c" style="height:70px; width:auto;"></a> |
51+
## Query capabilities overview
9652

97-
### Bronze
98-
99-
| | |
100-
| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
101-
| <a href="https://www.storyblok.com/" target="_blank"><img src="https://github.com/typicode/json-server/assets/5502029/c6b10674-4ada-4616-91b8-59d30046b45a" height="35px"></a> | <a href="https://betterstack.com/" target="_blank"><img src="https://github.com/typicode/json-server/assets/5502029/44679f8f-9671-470d-b77e-26d90b90cbdc" height="35px"></a> |
102-
103-
[Become a sponsor and have your company logo here](https://github.com/users/typicode/sponsorship)
104-
105-
## Sponsorware
106-
107-
> [!NOTE]
108-
> This project uses the [Fair Source License](https://fair.io/). Only organizations with 3+ users are kindly asked to contribute a small amount through sponsorship [sponsor](https://github.com/sponsors/typicode) for usage. **This license helps keep the project sustainable and healthy, benefiting everyone.**
109-
>
110-
> For more information, FAQs, and the rationale behind this, visit [https://fair.io/](https://fair.io/).
53+
```http
54+
GET /posts?views:gt=100
55+
GET /posts?_sort=-views
56+
GET /posts?_page=1&_per_page=10
57+
GET /posts?_embed=comments
58+
GET /posts?_where={"or":[{"views":{"gt":100}},{"title":{"eq":"Hello"}}]}
59+
```
11160

11261
## Routes
11362

114-
Based on the example `db.json`, you'll get the following routes:
63+
For array resources (`posts`, `comments`):
11564

116-
```
65+
```text
11766
GET /posts
11867
GET /posts/:id
11968
POST /posts
12069
PUT /posts/:id
12170
PATCH /posts/:id
12271
DELETE /posts/:id
123-
124-
# Same for comments
12572
```
12673

127-
```
74+
For object resources (`profile`):
75+
76+
```text
12877
GET /profile
12978
PUT /profile
13079
PATCH /profile
13180
```
13281

133-
## Params
82+
## Query params
13483

13584
### Conditions
13685

137-
- ` ``==`
138-
- `lt``<`
139-
- `lte``<=`
140-
- `gt``>`
141-
- `gte``>=`
142-
- `ne``!=`
86+
Use `field:operator=value`.
14387

144-
```
145-
GET /posts?views_gt=9000
146-
```
88+
Operators:
14789

148-
### Range
90+
- no operator -> `eq` (equal)
91+
- `lt` less than, `lte` less than or equal
92+
- `gt` greater than, `gte` greater than or equal
93+
- `eq` equal, `ne` not equal
14994

150-
- `start`
151-
- `end`
152-
- `limit`
95+
Examples:
15396

154-
```
155-
GET /posts?_start=10&_end=20
156-
GET /posts?_start=10&_limit=10
157-
```
158-
159-
### Paginate
160-
161-
- `page`
162-
- `per_page` (default = 10)
163-
164-
```
165-
GET /posts?_page=1&_per_page=25
97+
```http
98+
GET /posts?views:gt=100
99+
GET /posts?title:eq=Hello
100+
GET /posts?author.name:eq=typicode
166101
```
167102

168103
### Sort
169104

170-
- `_sort=f1,f2`
171-
172-
```
173-
GET /posts?_sort=id,-views
105+
```http
106+
GET /posts?_sort=title
107+
GET /posts?_sort=-views
108+
GET /posts?_sort=author.name,-views
174109
```
175110

176-
### Nested and array fields
111+
### Pagination
177112

178-
- `x.y.z...`
179-
- `x.y.z[i]...`
180-
181-
```
182-
GET /foo?a.b=bar
183-
GET /foo?x.y_lt=100
184-
GET /foo?arr[0]=bar
113+
```http
114+
GET /posts?_page=1&_per_page=25
185115
```
186116

117+
- `_per_page` default is `10`
118+
- invalid page/per_page values are normalized
119+
187120
### Embed
188121

189-
```
122+
```http
190123
GET /posts?_embed=comments
191124
GET /comments?_embed=post
192125
```
193126

194-
## Delete
127+
### Complex filter with `_where`
128+
129+
`_where` accepts a JSON object and overrides normal query params when valid.
195130

131+
```http
132+
GET /posts?_where={"or":[{"views":{"gt":100}},{"author":{"name":{"lt":"m"}}}]}
196133
```
197-
DELETE /posts/1
134+
135+
## Delete dependents
136+
137+
```http
198138
DELETE /posts/1?_dependent=comments
199139
```
200140

201-
## Serving static files
141+
## Static files
202142

203-
If you create a `./public` directory, JSON Server will serve its content in addition to the REST API.
143+
JSON Server serves `./public` automatically.
204144

205-
You can also add custom directories using `-s/--static` option.
145+
Add more static dirs:
206146

207147
```sh
208148
json-server -s ./static
209149
json-server -s ./static -s ./node_modules
210150
```
211151

212-
## Notable differences with v0.17
152+
## Behavior notes
213153

214-
- `id` is always a string and will be generated for you if missing
215-
- use `_per_page` with `_page` instead of `_limit`for pagination
216-
- use Chrome's `Network tab > throtling` to delay requests instead of `--delay` CLI option
154+
- `id` is always a string and is generated if missing.
155+
- `_where` has priority over URL filter params.
156+
- Unknown operators in URL/query filters are ignored.

src/app.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,28 @@ await test('createApp', async (t) => {
118118
)
119119
})
120120
}
121+
122+
await t.test('GET /posts?_where=... uses JSON query', async () => {
123+
// Reset data since previous tests may have modified it
124+
db.data = {
125+
posts: [{ id: '1', title: 'foo' }],
126+
comments: [{ id: '1', postId: '1' }],
127+
object: { f1: 'foo' },
128+
}
129+
const where = encodeURIComponent(JSON.stringify({ title: { eq: 'foo' } }))
130+
const response = await fetch(`http://localhost:${port}/posts?_where=${where}`)
131+
assert.equal(response.status, 200)
132+
const data = await response.json()
133+
assert.deepEqual(data, [{ id: '1', title: 'foo' }])
134+
})
135+
136+
await t.test('GET /posts?_where=... overrides query params', async () => {
137+
const where = encodeURIComponent(JSON.stringify({ title: { eq: 'foo' } }))
138+
const response = await fetch(
139+
`http://localhost:${port}/posts?title:eq=bar&_where=${where}`,
140+
)
141+
assert.equal(response.status, 200)
142+
const data = await response.json()
143+
assert.deepEqual(data, [{ id: '1', title: 'foo' }])
144+
})
121145
})

0 commit comments

Comments
 (0)