galbe 0.1.6 → 0.1.8
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/.github/workflows/deploy_website.yml +1 -1
- package/README.md +3 -1
- package/bin/cli.ts +11 -9
- package/bun.lockb +0 -0
- package/docs/getting-started.md +221 -3
- package/docs/handler.md +1 -0
- package/docs/hooks.md +88 -0
- package/docs/plugins.md +1 -0
- package/docs/router.md +1 -0
- package/docs/routes.md +124 -0
- package/docs/schemas.md +240 -0
- package/package.json +1 -2
- package/src/index.ts +122 -219
- package/src/parser.ts +98 -100
- package/src/routes.ts +3 -1
- package/src/schema.ts +378 -0
- package/src/server.ts +6 -2
- package/src/types.ts +128 -147
- package/src/validator.ts +33 -35
- package/test/parser.test.ts +67 -67
- package/test/requests.test.ts +64 -118
- package/test/resources/test.route.comment.ts +3 -3
- package/test/responses.test.ts +3 -3
- package/test/routeFiles.test.ts +13 -0
- package/test/test.utils.ts +14 -12
- package/docs/Getting Started/basic.md +0 -1
- package/docs/Guides/routes.md +0 -1
package/test/parser.test.ts
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
handleUrlFormStream,
|
|
10
10
|
isAsyncIterator
|
|
11
11
|
} from './test.utils'
|
|
12
|
-
import { Galbe, T } from '../src'
|
|
12
|
+
import { Galbe, $T } from '../src'
|
|
13
13
|
|
|
14
14
|
const port = 7357
|
|
15
15
|
|
|
@@ -21,14 +21,14 @@ describe('parser', () => {
|
|
|
21
21
|
'/headers/schema',
|
|
22
22
|
{
|
|
23
23
|
headers: {
|
|
24
|
-
string: T.
|
|
25
|
-
zero: T.
|
|
26
|
-
number: T.
|
|
27
|
-
'neg-number': T.
|
|
28
|
-
float: T.
|
|
29
|
-
integer: T.
|
|
30
|
-
'boolean-true': T.
|
|
31
|
-
'boolean-false': T.
|
|
24
|
+
string: $T.string(),
|
|
25
|
+
zero: $T.number(),
|
|
26
|
+
number: $T.number(),
|
|
27
|
+
'neg-number': $T.number(),
|
|
28
|
+
float: $T.number(),
|
|
29
|
+
integer: $T.integer(),
|
|
30
|
+
'boolean-true': $T.boolean(),
|
|
31
|
+
'boolean-false': $T.boolean()
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
34
|
ctx => {
|
|
@@ -40,10 +40,10 @@ describe('parser', () => {
|
|
|
40
40
|
'/params/schema/:p1/:p2/:p3/:p4',
|
|
41
41
|
{
|
|
42
42
|
params: {
|
|
43
|
-
p1: T.
|
|
44
|
-
p2: T.
|
|
45
|
-
p3: T.
|
|
46
|
-
p4: T.
|
|
43
|
+
p1: $T.string(),
|
|
44
|
+
p2: $T.number(),
|
|
45
|
+
p3: $T.integer(),
|
|
46
|
+
p4: $T.boolean()
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
49
|
ctx => {
|
|
@@ -55,11 +55,11 @@ describe('parser', () => {
|
|
|
55
55
|
'/query/params/schema',
|
|
56
56
|
{
|
|
57
57
|
query: {
|
|
58
|
-
p1: T.
|
|
59
|
-
p2: T.
|
|
60
|
-
p3: T.
|
|
61
|
-
p4: T.
|
|
62
|
-
p5: T.
|
|
58
|
+
p1: $T.string(),
|
|
59
|
+
p2: $T.number(),
|
|
60
|
+
p3: $T.boolean(),
|
|
61
|
+
p4: $T.union([$T.number(), $T.boolean()]),
|
|
62
|
+
p5: $T.optional($T.string())
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
65
|
ctx => {
|
|
@@ -70,11 +70,10 @@ describe('parser', () => {
|
|
|
70
70
|
'/query/params/schema/constraints',
|
|
71
71
|
{
|
|
72
72
|
query: {
|
|
73
|
-
default: T.
|
|
74
|
-
int: T.
|
|
75
|
-
num: T.
|
|
76
|
-
str: T.
|
|
77
|
-
array: T.Optional(T.Array(T.Integer(), { minItems: 3, maxItems: 5, uniqueItems: true }))
|
|
73
|
+
default: $T.optional($T.string({ default: 'DEFAULT_VALUE' })),
|
|
74
|
+
int: $T.integer({ exclusiveMin: 10, max: 42 }),
|
|
75
|
+
num: $T.number({ min: 10, exclusiveMax: 42 }),
|
|
76
|
+
str: $T.string({ minLength: 4, maxLength: 8, pattern: /^a.*z/ })
|
|
78
77
|
}
|
|
79
78
|
},
|
|
80
79
|
ctx => {
|
|
@@ -82,16 +81,16 @@ describe('parser', () => {
|
|
|
82
81
|
}
|
|
83
82
|
)
|
|
84
83
|
|
|
85
|
-
galbe.post('/obj/schema/base', { body: T.
|
|
84
|
+
galbe.post('/obj/schema/base', { body: $T.object(schema_object) }, handleBody)
|
|
86
85
|
|
|
87
86
|
galbe.post(
|
|
88
87
|
'/form/schema/base',
|
|
89
88
|
{
|
|
90
|
-
body: T.
|
|
89
|
+
body: $T.urlForm({
|
|
91
90
|
...schema_objectBase,
|
|
92
|
-
union: T.
|
|
93
|
-
literal: T.
|
|
94
|
-
array: T.
|
|
91
|
+
union: $T.optional($T.union([$T.number(), $T.boolean()])),
|
|
92
|
+
literal: $T.optional($T.literal('x')),
|
|
93
|
+
array: $T.array()
|
|
95
94
|
})
|
|
96
95
|
},
|
|
97
96
|
handleBody
|
|
@@ -99,13 +98,13 @@ describe('parser', () => {
|
|
|
99
98
|
galbe.post(
|
|
100
99
|
'/form/stream/schema/base',
|
|
101
100
|
{
|
|
102
|
-
body: T.
|
|
103
|
-
T.
|
|
101
|
+
body: $T.stream(
|
|
102
|
+
$T.urlForm({
|
|
104
103
|
...schema_objectBase,
|
|
105
|
-
union: T.
|
|
106
|
-
literal: T.
|
|
107
|
-
array: T.
|
|
108
|
-
numArray: T.
|
|
104
|
+
union: $T.optional($T.union([$T.number(), $T.boolean()])),
|
|
105
|
+
literal: $T.optional($T.literal('x')),
|
|
106
|
+
array: $T.array($T.any()),
|
|
107
|
+
numArray: $T.optional($T.array($T.number()))
|
|
109
108
|
})
|
|
110
109
|
)
|
|
111
110
|
},
|
|
@@ -114,11 +113,11 @@ describe('parser', () => {
|
|
|
114
113
|
galbe.post(
|
|
115
114
|
'/mp/schema/base',
|
|
116
115
|
{
|
|
117
|
-
body: T.
|
|
116
|
+
body: $T.multipartForm({
|
|
118
117
|
...schema_objectBase,
|
|
119
|
-
union: T.
|
|
120
|
-
literal: T.
|
|
121
|
-
array: T.
|
|
118
|
+
union: $T.optional($T.union([$T.number(), $T.boolean()])),
|
|
119
|
+
literal: $T.optional($T.literal('x')),
|
|
120
|
+
array: $T.array($T.any())
|
|
122
121
|
})
|
|
123
122
|
},
|
|
124
123
|
handleBody
|
|
@@ -126,12 +125,12 @@ describe('parser', () => {
|
|
|
126
125
|
galbe.post(
|
|
127
126
|
'/mp/stream/schema/base',
|
|
128
127
|
{
|
|
129
|
-
body: T.
|
|
130
|
-
T.
|
|
128
|
+
body: $T.stream(
|
|
129
|
+
$T.multipartForm({
|
|
131
130
|
...schema_objectBase,
|
|
132
|
-
union: T.
|
|
133
|
-
literal: T.
|
|
134
|
-
array: T.
|
|
131
|
+
union: $T.optional($T.union([$T.number(), $T.boolean()])),
|
|
132
|
+
literal: $T.optional($T.literal('x')),
|
|
133
|
+
array: $T.array($T.any())
|
|
135
134
|
})
|
|
136
135
|
)
|
|
137
136
|
},
|
|
@@ -139,28 +138,29 @@ describe('parser', () => {
|
|
|
139
138
|
)
|
|
140
139
|
|
|
141
140
|
let schema_jsonFile = {
|
|
142
|
-
string: T.
|
|
143
|
-
number: T.
|
|
144
|
-
bool: T.
|
|
145
|
-
arrayStr: T.
|
|
146
|
-
arrayNumber: T.
|
|
147
|
-
arrayBool: T.
|
|
141
|
+
string: $T.string(),
|
|
142
|
+
number: $T.number(),
|
|
143
|
+
bool: $T.boolean(),
|
|
144
|
+
arrayStr: $T.array($T.string()),
|
|
145
|
+
arrayNumber: $T.array($T.number()),
|
|
146
|
+
arrayBool: $T.array($T.boolean())
|
|
148
147
|
}
|
|
149
148
|
|
|
150
149
|
galbe.post(
|
|
151
150
|
'/mp/file',
|
|
152
|
-
{ body: T.
|
|
151
|
+
{ body: $T.multipartForm({ imgFile: $T.byteArray(), jsonFile: $T.object(schema_jsonFile) }) },
|
|
153
152
|
handleBody
|
|
154
153
|
)
|
|
155
154
|
galbe.post(
|
|
156
155
|
'/mp/stream/file',
|
|
157
|
-
{ body: T.
|
|
156
|
+
{ body: $T.stream($T.multipartForm({ imgFile: $T.byteArray(), jsonFile: $T.object(schema_jsonFile) })) },
|
|
158
157
|
async ctx => {
|
|
159
158
|
if (isAsyncIterator(ctx.body)) {
|
|
160
159
|
const chunks: any[] = []
|
|
161
160
|
for await (const chunk of ctx.body) {
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
const c = { ...chunk } as any
|
|
162
|
+
if (chunk.content instanceof Uint8Array) c.content = await fileHash(chunk.content)
|
|
163
|
+
chunks.push(c)
|
|
164
164
|
}
|
|
165
165
|
return { type: 'AsyncIterator', content: chunks }
|
|
166
166
|
} else {
|
|
@@ -168,14 +168,14 @@ describe('parser', () => {
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
)
|
|
171
|
-
galbe.post('/ba/file', { body: T.
|
|
171
|
+
galbe.post('/ba/file', { body: $T.byteArray() }, async ctx => {
|
|
172
172
|
if (ctx?.body instanceof Uint8Array) {
|
|
173
|
-
return { type: '
|
|
173
|
+
return { type: 'byteArray', content: await fileHash(ctx.body) }
|
|
174
174
|
} else {
|
|
175
175
|
return { type: null, content: 'error' }
|
|
176
176
|
}
|
|
177
177
|
})
|
|
178
|
-
galbe.post('/ba/stream/file', { body: T.
|
|
178
|
+
galbe.post('/ba/stream/file', { body: $T.stream($T.byteArray()) }, async ctx => {
|
|
179
179
|
if (isAsyncIterator(ctx.body)) {
|
|
180
180
|
let bytes = new Uint8Array()
|
|
181
181
|
for await (const b of ctx.body) {
|
|
@@ -190,7 +190,7 @@ describe('parser', () => {
|
|
|
190
190
|
await galbe.listen(port)
|
|
191
191
|
})
|
|
192
192
|
|
|
193
|
-
test('headers', async () => {
|
|
193
|
+
test('headers, schema', async () => {
|
|
194
194
|
const cases: any = [
|
|
195
195
|
{
|
|
196
196
|
h: {
|
|
@@ -274,7 +274,7 @@ describe('parser', () => {
|
|
|
274
274
|
}
|
|
275
275
|
})
|
|
276
276
|
|
|
277
|
-
test('query params', async () => {
|
|
277
|
+
test('query params, schema', async () => {
|
|
278
278
|
const cases: any = [
|
|
279
279
|
{
|
|
280
280
|
p: { p1: 'one', p2: '3.14', p3: 'false', p4: '42' },
|
|
@@ -377,7 +377,7 @@ describe('parser', () => {
|
|
|
377
377
|
status: 400,
|
|
378
378
|
resp: {
|
|
379
379
|
body: {
|
|
380
|
-
ba: 'Not a valid
|
|
380
|
+
ba: 'Not a valid byteArray',
|
|
381
381
|
string: '42 is not a valid string',
|
|
382
382
|
number: 'a is not a valid number',
|
|
383
383
|
bool: "x is not a valid boolean. Should be 'true' or 'false'",
|
|
@@ -475,7 +475,7 @@ describe('parser', () => {
|
|
|
475
475
|
number: 'aaa is not a valid number',
|
|
476
476
|
bool: "1 is not a valid boolean. Should be 'true' or 'false'",
|
|
477
477
|
literal: 'y is not a valid value',
|
|
478
|
-
union: 'X could not be parsed to any of
|
|
478
|
+
union: 'X could not be parsed to any of number, boolean'
|
|
479
479
|
}
|
|
480
480
|
}
|
|
481
481
|
}
|
|
@@ -761,7 +761,7 @@ describe('parser', () => {
|
|
|
761
761
|
number: 'aaa is not a valid number',
|
|
762
762
|
bool: "1 is not a valid boolean. Should be 'true' or 'false'",
|
|
763
763
|
literal: 'y is not a valid value',
|
|
764
|
-
union: 'X could not be parsed to any of:
|
|
764
|
+
union: 'X could not be parsed to any of: number, boolean'
|
|
765
765
|
}
|
|
766
766
|
}
|
|
767
767
|
}
|
|
@@ -1042,7 +1042,7 @@ describe('parser', () => {
|
|
|
1042
1042
|
schema: '/ba/file',
|
|
1043
1043
|
expected: {
|
|
1044
1044
|
status: 200,
|
|
1045
|
-
type: '
|
|
1045
|
+
type: 'byteArray',
|
|
1046
1046
|
resp: await fileHash(imgFileBytes)
|
|
1047
1047
|
}
|
|
1048
1048
|
}
|
|
@@ -1162,12 +1162,12 @@ describe('parser', () => {
|
|
|
1162
1162
|
test('type constraints', async () => {
|
|
1163
1163
|
const cases: any = [
|
|
1164
1164
|
{
|
|
1165
|
-
p: { int: '11', num: '10', str: 'aaaz'
|
|
1166
|
-
expected: { body: { default: 'DEFAULT_VALUE', int: 11, num: 10, str: 'aaaz'
|
|
1165
|
+
p: { int: '11', num: '10', str: 'aaaz' },
|
|
1166
|
+
expected: { body: { default: 'DEFAULT_VALUE', int: 11, num: 10, str: 'aaaz' } }
|
|
1167
1167
|
},
|
|
1168
1168
|
{
|
|
1169
|
-
p: { default: '', int: '42', num: '41.5', str: 'a______z'
|
|
1170
|
-
expected: { body: { default: '', int: 42, num: 41.5, str: 'a______z'
|
|
1169
|
+
p: { default: '', int: '42', num: '41.5', str: 'a______z' },
|
|
1170
|
+
expected: { body: { default: '', int: 42, num: 41.5, str: 'a______z' } }
|
|
1171
1171
|
},
|
|
1172
1172
|
{
|
|
1173
1173
|
p: { int: '10', num: '42.01', str: 'xxxxxxxxxx' },
|
|
@@ -1177,7 +1177,7 @@ describe('parser', () => {
|
|
|
1177
1177
|
query: {
|
|
1178
1178
|
int: '10 is less or equal to 10',
|
|
1179
1179
|
num: '42.01 is greater or equal to 42',
|
|
1180
|
-
str: ['xxxxxxxxxx length is too large (8 char max)', 'xxxxxxxxxx does not match pattern
|
|
1180
|
+
str: ['xxxxxxxxxx length is too large (8 char max)', 'xxxxxxxxxx does not match pattern /^a.*z/']
|
|
1181
1181
|
}
|
|
1182
1182
|
}
|
|
1183
1183
|
}
|
package/test/requests.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { expect, test, describe, beforeAll } from 'bun:test'
|
|
2
|
-
import { Galbe, T } from '../src'
|
|
2
|
+
import { Galbe, $T } from '../src'
|
|
3
3
|
import {
|
|
4
4
|
formdata,
|
|
5
5
|
type Case,
|
|
@@ -32,14 +32,14 @@ describe('requests', () => {
|
|
|
32
32
|
'/headers/schema',
|
|
33
33
|
{
|
|
34
34
|
headers: {
|
|
35
|
-
string: T.
|
|
36
|
-
zero: T.
|
|
37
|
-
number: T.
|
|
38
|
-
'neg-number': T.
|
|
39
|
-
float: T.
|
|
40
|
-
integer: T.
|
|
41
|
-
'boolean-true': T.
|
|
42
|
-
'boolean-false': T.
|
|
35
|
+
string: $T.string(),
|
|
36
|
+
zero: $T.number(),
|
|
37
|
+
number: $T.number(),
|
|
38
|
+
'neg-number': $T.number(),
|
|
39
|
+
float: $T.number(),
|
|
40
|
+
integer: $T.integer(),
|
|
41
|
+
'boolean-true': $T.boolean(),
|
|
42
|
+
'boolean-false': $T.boolean()
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
45
|
ctx => {
|
|
@@ -54,10 +54,10 @@ describe('requests', () => {
|
|
|
54
54
|
'/params/schema/:p1/:p2/:p3/:p4',
|
|
55
55
|
{
|
|
56
56
|
params: {
|
|
57
|
-
p1: T.
|
|
58
|
-
p2: T.
|
|
59
|
-
p3: T.
|
|
60
|
-
p4: T.
|
|
57
|
+
p1: $T.string(),
|
|
58
|
+
p2: $T.number(),
|
|
59
|
+
p3: $T.integer(),
|
|
60
|
+
p4: $T.boolean()
|
|
61
61
|
}
|
|
62
62
|
},
|
|
63
63
|
ctx => {
|
|
@@ -72,11 +72,11 @@ describe('requests', () => {
|
|
|
72
72
|
'/query/params/schema',
|
|
73
73
|
{
|
|
74
74
|
query: {
|
|
75
|
-
p1: T.
|
|
76
|
-
p2: T.
|
|
77
|
-
p3: T.
|
|
78
|
-
p4: T.
|
|
79
|
-
p5: T.
|
|
75
|
+
p1: $T.string(),
|
|
76
|
+
p2: $T.number(),
|
|
77
|
+
p3: $T.boolean(),
|
|
78
|
+
p4: $T.union([$T.number(), $T.boolean()]),
|
|
79
|
+
p5: $T.optional($T.string())
|
|
80
80
|
}
|
|
81
81
|
},
|
|
82
82
|
ctx => {
|
|
@@ -85,19 +85,19 @@ describe('requests', () => {
|
|
|
85
85
|
)
|
|
86
86
|
|
|
87
87
|
galbe.post('/none', handleBody)
|
|
88
|
-
galbe.post('/ba', { body: T.
|
|
89
|
-
galbe.post('/bool', { body: T.
|
|
90
|
-
galbe.post('/num', { body: T.
|
|
91
|
-
galbe.post('/str', { body: T.
|
|
92
|
-
galbe.post('/arr', { body: T.
|
|
93
|
-
galbe.post('/obj', { body: T.
|
|
94
|
-
|
|
95
|
-
galbe.post('/form', { body: T.
|
|
96
|
-
galbe.post('/mp', { body: T.
|
|
97
|
-
|
|
98
|
-
galbe.post('/stream/ba', { body: T.
|
|
99
|
-
galbe.post('/stream/str', { body: T.
|
|
100
|
-
galbe.post('/stream/form', { body: T.
|
|
88
|
+
galbe.post('/ba', { body: $T.byteArray() }, handleBody)
|
|
89
|
+
galbe.post('/bool', { body: $T.boolean() }, handleBody)
|
|
90
|
+
galbe.post('/num', { body: $T.number() }, handleBody)
|
|
91
|
+
galbe.post('/str', { body: $T.string() }, handleBody)
|
|
92
|
+
galbe.post('/arr', { body: $T.array() }, handleBody)
|
|
93
|
+
galbe.post('/obj', { body: $T.object($T.any()) }, handleBody)
|
|
94
|
+
|
|
95
|
+
galbe.post('/form', { body: $T.urlForm() }, handleBody)
|
|
96
|
+
galbe.post('/mp', { body: $T.multipartForm() }, handleBody)
|
|
97
|
+
|
|
98
|
+
galbe.post('/stream/ba', { body: $T.stream($T.byteArray()) }, handleBody)
|
|
99
|
+
galbe.post('/stream/str', { body: $T.stream($T.string()) }, handleBody)
|
|
100
|
+
galbe.post('/stream/form', { body: $T.stream($T.urlForm()) }, async ctx => {
|
|
101
101
|
let resp: Record<string, any> = {}
|
|
102
102
|
for await (const [k, v] of ctx.body) {
|
|
103
103
|
if (k in resp) {
|
|
@@ -106,97 +106,43 @@ describe('requests', () => {
|
|
|
106
106
|
}
|
|
107
107
|
return { type: 'object', content: resp }
|
|
108
108
|
})
|
|
109
|
-
galbe.post('/stream/mp', { body: T.
|
|
109
|
+
galbe.post('/stream/mp', { body: $T.stream($T.multipartForm()) }, async ctx => {
|
|
110
110
|
let resp: Record<string, any> = {}
|
|
111
111
|
for await (const field of ctx.body) {
|
|
112
|
-
let k = field
|
|
113
|
-
if (k in resp) {
|
|
112
|
+
let k = field?.headers.name
|
|
113
|
+
if (k && k in resp) {
|
|
114
114
|
resp[k].content = Array.isArray(resp[k]?.content)
|
|
115
|
-
? [...resp[k].content, field
|
|
116
|
-
: [resp[k]?.content, field
|
|
115
|
+
? [...resp[k].content, field?.content]
|
|
116
|
+
: [resp[k]?.content, field?.content]
|
|
117
117
|
} else resp[k] = field
|
|
118
118
|
}
|
|
119
119
|
return { type: 'object', content: resp }
|
|
120
120
|
})
|
|
121
121
|
|
|
122
|
-
galbe.post('/obj/schema/base', { body: T.Object(schema_object) }, handleBody)
|
|
123
|
-
galbe.post(
|
|
124
|
-
'/form/schema/base',
|
|
125
|
-
{
|
|
126
|
-
body: T.UrlForm({
|
|
127
|
-
...schema_objectBase,
|
|
128
|
-
union: T.Optional(T.Union([T.Number(), T.Boolean()])),
|
|
129
|
-
literal: T.Optional(T.Literal('x')),
|
|
130
|
-
array: T.Array(T.Any())
|
|
131
|
-
})
|
|
132
|
-
},
|
|
133
|
-
handleBody
|
|
134
|
-
)
|
|
135
|
-
galbe.post(
|
|
136
|
-
'/form/stream/schema/base',
|
|
137
|
-
{
|
|
138
|
-
body: T.Stream(
|
|
139
|
-
T.UrlForm({
|
|
140
|
-
...schema_objectBase,
|
|
141
|
-
union: T.Optional(T.Union([T.Number(), T.Boolean()])),
|
|
142
|
-
literal: T.Optional(T.Literal('x')),
|
|
143
|
-
array: T.Array(T.Any()),
|
|
144
|
-
numArray: T.Optional(T.Array(T.Number()))
|
|
145
|
-
})
|
|
146
|
-
)
|
|
147
|
-
},
|
|
148
|
-
handleUrlFormStream
|
|
149
|
-
)
|
|
150
|
-
galbe.post(
|
|
151
|
-
'/mp/schema/base',
|
|
152
|
-
{
|
|
153
|
-
body: T.MultipartForm({
|
|
154
|
-
...schema_objectBase,
|
|
155
|
-
union: T.Optional(T.Union([T.Number(), T.Boolean()])),
|
|
156
|
-
literal: T.Optional(T.Literal('x')),
|
|
157
|
-
array: T.Array(T.Any())
|
|
158
|
-
})
|
|
159
|
-
},
|
|
160
|
-
handleBody
|
|
161
|
-
)
|
|
162
|
-
galbe.post(
|
|
163
|
-
'/mp/stream/schema/base',
|
|
164
|
-
{
|
|
165
|
-
body: T.Stream(
|
|
166
|
-
T.MultipartForm({
|
|
167
|
-
...schema_objectBase,
|
|
168
|
-
union: T.Optional(T.Union([T.Number(), T.Boolean()])),
|
|
169
|
-
literal: T.Optional(T.Literal('x')),
|
|
170
|
-
array: T.Array(T.Any())
|
|
171
|
-
})
|
|
172
|
-
)
|
|
173
|
-
},
|
|
174
|
-
handleBody
|
|
175
|
-
)
|
|
176
|
-
|
|
177
122
|
let schema_jsonFile = {
|
|
178
|
-
string: T.
|
|
179
|
-
number: T.
|
|
180
|
-
bool: T.
|
|
181
|
-
arrayStr: T.
|
|
182
|
-
arrayNumber: T.
|
|
183
|
-
arrayBool: T.
|
|
123
|
+
string: $T.string(),
|
|
124
|
+
number: $T.number(),
|
|
125
|
+
bool: $T.boolean(),
|
|
126
|
+
arrayStr: $T.array($T.string()),
|
|
127
|
+
arrayNumber: $T.array($T.number()),
|
|
128
|
+
arrayBool: $T.array($T.boolean())
|
|
184
129
|
}
|
|
185
130
|
|
|
186
131
|
galbe.post(
|
|
187
132
|
'/mp/file',
|
|
188
|
-
{ body: T.
|
|
133
|
+
{ body: $T.multipartForm({ imgFile: $T.byteArray(), jsonFile: $T.object(schema_jsonFile) }) },
|
|
189
134
|
handleBody
|
|
190
135
|
)
|
|
191
136
|
galbe.post(
|
|
192
137
|
'/mp/stream/file',
|
|
193
|
-
{ body: T.
|
|
138
|
+
{ body: $T.stream($T.multipartForm({ imgFile: $T.byteArray(), jsonFile: $T.object(schema_jsonFile) })) },
|
|
194
139
|
async ctx => {
|
|
195
140
|
if (isAsyncIterator(ctx.body)) {
|
|
196
141
|
const chunks: any[] = []
|
|
197
142
|
for await (const chunk of ctx.body) {
|
|
198
|
-
|
|
199
|
-
|
|
143
|
+
const c = { ...chunk } as any
|
|
144
|
+
if (chunk.content instanceof Uint8Array) c.content = await fileHash(chunk.content)
|
|
145
|
+
chunks.push(c)
|
|
200
146
|
}
|
|
201
147
|
return { type: 'AsyncIterator', content: chunks }
|
|
202
148
|
} else {
|
|
@@ -204,14 +150,14 @@ describe('requests', () => {
|
|
|
204
150
|
}
|
|
205
151
|
}
|
|
206
152
|
)
|
|
207
|
-
galbe.post('/ba/file', { body: T.
|
|
153
|
+
galbe.post('/ba/file', { body: $T.byteArray() }, async ctx => {
|
|
208
154
|
if (ctx?.body instanceof Uint8Array) {
|
|
209
|
-
return { type: '
|
|
155
|
+
return { type: 'byteArray', content: await fileHash(ctx.body) }
|
|
210
156
|
} else {
|
|
211
157
|
return { type: null, content: 'error' }
|
|
212
158
|
}
|
|
213
159
|
})
|
|
214
|
-
galbe.post('/ba/stream/file', { body: T.
|
|
160
|
+
galbe.post('/ba/stream/file', { body: $T.stream($T.byteArray()) }, async ctx => {
|
|
215
161
|
if (isAsyncIterator(ctx.body)) {
|
|
216
162
|
let bytes = new Uint8Array()
|
|
217
163
|
for await (const b of ctx.body) {
|
|
@@ -281,7 +227,7 @@ describe('requests', () => {
|
|
|
281
227
|
test('no body, no header', async () => {
|
|
282
228
|
const cases: Case[] = [
|
|
283
229
|
{ body: null, type: undefined, schema: 'none', expected: { status: 200, resp: null } },
|
|
284
|
-
{ body: null, type: undefined, schema: 'ba', expected: { status: 200, type: '
|
|
230
|
+
{ body: null, type: undefined, schema: 'ba', expected: { status: 200, type: 'byteArray', resp: '' } },
|
|
285
231
|
{ body: null, type: undefined, schema: 'bool', expected: { status: 400 } },
|
|
286
232
|
{ body: null, type: undefined, schema: 'num', expected: { status: 400 } },
|
|
287
233
|
{ body: null, type: undefined, schema: 'str', expected: { status: 400 } },
|
|
@@ -316,7 +262,7 @@ describe('requests', () => {
|
|
|
316
262
|
const contentType = 'application/octet-stream'
|
|
317
263
|
const cases: Case[] = [
|
|
318
264
|
{ body: null, type: contentType, schema: 'none', expected: { status: 200, resp: '' } },
|
|
319
|
-
{ body: null, type: contentType, schema: 'ba', expected: { status: 200, type: '
|
|
265
|
+
{ body: null, type: contentType, schema: 'ba', expected: { status: 200, type: 'byteArray', resp: '' } },
|
|
320
266
|
{ body: null, type: contentType, schema: 'bool', expected: { status: 400 } },
|
|
321
267
|
{ body: null, type: contentType, schema: 'num', expected: { status: 400 } },
|
|
322
268
|
{ body: null, type: contentType, schema: 'str', expected: { status: 400 } },
|
|
@@ -357,7 +303,7 @@ describe('requests', () => {
|
|
|
357
303
|
const contentType = 'application/json'
|
|
358
304
|
const cases: Case[] = [
|
|
359
305
|
{ body: null, type: contentType, schema: 'none', expected: { status: 400 } },
|
|
360
|
-
{ body: null, type: contentType, schema: 'ba', expected: { status: 200, type: '
|
|
306
|
+
{ body: null, type: contentType, schema: 'ba', expected: { status: 200, type: 'byteArray', resp: '' } },
|
|
361
307
|
{ body: null, type: contentType, schema: 'bool', expected: { status: 400 } },
|
|
362
308
|
{ body: null, type: contentType, schema: 'num', expected: { status: 400 } },
|
|
363
309
|
{ body: null, type: contentType, schema: 'str', expected: { status: 400 } },
|
|
@@ -398,7 +344,7 @@ describe('requests', () => {
|
|
|
398
344
|
const contentType = 'text/plain'
|
|
399
345
|
const cases: Case[] = [
|
|
400
346
|
{ body: null, type: contentType, schema: 'none', expected: { status: 400 } },
|
|
401
|
-
{ body: null, type: contentType, schema: 'ba', expected: { status: 200, type: '
|
|
347
|
+
{ body: null, type: contentType, schema: 'ba', expected: { status: 200, type: 'byteArray', resp: '' } },
|
|
402
348
|
{ body: null, type: contentType, schema: 'bool', expected: { status: 400 } },
|
|
403
349
|
{ body: null, type: contentType, schema: 'num', expected: { status: 400 } },
|
|
404
350
|
{ body: null, type: contentType, schema: 'str', expected: { status: 400 } },
|
|
@@ -439,7 +385,7 @@ describe('requests', () => {
|
|
|
439
385
|
const contentType = 'application/x-www-form-urlencoded'
|
|
440
386
|
const cases: Case[] = [
|
|
441
387
|
{ body: null, type: contentType, schema: 'none', expected: { status: 400 } },
|
|
442
|
-
{ body: null, type: contentType, schema: 'ba', expected: { status: 200, type: '
|
|
388
|
+
{ body: null, type: contentType, schema: 'ba', expected: { status: 200, type: 'byteArray', resp: '' } },
|
|
443
389
|
{ body: null, type: contentType, schema: 'bool', expected: { status: 400 } },
|
|
444
390
|
{ body: null, type: contentType, schema: 'num', expected: { status: 400 } },
|
|
445
391
|
{ body: null, type: contentType, schema: 'str', expected: { status: 400 } },
|
|
@@ -480,7 +426,7 @@ describe('requests', () => {
|
|
|
480
426
|
const contentType = 'multipart/form-data'
|
|
481
427
|
const cases: Case[] = [
|
|
482
428
|
{ body: null, type: contentType, schema: 'none', expected: { status: 400 } },
|
|
483
|
-
{ body: null, type: contentType, schema: 'ba', expected: { status: 200, type: '
|
|
429
|
+
{ body: null, type: contentType, schema: 'ba', expected: { status: 200, type: 'byteArray', resp: '' } },
|
|
484
430
|
{ body: null, type: contentType, schema: 'bool', expected: { status: 400 } },
|
|
485
431
|
{ body: null, type: contentType, schema: 'num', expected: { status: 400 } },
|
|
486
432
|
{ body: null, type: contentType, schema: 'str', expected: { status: 400 } },
|
|
@@ -519,8 +465,8 @@ describe('requests', () => {
|
|
|
519
465
|
|
|
520
466
|
test('body, no header', async () => {
|
|
521
467
|
const cases: Case[] = [
|
|
522
|
-
{ body: 'test', schema: 'none', expected: { status: 200, type: '
|
|
523
|
-
{ body: 'test', schema: 'ba', expected: { status: 200, type: '
|
|
468
|
+
{ body: 'test', schema: 'none', expected: { status: 200, type: 'byteArray', resp: 'test' } },
|
|
469
|
+
{ body: 'test', schema: 'ba', expected: { status: 200, type: 'byteArray', resp: 'test' } },
|
|
524
470
|
{ body: 'true', schema: 'bool', expected: { status: 200, type: 'boolean', resp: true } },
|
|
525
471
|
{ body: 'false', schema: 'bool', expected: { status: 200, type: 'boolean', resp: false } },
|
|
526
472
|
{ body: 'test', schema: 'bool', expected: { status: 400 } },
|
|
@@ -575,8 +521,8 @@ describe('requests', () => {
|
|
|
575
521
|
test('body, application/octet-stream', async () => {
|
|
576
522
|
const contentType = 'application/octet-stream'
|
|
577
523
|
const cases: Case[] = [
|
|
578
|
-
{ body: 'test', type: contentType, schema: 'none', expected: { status: 200, type: '
|
|
579
|
-
{ body: 'test', type: contentType, schema: 'ba', expected: { status: 200, type: '
|
|
524
|
+
{ body: 'test', type: contentType, schema: 'none', expected: { status: 200, type: 'byteArray', resp: 'test' } },
|
|
525
|
+
{ body: 'test', type: contentType, schema: 'ba', expected: { status: 200, type: 'byteArray', resp: 'test' } },
|
|
580
526
|
{ body: 'true', type: contentType, schema: 'bool', expected: { status: 200, type: 'boolean', resp: true } },
|
|
581
527
|
{ body: 'false', type: contentType, schema: 'bool', expected: { status: 200, type: 'boolean', resp: false } },
|
|
582
528
|
{ body: 'test', type: contentType, schema: 'bool', expected: { status: 400 } },
|
|
@@ -650,7 +596,7 @@ describe('requests', () => {
|
|
|
650
596
|
expected: { status: 200, type: 'object', resp: { foo: 'bar' } }
|
|
651
597
|
},
|
|
652
598
|
{ body: 'test', type: contentType, schema: 'none', expected: { status: 400 } },
|
|
653
|
-
{ body: 'test', type: contentType, schema: 'ba', expected: { status: 200, type: '
|
|
599
|
+
{ body: 'test', type: contentType, schema: 'ba', expected: { status: 200, type: 'byteArray', resp: 'test' } },
|
|
654
600
|
{ body: 'true', type: contentType, schema: 'bool', expected: { status: 200, type: 'boolean', resp: true } },
|
|
655
601
|
{ body: 'false', type: contentType, schema: 'bool', expected: { status: 200, type: 'boolean', resp: false } },
|
|
656
602
|
{ body: 'test', type: contentType, schema: 'bool', expected: { status: 400 } },
|
|
@@ -720,7 +666,7 @@ describe('requests', () => {
|
|
|
720
666
|
const contentType = 'text/plain'
|
|
721
667
|
const cases: Case[] = [
|
|
722
668
|
{ body: 'test', type: contentType, schema: 'none', expected: { status: 200, type: 'string', resp: 'test' } },
|
|
723
|
-
{ body: 'test', type: contentType, schema: 'ba', expected: { status: 200, type: '
|
|
669
|
+
{ body: 'test', type: contentType, schema: 'ba', expected: { status: 200, type: 'byteArray', resp: 'test' } },
|
|
724
670
|
{ body: 'true', type: contentType, schema: 'bool', expected: { status: 200, type: 'boolean', resp: true } },
|
|
725
671
|
{ body: 'false', type: contentType, schema: 'bool', expected: { status: 200, type: 'boolean', resp: false } },
|
|
726
672
|
{ body: 'test', type: contentType, schema: 'bool', expected: { status: 400 } },
|
|
@@ -792,7 +738,7 @@ describe('requests', () => {
|
|
|
792
738
|
const objBody = { string: 'text', number: '42', boolean: 'true', 'encoded=': '=' }
|
|
793
739
|
const cases: Case[] = [
|
|
794
740
|
{ body: strBody, type: contentType, schema: 'none', expected: { status: 200, type: 'object', resp: objBody } },
|
|
795
|
-
{ body: strBody, type: contentType, schema: 'ba', expected: { status: 200, type: '
|
|
741
|
+
{ body: strBody, type: contentType, schema: 'ba', expected: { status: 200, type: 'byteArray', resp: strBody } },
|
|
796
742
|
{ body: strBody, type: contentType, schema: 'bool', expected: { status: 400 } },
|
|
797
743
|
{ body: strBody, type: contentType, schema: 'num', expected: { status: 400 } },
|
|
798
744
|
{ body: strBody, type: contentType, schema: 'str', expected: { status: 400 } },
|
|
@@ -871,7 +817,7 @@ describe('requests', () => {
|
|
|
871
817
|
|
|
872
818
|
const cases: Case[] = [
|
|
873
819
|
{ body: form, schema: 'none', expected: { status: 200, type: 'object', resp: objResp } },
|
|
874
|
-
{ body: form, schema: 'ba', expected: { status: 200, type: '
|
|
820
|
+
{ body: form, schema: 'ba', expected: { status: 200, type: 'byteArray', resp: objRespStrRgx } },
|
|
875
821
|
{ body: form, schema: 'bool', expected: { status: 400 } },
|
|
876
822
|
{ body: form, schema: 'num', expected: { status: 400 } },
|
|
877
823
|
{ body: form, schema: 'str', expected: { status: 400 } },
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Galbe } from '../../src'
|
|
2
|
-
import { T } from '../../src'
|
|
2
|
+
import { $T } from '../../src'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* description
|
|
@@ -28,11 +28,11 @@ export default (g: Galbe) => {
|
|
|
28
28
|
* @description longer description example
|
|
29
29
|
* @body body descripton
|
|
30
30
|
*/
|
|
31
|
-
g.post('/test', { body: T.
|
|
31
|
+
g.post('/test', { body: $T.object({ foo: $T.string() }) }, _ => {})
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* @tags tag1, tag2
|
|
35
35
|
* @other Hello Mom!
|
|
36
36
|
*/
|
|
37
|
-
g.put('/test', { body: T.
|
|
37
|
+
g.put('/test', { body: $T.object({ foo: $T.string() }) }, [() => {}], _ => {})
|
|
38
38
|
}
|