Skip to content

Commit 41e3c2b

Browse files
committed
feat: enhance context handling in serializers and add tests for global context usage
1 parent f4c0f8c commit 41e3c2b

File tree

5 files changed

+57
-18
lines changed

5 files changed

+57
-18
lines changed

src/BaseSerializer.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ import {
1616
setCtx as setCtxState,
1717
} from './utilities'
1818

19+
import { H3Event } from 'h3'
20+
import { Response } from 'express'
21+
1922
interface SerializerConstructor {
2023
preferredCase?: CaseStyle
2124
responseStructure?: ResponseStructureConfig
@@ -37,6 +40,7 @@ export abstract class BaseSerializer<TResource = any> {
3740
static responseStructure?: ResponseStructureConfig
3841
static config?: () => ResourceLevelConfig
3942

43+
protected static ctx?: Response | H3Event | Record<string, any>
4044
protected instanceConfig?: ResourceLevelConfig
4145
protected additionalMeta?: MetaData
4246
protected called: {
@@ -67,6 +71,7 @@ export abstract class BaseSerializer<TResource = any> {
6771
*/
6872
static setCtx (ctx: unknown): void {
6973
setCtxState(ctx)
74+
this.ctx = ctx as any
7075
}
7176

7277
/**

src/GenericResource.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export class GenericResource<
5252

5353
constructor(rsc: R, ctx?: Response | H3Event | Record<string, any>) {
5454
super()
55+
if (ctx) GenericResource.ctx = ctx
5556
this.resource = rsc
5657

5758
if (ctx) {
@@ -350,21 +351,22 @@ export class GenericResource<
350351
* @param res
351352
*/
352353
response (res: H3Event['res']): ServerResponse<GenericBody<R>>
354+
response (res: Response): ServerResponse<GenericBody<R>>
353355
/**
354356
* Build a response object, writing to the provided raw response if possible.
355357
*
356358
* @param res
357359
* @returns
358360
*/
359-
response (res?: H3Event['res']): ServerResponse<GenericBody<R>> {
360-
const rawResponse = res ?? this.res as never
361+
response (res?: Response | H3Event['res']): ServerResponse<GenericBody<R>> {
362+
const rawResponse = res ?? this.res ?? (GenericResource.ctx as any)?.res as never
361363

362364
return this.runResponse({
363365
ensureJson: () => this.json(),
364366
rawResponse,
365367
body: () => this.body,
366368
createServerResponse: (raw, body) => {
367-
const response = new ServerResponse(raw, body)
369+
const response = new ServerResponse(raw as never, body)
368370
this.withResponseContext = {
369371
response,
370372
raw,
@@ -404,7 +406,7 @@ export class GenericResource<
404406
return this.runThen({
405407
ensureJson: () => this.json(),
406408
body: () => this.body,
407-
rawResponse: this.res,
409+
rawResponse: this.res ?? (GenericResource.ctx as any)?.res as never,
408410
createServerResponse: (raw, body) => {
409411
const response = new ServerResponse(raw as never, body)
410412
this.withResponseContext = {
@@ -437,7 +439,7 @@ export class GenericResource<
437439
return this.runThen({
438440
ensureJson: () => this.json(),
439441
body: () => this.body,
440-
rawResponse: this.res,
442+
rawResponse: this.res ?? (GenericResource.ctx as any)?.res as never,
441443
createServerResponse: (raw, body) => {
442444
const response = new ServerResponse(raw as never, body)
443445
this.withResponseContext = {
@@ -467,7 +469,7 @@ export class GenericResource<
467469
return this.runThen({
468470
ensureJson: () => this.json(),
469471
body: () => this.body,
470-
rawResponse: this.res,
472+
rawResponse: this.res ?? (GenericResource.ctx as any)?.res as never,
471473
createServerResponse: (raw, body) => {
472474
const response = new ServerResponse(raw as never, body)
473475
this.withResponseContext = {

src/Resource.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export class Resource<R extends ResourceData | NonCollectible = ResourceData> ex
4545

4646
constructor(rsc: R, ctx?: Response | H3Event | Record<string, any>) {
4747
super()
48+
if (ctx) Resource.ctx = ctx
4849
this.resource = rsc
4950

5051
if (ctx) {
@@ -275,21 +276,22 @@ export class Resource<R extends ResourceData | NonCollectible = ResourceData> ex
275276
* @param res Optional raw response object (e.g. Express Response or H3Event res)
276277
*/
277278
response (res: H3Event['res']): ServerResponse<ResourceBody<R>>
279+
response (res: Response): ServerResponse<ResourceBody<R>>
278280
/**
279281
* Build a response object, optionally accepting a raw response to mutate in withResponse.
280282
*
281283
* @param res Optional raw response object (e.g. Express Response or H3Event res)
282284
* @returns
283285
*/
284-
response (res?: H3Event['res']): ServerResponse<ResourceBody<R>> {
285-
const rawResponse = res ?? this.res as never
286+
response (res?: H3Event['res'] | Response): ServerResponse<ResourceBody<R>> {
287+
const rawResponse = res ?? this.res ?? (Resource.ctx as any)?.res as never
286288

287289
return this.runResponse({
288290
ensureJson: () => this.json(),
289291
rawResponse,
290292
body: () => this.body,
291293
createServerResponse: (raw, body) => {
292-
const response = new ServerResponse(raw, body)
294+
const response = new ServerResponse(raw as never, body)
293295
this.withResponseContext = {
294296
response,
295297
raw,
@@ -329,7 +331,7 @@ export class Resource<R extends ResourceData | NonCollectible = ResourceData> ex
329331
return this.runThen({
330332
ensureJson: () => this.json(),
331333
body: () => this.body,
332-
rawResponse: this.res,
334+
rawResponse: this.res ?? (Resource.ctx as any)?.res as never,
333335
createServerResponse: (raw, body) => {
334336
const response = new ServerResponse(raw as never, body)
335337
this.withResponseContext = {
@@ -362,7 +364,7 @@ export class Resource<R extends ResourceData | NonCollectible = ResourceData> ex
362364
return this.runThen({
363365
ensureJson: () => this.json(),
364366
body: () => this.body,
365-
rawResponse: this.res,
367+
rawResponse: this.res ?? (Resource.ctx as any)?.res as never,
366368
createServerResponse: (raw, body) => {
367369
const response = new ServerResponse(raw as never, body)
368370
this.withResponseContext = {
@@ -392,7 +394,7 @@ export class Resource<R extends ResourceData | NonCollectible = ResourceData> ex
392394
return this.runThen({
393395
ensureJson: () => this.json(),
394396
body: () => this.body,
395-
rawResponse: this.res,
397+
rawResponse: this.res ?? (Resource.ctx as any)?.res as never,
396398
createServerResponse: (raw, body) => {
397399
const response = new ServerResponse(raw as never, body)
398400
this.withResponseContext = {

src/ResourceCollection.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export class ResourceCollection<
8181
constructor(rsc: R, ctx: Response | H3Event | Record<string, any>)
8282
constructor(rsc: R, ctx?: Response | H3Event | Record<string, any>) {
8383
super()
84+
if (ctx) ResourceCollection.ctx = ctx
8485
this.resource = rsc
8586

8687
if (ctx) {
@@ -333,17 +334,31 @@ export class ResourceCollection<
333334
return this
334335
}
335336

337+
/**
338+
* Build a response object, optionally accepting a raw response to mutate in withResponse.
339+
*/
336340
response (): ServerResponse<CollectionBody<R>>
341+
/**
342+
* Build a response object, optionally accepting a raw response to mutate in withResponse.
343+
* @param res Optional raw response object (e.g. Express Response or H3Event res)
344+
*/
337345
response (res: H3Event['res']): ServerResponse<CollectionBody<R>>
338-
response (res?: H3Event['res']): ServerResponse<CollectionBody<R>> {
339-
const rawResponse = res ?? this.res as never
346+
response (res: Response): ServerResponse<CollectionBody<R>>
347+
/**
348+
* Build a response object, optionally accepting a raw response to mutate in withResponse.
349+
*
350+
* @param res Optional raw response object (e.g. Express Response or H3Event res)
351+
* @returns
352+
*/
353+
response (res?: H3Event['res'] | Response): ServerResponse<CollectionBody<R>> {
354+
const rawResponse = res ?? this.res ?? (this.ctx as any)?.res as never
340355

341356
return this.runResponse({
342357
ensureJson: () => this.json(),
343358
rawResponse,
344359
body: () => this.body,
345360
createServerResponse: (raw, body) => {
346-
const response = new ServerResponse(raw, body)
361+
const response = new ServerResponse(raw as never, body)
347362
this.withResponseContext = {
348363
response,
349364
raw,
@@ -389,7 +404,7 @@ export class ResourceCollection<
389404
return this.runThen({
390405
ensureJson: () => this.json(),
391406
body: () => this.body,
392-
rawResponse: this.res,
407+
rawResponse: this.res ?? (ResourceCollection.ctx as any)?.res as never,
393408
createServerResponse: (raw, body) => {
394409
const response = new ServerResponse(raw as never, body)
395410
this.withResponseContext = {
@@ -422,7 +437,7 @@ export class ResourceCollection<
422437
return this.runThen({
423438
ensureJson: () => this.json(),
424439
body: () => this.body,
425-
rawResponse: this.res,
440+
rawResponse: this.res ?? (ResourceCollection.ctx as any)?.res as never,
426441
createServerResponse: (raw, body) => {
427442
const response = new ServerResponse(raw as never, body)
428443
this.withResponseContext = {
@@ -452,7 +467,7 @@ export class ResourceCollection<
452467
return this.runThen({
453468
ensureJson: () => this.json(),
454469
body: () => this.body,
455-
rawResponse: this.res,
470+
rawResponse: this.res ?? (ResourceCollection.ctx as any)?.res as never,
456471
createServerResponse: (raw, body) => {
457472
const response = new ServerResponse(raw as never, body)
458473
this.withResponseContext = {

tests/express.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,21 @@ describe('Connect-style Requests (Express)', () => {
2222
expect(response.body).toEqual({ data: resource })
2323
})
2424

25+
it('should can use the global context object', async () => {
26+
const resource = { id: 1, name: 'Test Resource' }
27+
app.get('/test', async (req, res) => {
28+
Resource.setCtx({ res, req })
29+
30+
return await new Resource(resource)
31+
.response()
32+
.setStatusCode(202)
33+
})
34+
35+
const response = await supertest(app).get('/test')
36+
expect(response.body).toEqual({ data: resource })
37+
expect(response.status).toEqual(202)
38+
})
39+
2540
it('should allow chaining of methods', async () => {
2641
const resource = { id: 1, name: 'Test Resource' }
2742
app.get('/test', async (req, res) => {

0 commit comments

Comments
 (0)