You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/guide/getting-started.md
+10-4Lines changed: 10 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -41,18 +41,24 @@ app.get('/:id', async () => {
41
41
});
42
42
```
43
43
44
-
For Express and other framewords implementing Connect-style middleware, you will have to pass the response object into the contructor
44
+
For Express and other frameworks implementing Connect-style middleware, pass the `{ req, res }` context into the constructor. This enables both auto-send and [automatic URL detection](/guide/pagination-cursor-recipes#url-detection) for pagination links.
45
45
46
46
```ts
47
47
import { Resource } from'resora';
48
48
49
49
app.get('/:id', async (req, res) => {
50
50
const user = { id: req.params.id, name: 'John Doe' };
Copy file name to clipboardExpand all lines: docs/guide/pagination-cursor-recipes.md
+120-7Lines changed: 120 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,12 +9,12 @@ import { defineConfig } from 'resora';
9
9
10
10
exportdefaultdefineConfig({
11
11
paginatedExtras: ['meta', 'links'],
12
-
baseUrl: 'https://localhost',
12
+
baseUrl: '',
13
13
pageName: 'page',
14
14
});
15
15
```
16
16
17
-
When `pagination.path` is available on a collection resource, links are generated as absolute URLs.
17
+
When `pagination.path` is available on a collection resource, links are generated as path-relative URLs. If a `baseUrl` is configured or the request URL is [auto-detected from context](#url-detection), links become absolute.
18
18
19
19
Example:
20
20
@@ -27,8 +27,8 @@ Example:
27
27
"path": "/users"
28
28
},
29
29
"links": {
30
-
"prev": "https://localhost/users?page=1",
31
-
"next": "https://localhost/users?page=3"
30
+
"prev": "/users?page=1",
31
+
"next": "/users?page=3"
32
32
}
33
33
}
34
34
```
@@ -142,8 +142,8 @@ Example output:
142
142
"endpoint": "/users"
143
143
},
144
144
"links": {
145
-
"previous": "https://localhost/users?page=1",
146
-
"next": "https://localhost/users?page=3"
145
+
"previous": "/users?page=1",
146
+
"next": "/users?page=3"
147
147
}
148
148
}
149
149
```
@@ -152,4 +152,117 @@ Example output:
152
152
153
153
- Pagination links are generated from numeric page values (`firstPage`, `lastPage`, `prevPage`, `nextPage`) and `pagination.path`.
154
154
- If `paginatedExtras.cursor` is not configured, cursor values are emitted under `meta.cursor` by default.
155
-
-`baseUrl` should be set to your public API origin for production responses.
155
+
- Set `baseUrl` to your public API origin for absolute URLs in production, or use [URL auto-detection](#url-detection) to derive paths from the request context.
156
+
157
+
## 6. Automatic URL detection from request context {#url-detection}
158
+
159
+
When your pagination data does **not** include an explicit `path`, Resora can automatically detect the current request URL from the HTTP context and use it for link generation — including any existing query string parameters.
160
+
161
+
This works with both **Express** and **H3** because both expose a `{ req, res }` context shape.
162
+
163
+
### Passing context to the constructor
164
+
165
+
Pass the full `{ req, res }` context (or the framework event) as the second argument:
166
+
167
+
::: code-group
168
+
169
+
```ts [Express]
170
+
app.get('/api/users', async (req, res) => {
171
+
const users =awaitgetUsers(req.query);
172
+
173
+
// Pass { req, res } — Resora reads req.originalUrl for the path
174
+
returnawaitnewResourceCollection(users, { req, res });
175
+
});
176
+
```
177
+
178
+
```ts [H3]
179
+
exportdefaultdefineEventHandler((event) => {
180
+
const users =awaitgetUsers(getQuery(event));
181
+
182
+
// Pass the H3 event — Resora reads event.req.url
183
+
returnnewResourceCollection(users, event);
184
+
});
185
+
```
186
+
187
+
:::
188
+
189
+
If the user navigates to `/api/users?search=foo&sort=name`, the generated links will preserve the query string:
An explicit `pagination.path` always takes precedence over the auto-detected URL. If both are present, the explicit path wins.
213
+
:::
214
+
215
+
### Using `setCtx()` in middleware
216
+
217
+
If you prefer to set the request context once in a middleware (instead of passing it to each resource), use the static `setCtx()` method available on all serializer classes:
218
+
219
+
::: code-group
220
+
221
+
```ts [Express]
222
+
import { Resource } from'resora';
223
+
224
+
// Register middleware before your routes
225
+
app.use((req, res, next) => {
226
+
Resource.setCtx({ req, res });
227
+
next();
228
+
});
229
+
230
+
// In your route handler — no need to pass context
231
+
app.get('/api/users', async (req, res) => {
232
+
const users =awaitgetUsers(req.query);
233
+
returnawaitnewResourceCollection(users, res);
234
+
});
235
+
```
236
+
237
+
```ts [H3]
238
+
import { Resource } from'resora';
239
+
240
+
app.use((event) => {
241
+
Resource.setCtx(event);
242
+
});
243
+
244
+
exportdefaultdefineEventHandler((event) => {
245
+
returnnewResourceCollection(users);
246
+
});
247
+
```
248
+
249
+
:::
250
+
251
+
`setCtx()` is inherited by `Resource`, `ResourceCollection`, and `GenericResource` — calling it on any one of them makes the request URL available for all of them.
252
+
253
+
::: warning Request scoping
254
+
`setCtx()` stores the URL globally. If your application handles concurrent requests in a shared process, call `setCtx()` at the start of each request to ensure accuracy. For single-request-per-process runtimes (serverless, edge workers), this is automatic.
255
+
:::
256
+
257
+
### How URL extraction works
258
+
259
+
Resora inspects the context using the common `{ req, res }` interface:
260
+
261
+
| Framework | Request URL source | Example value |
| H3 |`req.url` (Web standard `Request`) |`http://localhost:3000/api/users?q=1`|
265
+
266
+
For H3's Web standard `Request`, the full URL is parsed and only the pathname + search is used for link generation.
267
+
268
+
If a bare response object is passed (without `req`), URL detection is skipped and the resource falls back to `pagination.path` or the bare `/?page=X` format.
Copy file name to clipboardExpand all lines: docs/guide/server-response.md
+4-2Lines changed: 4 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,9 +13,11 @@ Binds the internal Resource instance to a framework-specific response object.
13
13
### Parameters
14
14
15
15
-`res`
16
-
The framework’s native response object (e.g., H3 `res`, Express `res`).
16
+
The framework’s native response object (e.g., H3 `res`, Express `res`) or a full context object containing `{ req, res }`.
17
17
18
-
> For Express and other frameworks implementing the connect-style middleware, this can be skipped, in which case Resora will use the response object provided in the the `Resource` or `ResourceCollection` constructor which is required by default.
18
+
> For Express and other frameworks implementing the connect-style middleware, this can be skipped, in which case Resora will use the response object provided in the `Resource` or `ResourceCollection` constructor.
19
+
>
20
+
> The constructor accepts either a bare response object or a full `{ req, res }` context. When a context is passed, Resora also extracts the request URL for [automatic pagination link generation](/guide/pagination-cursor-recipes#url-detection).
0 commit comments