Skip to content

Commit 5a13803

Browse files
committed
feat: JSON query documentation and changeset
1 parent 9137699 commit 5a13803

7 files changed

Lines changed: 128 additions & 3 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@ts-rest/core': minor
3+
'@ts-rest/express': minor
4+
'@ts-rest/nest': minor
5+
'@ts-rest/next': minor
6+
'@ts-rest/open-api': minor
7+
'@ts-rest/react-query': minor
8+
'@ts-rest/solid-query': minor
9+
---
10+
11+
Allow typed query parameters by encoding them as JSON strings (disabled by default)

apps/docs/docs/core/core.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,27 @@ export const contract = c.router({
3939
});
4040
```
4141

42+
## Query Parameters
43+
44+
All query parameters, by default, need to have an input type of `string` since query strings inherently cannot be typed, however, ts-rest allows you to encode query parameters as JSON values.
45+
This will allow you to use input types other than strings in your contracts.
46+
47+
```typescript
48+
const c = initContract();
49+
export const contract = c.router({
50+
getPosts: {
51+
...,
52+
query: z.object({
53+
take: z.number().default(10),
54+
skip: z.number().default(0),
55+
search: z.string().optional(),
56+
}),
57+
}
58+
});
59+
```
60+
61+
Check the relevant sections to see how to enable JSON query encoding/decoding on the client or server.
62+
4263
## Combining Contracts
4364

4465
You can combine contracts to create a single contract, helpful if you want many sub contracts, especially if they are huge.

apps/docs/docs/core/fetch.md

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,52 @@ export const client = initClient(router, {
99
});
1010
```
1111

12-
### Query
12+
## Query
1313

1414
**Query** against the contract, a _query_ is a function that does a GET request to the api.
1515

1616
```typescript
1717
const { data } = await client.posts.get();
1818
```
1919

20-
### Mutate
20+
### Typed Query Parameters
21+
22+
By default, all query parameters are encoded as strings, however, you can use the `jsonQuery` option to encode query parameters as typed JSON values.
23+
Make sure to enable JSON query handling on the server as well.
24+
25+
```typescript
26+
const client = initClient(router, {
27+
baseUrl: 'http://localhost:3334',
28+
baseHeaders: {},
29+
jsonQuery: true,
30+
});
31+
32+
const { data } = await client.posts.get({
33+
query: {
34+
take: 10,
35+
skip: 0,
36+
search: 'hello',
37+
},
38+
});
39+
```
40+
41+
:::caution
42+
43+
Objects implementing `.toJSON()` will irreversibly be converted to JSON, so you will need to use custom zod transforms to convert back to the original object types.
44+
45+
For example, Date objects will be converted ISO strings by default, so you could handle this case like so:
46+
47+
```typescript
48+
const dateSchema = z
49+
.union([z.string().datetime(), z.date()])
50+
.transform((date) => (typeof date === 'string' ? new Date(date) : date));
51+
```
52+
53+
This will ensure that you could pass Date objects in your client queries. They will be converted to ISO strings in the JSON-encoded URL query string, and then converted back to Date objects on the server by zod's parser.
54+
55+
:::
56+
57+
## Mutate
2158

2259
**Mutate** against the contract, a _mutation_ is a function that does a POST, PUT, PATCH or DELETE request to the api.
2360

@@ -43,7 +80,7 @@ if (status === 200) {
4380
}
4481
```
4582

46-
### Return type
83+
## Return type
4784

4885
```typescript
4986
const data: {

apps/docs/docs/express.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,11 @@ createExpressEndpoints(router, completeRouter, app);
1818
```
1919

2020
`createExpressEndpoints` is a function that takes a router and a complete router, and creates endpoints, with the correct methods, paths and callbacks.
21+
22+
### JSON Query Parameters
23+
24+
To handle JSON query parameters, you can use the `jsonQuery` option.
25+
26+
```typescript
27+
createExpressEndpoints(router, completeRouter, app, { jsonQuery: true });
28+
```

apps/docs/docs/nest.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,34 @@ The `@Api` decorator takes the route, defines the path and method for the contro
2828

2929
It also injects "appRoute" into the req object, allowing the `@ApiDecorator` decorator automatically parse and check the query and body parameters.
3030

31+
### JSON Query Parameters
32+
33+
To handle JSON query parameters, you can use the `@JsonQuery()` decorator on either your Controller classes or individual endpoint methods.
34+
35+
```typescript
36+
@Controller()
37+
@JsonQuery()
38+
export class PostController implements ControllerShape {}
39+
40+
```
41+
42+
The method decorator can be useful to override the controller's behaviour on a per-endpoint basis.
43+
44+
```typescript
45+
46+
@Controller()
47+
@JsonQuery()
48+
export class PostController implements ControllerShape {
49+
constructor(private readonly postService: PostService) {}
50+
51+
@Api(s.route.getPost)
52+
@JsonQuery(false)
53+
async getPost(@ApiDecorator() { params: { id } }: RouteShape['getPost']) {
54+
// ...
55+
}
56+
}
57+
```
58+
3159
:::caution
3260

3361
Currently any existing Nest global prefix, versioning, or controller prefixes will be ignored, please see https://github.com/ts-rest/ts-rest/issues/70 for more details.

apps/docs/docs/next.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ export default createNextRouter(api, router);
3030

3131
`createNextRouter` is a function that takes a router and a complete router, and creates endpoints, with the correct methods, paths and callbacks.
3232

33+
### JSON Query Parameters
34+
35+
To handle JSON query parameters, you can use the `jsonQuery` option.
36+
37+
```typescript
38+
export default createNextRouter(api, router, { jsonQuery: true });
39+
```
40+
3341
## Future Work
3442

3543
As this pattern doesn't support a lambda per endpoint, it is planned to provide a helper utility to allow individual endpoints to be created.

apps/docs/docs/react-query.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ const App = () => {
3535
};
3636
```
3737

38+
### JSON Query Parameters
39+
40+
To enable encoding query parameters as typed JSON values, you can use the `jsonQuery` option.
41+
42+
```typescript
43+
export const client = initQueryClient(router, {
44+
baseUrl: 'http://localhost:3333',
45+
baseHeaders: {},
46+
jsonQuery: true,
47+
});
48+
```
49+
3850
## Regular Query and Mutations
3951

4052
`@ts-rest/react-query` allows for a regular fetch or mutation if you want, without having to initialise two different clients, one with `@ts-rest/core` and one with `@ts-react/react-query`.

0 commit comments

Comments
 (0)