@orpc/server 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-TDFYNRZV.js → chunk-CVLK2PBB.js} +0 -1
- package/dist/fetch.js +1 -2
- package/dist/index.js +1 -2
- package/dist/src/adapters/fetch.d.ts +0 -1
- package/dist/src/builder.d.ts +0 -1
- package/dist/src/index.d.ts +0 -1
- package/dist/src/middleware.d.ts +0 -1
- package/dist/src/procedure-builder.d.ts +0 -1
- package/dist/src/procedure-caller.d.ts +0 -1
- package/dist/src/procedure-implementer.d.ts +0 -1
- package/dist/src/procedure.d.ts +0 -1
- package/dist/src/router-builder.d.ts +0 -1
- package/dist/src/router-caller.d.ts +0 -1
- package/dist/src/router-implementer.d.ts +0 -1
- package/dist/src/router.d.ts +0 -1
- package/dist/src/types.d.ts +0 -1
- package/dist/src/utils.d.ts +0 -1
- package/package.json +12 -16
- package/dist/chunk-TDFYNRZV.js.map +0 -1
- package/dist/fetch.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/src/adapters/fetch.d.ts.map +0 -1
- package/dist/src/builder.d.ts.map +0 -1
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/middleware.d.ts.map +0 -1
- package/dist/src/procedure-builder.d.ts.map +0 -1
- package/dist/src/procedure-caller.d.ts.map +0 -1
- package/dist/src/procedure-implementer.d.ts.map +0 -1
- package/dist/src/procedure.d.ts.map +0 -1
- package/dist/src/router-builder.d.ts.map +0 -1
- package/dist/src/router-caller.d.ts.map +0 -1
- package/dist/src/router-implementer.d.ts.map +0 -1
- package/dist/src/router.d.ts.map +0 -1
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/utils.d.ts.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/adapters/fetch.test.ts +0 -629
- package/src/adapters/fetch.ts +0 -290
- package/src/builder.test.ts +0 -371
- package/src/builder.ts +0 -238
- package/src/index.ts +0 -16
- package/src/middleware.test.ts +0 -260
- package/src/middleware.ts +0 -136
- package/src/procedure-builder.test.ts +0 -223
- package/src/procedure-builder.ts +0 -158
- package/src/procedure-caller.test.ts +0 -171
- package/src/procedure-caller.ts +0 -138
- package/src/procedure-implementer.test.ts +0 -220
- package/src/procedure-implementer.ts +0 -102
- package/src/procedure.test.ts +0 -317
- package/src/procedure.ts +0 -237
- package/src/router-builder.test.ts +0 -106
- package/src/router-builder.ts +0 -122
- package/src/router-caller.test.ts +0 -126
- package/src/router-caller.ts +0 -64
- package/src/router-implementer.test.ts +0 -116
- package/src/router-implementer.ts +0 -113
- package/src/router.test-d.ts +0 -48
- package/src/router.test.ts +0 -142
- package/src/router.ts +0 -91
- package/src/types.test.ts +0 -18
- package/src/types.ts +0 -13
- package/src/utils.test.ts +0 -16
- package/src/utils.ts +0 -16
@@ -1,629 +0,0 @@
|
|
1
|
-
import { ORPC_HEADER, ORPC_HEADER_VALUE } from '@orpc/contract'
|
2
|
-
import { oz } from '@orpc/zod'
|
3
|
-
import { describe, expect, it } from 'vitest'
|
4
|
-
import { z } from 'zod'
|
5
|
-
import { ORPCError, os } from '..'
|
6
|
-
import { createFetchHandler } from './fetch'
|
7
|
-
|
8
|
-
const router = os.router({
|
9
|
-
throw: os.func(() => {
|
10
|
-
throw new Error('test')
|
11
|
-
}),
|
12
|
-
ping: os.func(() => {
|
13
|
-
return 'ping'
|
14
|
-
}),
|
15
|
-
ping2: os.route({ method: 'GET', path: '/ping2' }).func(() => {
|
16
|
-
return 'ping2'
|
17
|
-
}),
|
18
|
-
})
|
19
|
-
|
20
|
-
const handler = createFetchHandler({ router })
|
21
|
-
|
22
|
-
describe('simple', () => {
|
23
|
-
const osw = os.context<{ auth?: boolean }>()
|
24
|
-
const router = osw.router({
|
25
|
-
ping: osw.func(async () => 'pong'),
|
26
|
-
ping2: osw
|
27
|
-
.route({ method: 'GET', path: '/ping2' })
|
28
|
-
.func(async () => 'pong2'),
|
29
|
-
})
|
30
|
-
const handler = createFetchHandler({
|
31
|
-
router,
|
32
|
-
})
|
33
|
-
|
34
|
-
it('200: public url', async () => {
|
35
|
-
const response = await handler({
|
36
|
-
prefix: '/orpc',
|
37
|
-
request: new Request('http://localhost/orpc/ping', {
|
38
|
-
method: 'POST',
|
39
|
-
}),
|
40
|
-
context: () => ({ auth: true }),
|
41
|
-
})
|
42
|
-
|
43
|
-
expect(response.status).toBe(200)
|
44
|
-
expect(await response.json()).toEqual('pong')
|
45
|
-
|
46
|
-
const response2 = await handler({
|
47
|
-
prefix: '/orpc',
|
48
|
-
request: new Request('http://localhost/orpc/ping2', {
|
49
|
-
method: 'GET',
|
50
|
-
}),
|
51
|
-
context: { auth: true },
|
52
|
-
})
|
53
|
-
|
54
|
-
expect(response2.status).toBe(200)
|
55
|
-
expect(await response2.json()).toEqual('pong2')
|
56
|
-
})
|
57
|
-
|
58
|
-
it('200: internal url', async () => {
|
59
|
-
const response = await handler({
|
60
|
-
request: new Request('http://localhost/ping'),
|
61
|
-
context: { auth: true },
|
62
|
-
})
|
63
|
-
|
64
|
-
expect(response.status).toBe(200)
|
65
|
-
expect(await response.json()).toEqual('pong')
|
66
|
-
|
67
|
-
const response2 = await handler({
|
68
|
-
prefix: '/orpc',
|
69
|
-
request: new Request('http://localhost/orpc/ping2'),
|
70
|
-
context: { auth: true },
|
71
|
-
})
|
72
|
-
|
73
|
-
expect(response2.status).toBe(200)
|
74
|
-
expect(await response2.json()).toEqual('pong2')
|
75
|
-
})
|
76
|
-
|
77
|
-
it('404', async () => {
|
78
|
-
const response = await handler({
|
79
|
-
prefix: '/orpc',
|
80
|
-
request: new Request('http://localhost/orpc/pingp', {
|
81
|
-
method: 'POST',
|
82
|
-
}),
|
83
|
-
context: { auth: true },
|
84
|
-
})
|
85
|
-
|
86
|
-
expect(response.status).toBe(404)
|
87
|
-
})
|
88
|
-
})
|
89
|
-
|
90
|
-
describe('procedure throw error', () => {
|
91
|
-
it('unknown error', async () => {
|
92
|
-
const response = await handler({
|
93
|
-
request: new Request('https://local.com/throw', { method: 'POST' }),
|
94
|
-
})
|
95
|
-
|
96
|
-
expect(response.status).toBe(500)
|
97
|
-
expect(await response.json()).toEqual({
|
98
|
-
code: 'INTERNAL_SERVER_ERROR',
|
99
|
-
status: 500,
|
100
|
-
message: 'Internal server error',
|
101
|
-
})
|
102
|
-
})
|
103
|
-
|
104
|
-
it('orpc error', async () => {
|
105
|
-
const router = os.router({
|
106
|
-
ping: os.func(() => {
|
107
|
-
throw new ORPCError({ code: 'TIMEOUT' })
|
108
|
-
}),
|
109
|
-
})
|
110
|
-
|
111
|
-
const handler = createFetchHandler({ router })
|
112
|
-
|
113
|
-
const response = await handler({
|
114
|
-
request: new Request('https://local.com/ping', { method: 'POST' }),
|
115
|
-
})
|
116
|
-
|
117
|
-
expect(response.status).toBe(408)
|
118
|
-
expect(await response.json()).toEqual({
|
119
|
-
code: 'TIMEOUT',
|
120
|
-
status: 408,
|
121
|
-
message: '',
|
122
|
-
})
|
123
|
-
})
|
124
|
-
|
125
|
-
it('orpc error with data', async () => {
|
126
|
-
const router = os.router({
|
127
|
-
ping: os.func(() => {
|
128
|
-
throw new ORPCError({
|
129
|
-
code: 'PAYLOAD_TOO_LARGE',
|
130
|
-
message: 'test',
|
131
|
-
data: { max: '10mb' },
|
132
|
-
})
|
133
|
-
}),
|
134
|
-
})
|
135
|
-
|
136
|
-
const handler = createFetchHandler({ router })
|
137
|
-
|
138
|
-
const response = await handler({
|
139
|
-
request: new Request('https://local.com/ping', { method: 'POST' }),
|
140
|
-
})
|
141
|
-
|
142
|
-
expect(response.status).toBe(413)
|
143
|
-
expect(await response.json()).toEqual({
|
144
|
-
code: 'PAYLOAD_TOO_LARGE',
|
145
|
-
status: 413,
|
146
|
-
message: 'test',
|
147
|
-
data: { max: '10mb' },
|
148
|
-
})
|
149
|
-
})
|
150
|
-
|
151
|
-
it('orpc error with custom status', async () => {
|
152
|
-
const router = os.router({
|
153
|
-
ping: os.func(() => {
|
154
|
-
throw new ORPCError({
|
155
|
-
code: 'PAYLOAD_TOO_LARGE',
|
156
|
-
status: 100,
|
157
|
-
})
|
158
|
-
}),
|
159
|
-
|
160
|
-
ping2: os.func(() => {
|
161
|
-
throw new ORPCError({
|
162
|
-
code: 'PAYLOAD_TOO_LARGE',
|
163
|
-
status: 488,
|
164
|
-
})
|
165
|
-
}),
|
166
|
-
})
|
167
|
-
|
168
|
-
const handler = createFetchHandler({ router })
|
169
|
-
|
170
|
-
const response = await handler({
|
171
|
-
request: new Request('https://local.com/ping', { method: 'POST' }),
|
172
|
-
})
|
173
|
-
|
174
|
-
expect(response.status).toBe(500)
|
175
|
-
expect(await response.json()).toEqual({
|
176
|
-
code: 'INTERNAL_SERVER_ERROR',
|
177
|
-
status: 500,
|
178
|
-
message: 'Internal server error',
|
179
|
-
})
|
180
|
-
|
181
|
-
const response2 = await handler({
|
182
|
-
request: new Request('https://local.com/ping2', { method: 'POST' }),
|
183
|
-
})
|
184
|
-
|
185
|
-
expect(response2.status).toBe(488)
|
186
|
-
expect(await response2.json()).toEqual({
|
187
|
-
code: 'PAYLOAD_TOO_LARGE',
|
188
|
-
status: 488,
|
189
|
-
message: '',
|
190
|
-
})
|
191
|
-
})
|
192
|
-
|
193
|
-
it('input validation error', async () => {
|
194
|
-
const router = os.router({
|
195
|
-
ping: os
|
196
|
-
.input(z.object({}))
|
197
|
-
.output(z.string())
|
198
|
-
.func(() => {
|
199
|
-
return 'unnoq'
|
200
|
-
}),
|
201
|
-
})
|
202
|
-
|
203
|
-
const handler = createFetchHandler({ router })
|
204
|
-
|
205
|
-
const response = await handler({
|
206
|
-
request: new Request('https://local.com/ping', { method: 'POST' }),
|
207
|
-
})
|
208
|
-
|
209
|
-
expect(response.status).toBe(400)
|
210
|
-
expect(await response.json()).toEqual({
|
211
|
-
code: 'BAD_REQUEST',
|
212
|
-
status: 400,
|
213
|
-
message: 'Validation input failed',
|
214
|
-
issues: [
|
215
|
-
{
|
216
|
-
code: 'invalid_type',
|
217
|
-
expected: 'object',
|
218
|
-
message: 'Required',
|
219
|
-
path: [],
|
220
|
-
received: 'undefined',
|
221
|
-
},
|
222
|
-
],
|
223
|
-
})
|
224
|
-
})
|
225
|
-
|
226
|
-
it('output validation error', async () => {
|
227
|
-
const router = os.router({
|
228
|
-
ping: os
|
229
|
-
.input(z.string())
|
230
|
-
.output(z.string())
|
231
|
-
.func(() => {
|
232
|
-
return 12344 as any
|
233
|
-
}),
|
234
|
-
})
|
235
|
-
|
236
|
-
const handler = createFetchHandler({ router })
|
237
|
-
|
238
|
-
const response = await handler({
|
239
|
-
request: new Request('https://local.com/ping', {
|
240
|
-
method: 'POST',
|
241
|
-
body: '"hi"',
|
242
|
-
}),
|
243
|
-
})
|
244
|
-
|
245
|
-
expect(response.status).toBe(500)
|
246
|
-
expect(await response.json()).toEqual({
|
247
|
-
code: 'INTERNAL_SERVER_ERROR',
|
248
|
-
status: 500,
|
249
|
-
message: 'Validation output failed',
|
250
|
-
})
|
251
|
-
})
|
252
|
-
})
|
253
|
-
|
254
|
-
describe('hooks', () => {
|
255
|
-
it('on success', async () => {
|
256
|
-
const onSuccess = vi.fn()
|
257
|
-
const onError = vi.fn()
|
258
|
-
const onFinish = vi.fn()
|
259
|
-
|
260
|
-
const handler = createFetchHandler({
|
261
|
-
router,
|
262
|
-
hooks: async (context, hooks) => {
|
263
|
-
try {
|
264
|
-
const response = await hooks.next()
|
265
|
-
onSuccess(response)
|
266
|
-
return response
|
267
|
-
}
|
268
|
-
catch (e) {
|
269
|
-
onError(e)
|
270
|
-
throw e
|
271
|
-
}
|
272
|
-
finally {
|
273
|
-
onFinish()
|
274
|
-
}
|
275
|
-
},
|
276
|
-
})
|
277
|
-
|
278
|
-
await handler({
|
279
|
-
prefix: '/orpc',
|
280
|
-
request: new Request('http://localhost/orpc/ping', {
|
281
|
-
method: 'POST',
|
282
|
-
}),
|
283
|
-
})
|
284
|
-
|
285
|
-
expect(onSuccess).toHaveBeenCalledTimes(1)
|
286
|
-
expect(onError).toHaveBeenCalledTimes(0)
|
287
|
-
expect(onFinish).toHaveBeenCalledTimes(1)
|
288
|
-
|
289
|
-
expect(onSuccess.mock.calls[0]?.[0]).toBeInstanceOf(Response)
|
290
|
-
expect(onFinish.mock.calls[0]?.[1]).toBe(undefined)
|
291
|
-
})
|
292
|
-
|
293
|
-
it('on failed', async () => {
|
294
|
-
const onSuccess = vi.fn()
|
295
|
-
const onError = vi.fn()
|
296
|
-
const onFinish = vi.fn()
|
297
|
-
|
298
|
-
const handler = createFetchHandler({
|
299
|
-
router,
|
300
|
-
hooks: async (context, hooks) => {
|
301
|
-
try {
|
302
|
-
const response = await hooks.next()
|
303
|
-
onSuccess(response)
|
304
|
-
return response
|
305
|
-
}
|
306
|
-
catch (e) {
|
307
|
-
onError(e)
|
308
|
-
throw e
|
309
|
-
}
|
310
|
-
finally {
|
311
|
-
onFinish()
|
312
|
-
}
|
313
|
-
},
|
314
|
-
})
|
315
|
-
|
316
|
-
await handler({
|
317
|
-
prefix: '/orpc',
|
318
|
-
request: new Request('http://localhost/orpc/throw', {
|
319
|
-
method: 'POST',
|
320
|
-
}),
|
321
|
-
})
|
322
|
-
|
323
|
-
expect(onSuccess).toHaveBeenCalledTimes(0)
|
324
|
-
expect(onError).toHaveBeenCalledTimes(1)
|
325
|
-
expect(onFinish).toHaveBeenCalledTimes(1)
|
326
|
-
|
327
|
-
expect(onError.mock.calls[0]?.[0]).toBeInstanceOf(Error)
|
328
|
-
expect(onError.mock.calls[0]?.[0]?.message).toBe('test')
|
329
|
-
expect(onFinish.mock.calls[0]?.[0]).toBe(undefined)
|
330
|
-
})
|
331
|
-
})
|
332
|
-
|
333
|
-
describe('file upload', () => {
|
334
|
-
const router = os.router({
|
335
|
-
signal: os.input(z.instanceof(Blob)).func((input) => {
|
336
|
-
return input
|
337
|
-
}),
|
338
|
-
multiple: os
|
339
|
-
.input(
|
340
|
-
z.object({ first: z.instanceof(Blob), second: z.instanceof(Blob) }),
|
341
|
-
)
|
342
|
-
.func((input) => {
|
343
|
-
return input
|
344
|
-
}),
|
345
|
-
})
|
346
|
-
|
347
|
-
const handler = createFetchHandler({ router })
|
348
|
-
|
349
|
-
const blob1 = new Blob(['hello'], { type: 'text/plain;charset=utf-8' })
|
350
|
-
const blob2 = new Blob(['"world"'], { type: 'image/png' })
|
351
|
-
const blob3 = new Blob(['unnoq'], { type: 'application/octet-stream' })
|
352
|
-
|
353
|
-
it('single file', async () => {
|
354
|
-
const rForm = new FormData()
|
355
|
-
rForm.set('meta', JSON.stringify([]))
|
356
|
-
rForm.set('maps', JSON.stringify([[]]))
|
357
|
-
rForm.set('0', blob3)
|
358
|
-
|
359
|
-
const response = await handler({
|
360
|
-
prefix: '/orpc',
|
361
|
-
request: new Request('http://localhost/orpc/signal', {
|
362
|
-
method: 'POST',
|
363
|
-
body: rForm,
|
364
|
-
headers: {
|
365
|
-
[ORPC_HEADER]: ORPC_HEADER_VALUE,
|
366
|
-
},
|
367
|
-
}),
|
368
|
-
})
|
369
|
-
|
370
|
-
expect(response.status).toBe(200)
|
371
|
-
const form = await response.formData()
|
372
|
-
|
373
|
-
const file0 = form.get('0') as File
|
374
|
-
expect(file0).toBeInstanceOf(File)
|
375
|
-
expect(file0.name).toBe('blob')
|
376
|
-
expect(file0.type).toBe('application/octet-stream')
|
377
|
-
expect(await file0.text()).toBe('unnoq')
|
378
|
-
})
|
379
|
-
|
380
|
-
it('multiple file', async () => {
|
381
|
-
const form = new FormData()
|
382
|
-
form.set('data', JSON.stringify({ first: blob1, second: blob2 }))
|
383
|
-
form.set('meta', JSON.stringify([]))
|
384
|
-
form.set('maps', JSON.stringify([['first'], ['second']]))
|
385
|
-
form.set('0', blob1)
|
386
|
-
form.set('1', blob2)
|
387
|
-
|
388
|
-
const response = await handler({
|
389
|
-
prefix: '/orpc',
|
390
|
-
request: new Request('http://localhost/orpc/multiple', {
|
391
|
-
method: 'POST',
|
392
|
-
body: form,
|
393
|
-
headers: {
|
394
|
-
[ORPC_HEADER]: ORPC_HEADER_VALUE,
|
395
|
-
},
|
396
|
-
}),
|
397
|
-
})
|
398
|
-
|
399
|
-
expect(response.status).toBe(200)
|
400
|
-
|
401
|
-
const form_ = await response.formData()
|
402
|
-
const file0 = form_.get('0') as File
|
403
|
-
const file1 = form_.get('1') as File
|
404
|
-
|
405
|
-
expect(file0).toBeInstanceOf(File)
|
406
|
-
expect(file0.name).toBe('blob')
|
407
|
-
expect(file0.type).toBe('text/plain;charset=utf-8')
|
408
|
-
expect(await file0.text()).toBe('hello')
|
409
|
-
|
410
|
-
expect(file1).toBeInstanceOf(File)
|
411
|
-
expect(file1.name).toBe('blob')
|
412
|
-
expect(file1.type).toBe('image/png')
|
413
|
-
expect(await file1.text()).toBe('"world"')
|
414
|
-
})
|
415
|
-
})
|
416
|
-
|
417
|
-
describe('accept header', () => {
|
418
|
-
const router = os.router({
|
419
|
-
ping: os.func(async () => 'pong'),
|
420
|
-
})
|
421
|
-
const handler = createFetchHandler({
|
422
|
-
router,
|
423
|
-
})
|
424
|
-
|
425
|
-
it('application/json', async () => {
|
426
|
-
const response = await handler({
|
427
|
-
prefix: '/orpc',
|
428
|
-
request: new Request('http://localhost/orpc/ping', {
|
429
|
-
method: 'POST',
|
430
|
-
headers: {
|
431
|
-
Accept: 'application/json',
|
432
|
-
},
|
433
|
-
}),
|
434
|
-
})
|
435
|
-
|
436
|
-
expect(response.headers.get('Content-Type')).toEqual('application/json')
|
437
|
-
|
438
|
-
expect(await response.json()).toEqual('pong')
|
439
|
-
})
|
440
|
-
|
441
|
-
it('multipart/form-data', async () => {
|
442
|
-
const response = await handler({
|
443
|
-
prefix: '/orpc',
|
444
|
-
request: new Request('http://localhost/orpc/ping', {
|
445
|
-
method: 'POST',
|
446
|
-
headers: {
|
447
|
-
Accept: 'multipart/form-data',
|
448
|
-
},
|
449
|
-
}),
|
450
|
-
})
|
451
|
-
|
452
|
-
expect(response.headers.get('Content-Type')).toContain(
|
453
|
-
'multipart/form-data',
|
454
|
-
)
|
455
|
-
|
456
|
-
const form = await response.formData()
|
457
|
-
expect(form.get('')).toEqual('pong')
|
458
|
-
})
|
459
|
-
|
460
|
-
it('application/x-www-form-urlencoded', async () => {
|
461
|
-
const response = await handler({
|
462
|
-
prefix: '/orpc',
|
463
|
-
request: new Request('http://localhost/orpc/ping', {
|
464
|
-
method: 'POST',
|
465
|
-
headers: {
|
466
|
-
Accept: 'application/x-www-form-urlencoded',
|
467
|
-
},
|
468
|
-
}),
|
469
|
-
})
|
470
|
-
|
471
|
-
expect(response.headers.get('Content-Type')).toEqual(
|
472
|
-
'application/x-www-form-urlencoded',
|
473
|
-
)
|
474
|
-
|
475
|
-
const params = new URLSearchParams(await response.text())
|
476
|
-
expect(params.get('')).toEqual('pong')
|
477
|
-
})
|
478
|
-
|
479
|
-
it('*/*', async () => {
|
480
|
-
const response = await handler({
|
481
|
-
prefix: '/orpc',
|
482
|
-
request: new Request('http://localhost/orpc/ping', {
|
483
|
-
method: 'POST',
|
484
|
-
headers: {
|
485
|
-
Accept: '*/*',
|
486
|
-
},
|
487
|
-
}),
|
488
|
-
})
|
489
|
-
|
490
|
-
expect(response.headers.get('Content-Type')).toEqual('application/json')
|
491
|
-
expect(await response.json()).toEqual('pong')
|
492
|
-
})
|
493
|
-
|
494
|
-
it('invalid', async () => {
|
495
|
-
const response = await handler({
|
496
|
-
prefix: '/orpc',
|
497
|
-
request: new Request('http://localhost/orpc/ping', {
|
498
|
-
method: 'POST',
|
499
|
-
headers: {
|
500
|
-
Accept: 'invalid',
|
501
|
-
},
|
502
|
-
}),
|
503
|
-
})
|
504
|
-
|
505
|
-
expect(response.headers.get('Content-Type')).toEqual('application/json')
|
506
|
-
expect(await response.json()).toEqual({
|
507
|
-
code: 'NOT_ACCEPTABLE',
|
508
|
-
message: 'Unsupported content-type: invalid',
|
509
|
-
status: 406,
|
510
|
-
})
|
511
|
-
})
|
512
|
-
})
|
513
|
-
|
514
|
-
describe('dynamic params', () => {
|
515
|
-
const router = os.router({
|
516
|
-
deep: os
|
517
|
-
.route({
|
518
|
-
method: 'POST',
|
519
|
-
path: '/{id}/{id2}',
|
520
|
-
})
|
521
|
-
.input(
|
522
|
-
z.object({
|
523
|
-
id: z.number(),
|
524
|
-
id2: z.string(),
|
525
|
-
file: oz.file(),
|
526
|
-
}),
|
527
|
-
)
|
528
|
-
.func(input => input),
|
529
|
-
|
530
|
-
find: os
|
531
|
-
.route({
|
532
|
-
method: 'GET',
|
533
|
-
path: '/{id}',
|
534
|
-
})
|
535
|
-
.input(
|
536
|
-
z.object({
|
537
|
-
id: z.number(),
|
538
|
-
}),
|
539
|
-
)
|
540
|
-
.func(input => input),
|
541
|
-
})
|
542
|
-
|
543
|
-
const handlers = [
|
544
|
-
createFetchHandler({
|
545
|
-
router,
|
546
|
-
}),
|
547
|
-
createFetchHandler({
|
548
|
-
router,
|
549
|
-
serverless: true,
|
550
|
-
}),
|
551
|
-
]
|
552
|
-
|
553
|
-
it.each(handlers)('should handle dynamic params', async (handler) => {
|
554
|
-
const response = await handler({
|
555
|
-
request: new Request('http://localhost/123'),
|
556
|
-
})
|
557
|
-
|
558
|
-
expect(response.status).toEqual(200)
|
559
|
-
expect(response.headers.get('Content-Type')).toEqual('application/json')
|
560
|
-
expect(await response.json()).toEqual({ id: 123 })
|
561
|
-
})
|
562
|
-
|
563
|
-
it.each(handlers)('should handle deep dynamic params', async (handler) => {
|
564
|
-
const form = new FormData()
|
565
|
-
form.append('file', new Blob(['hello']), 'hello.txt')
|
566
|
-
|
567
|
-
const response = await handler({
|
568
|
-
request: new Request('http://localhost/123/dfdsfds', {
|
569
|
-
method: 'POST',
|
570
|
-
body: form,
|
571
|
-
}),
|
572
|
-
})
|
573
|
-
|
574
|
-
expect(response.status).toEqual(200)
|
575
|
-
const rForm = await response.formData()
|
576
|
-
expect(rForm.get('id')).toEqual('123')
|
577
|
-
expect(rForm.get('id2')).toEqual('dfdsfds')
|
578
|
-
})
|
579
|
-
})
|
580
|
-
|
581
|
-
describe('can control method on POST request', () => {
|
582
|
-
const router = os.router({
|
583
|
-
update: os
|
584
|
-
.route({
|
585
|
-
method: 'PUT',
|
586
|
-
path: '/{id}',
|
587
|
-
})
|
588
|
-
.input(
|
589
|
-
z.object({
|
590
|
-
id: z.number(),
|
591
|
-
file: oz.file(),
|
592
|
-
}),
|
593
|
-
)
|
594
|
-
.func(input => input),
|
595
|
-
})
|
596
|
-
|
597
|
-
const handlers = [
|
598
|
-
createFetchHandler({
|
599
|
-
router,
|
600
|
-
}),
|
601
|
-
createFetchHandler({
|
602
|
-
router,
|
603
|
-
serverless: true,
|
604
|
-
}),
|
605
|
-
]
|
606
|
-
|
607
|
-
it.each(handlers)('work', async (handler) => {
|
608
|
-
const form = new FormData()
|
609
|
-
form.set('file', new File(['hello'], 'hello.txt'))
|
610
|
-
|
611
|
-
const response = await handler({
|
612
|
-
request: new Request('http://localhost/123', {
|
613
|
-
method: 'POST',
|
614
|
-
body: form,
|
615
|
-
}),
|
616
|
-
})
|
617
|
-
|
618
|
-
expect(response.status).toEqual(404)
|
619
|
-
|
620
|
-
const response2 = await handler({
|
621
|
-
request: new Request('http://localhost/123?method=PUT', {
|
622
|
-
method: 'POST',
|
623
|
-
body: form,
|
624
|
-
}),
|
625
|
-
})
|
626
|
-
|
627
|
-
expect(response2.status).toEqual(200)
|
628
|
-
})
|
629
|
-
})
|