@@ -2,12 +2,15 @@ import { IncomingMessage } from 'http'
2
2
import { NextApiResponse , NextApiRequest } from '../lib/utils'
3
3
import { Stream } from 'stream'
4
4
import getRawBody from 'raw-body'
5
- import { URL } from 'url'
6
5
import { parse } from 'content-type'
6
+ import { Params } from './router'
7
+
8
+ export type NextApiRequestCookies = { [ key : string ] : string }
9
+ export type NextApiRequestQuery = { [ key : string ] : string | string [ ] }
7
10
8
11
/**
9
12
* Parse incoming message like `json` or `urlencoded`
10
- * @param req
13
+ * @param req request object
11
14
*/
12
15
export async function parseBody ( req : NextApiRequest , limit : string = '1mb' ) {
13
16
const contentType = parse ( req . headers [ 'content-type' ] || 'text/plain' )
@@ -55,14 +58,35 @@ function parseJson(str: string) {
55
58
* @param url of request
56
59
* @returns Object with key name of query argument and its value
57
60
*/
58
- export function parseQuery ( { url } : IncomingMessage ) {
59
- if ( url ) {
60
- // This is just for parsing search params, base it's not important
61
+ export function getQueryParser ( { url } : IncomingMessage ) {
62
+ return function parseQuery ( ) : NextApiRequestQuery {
63
+ const { URL } = require ( 'url' )
64
+ // we provide a placeholder base url because we only want searchParams
61
65
const params = new URL ( url , 'https://n' ) . searchParams
62
66
63
- return reduceParams ( params . entries ( ) )
64
- } else {
65
- return { }
67
+ const query : { [ key : string ] : string | string [ ] } = { }
68
+ for ( const [ key , value ] of params ) {
69
+ query [ key ] = value
70
+ }
71
+
72
+ return query
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Parse cookeies from `req` header
78
+ * @param req request object
79
+ */
80
+ export function getCookieParser ( req : IncomingMessage ) {
81
+ return function parseCookie ( ) : NextApiRequestCookies {
82
+ const header : undefined | string | string [ ] = req . headers . cookie
83
+
84
+ if ( ! header ) {
85
+ return { }
86
+ }
87
+
88
+ const { parse } = require ( 'cookie' )
89
+ return parse ( Array . isArray ( header ) ? header . join ( ';' ) : header )
66
90
}
67
91
}
68
92
@@ -131,14 +155,6 @@ export function sendJson(res: NextApiResponse, jsonBody: any): void {
131
155
res . send ( jsonBody )
132
156
}
133
157
134
- function reduceParams ( params : IterableIterator < [ string , string ] > ) {
135
- const obj : any = { }
136
- for ( const [ key , value ] of params ) {
137
- obj [ key ] = value
138
- }
139
- return obj
140
- }
141
-
142
158
/**
143
159
* Custom error class
144
160
*/
@@ -166,3 +182,39 @@ export function sendError(
166
182
res . statusMessage = message
167
183
res . end ( )
168
184
}
185
+
186
+ interface LazyProps {
187
+ req : NextApiRequest
188
+ params ?: Params | boolean
189
+ }
190
+
191
+ /**
192
+ * Execute getter function only if its needed
193
+ * @param LazyProps `req` and `params` for lazyProp
194
+ * @param prop name of property
195
+ * @param getter function to get data
196
+ */
197
+ export function setLazyProp < T > (
198
+ { req, params } : LazyProps ,
199
+ prop : string ,
200
+ getter : ( ) => T
201
+ ) {
202
+ const opts = { configurable : true , enumerable : true }
203
+ const optsReset = { ...opts , writable : true }
204
+
205
+ Object . defineProperty ( req , prop , {
206
+ ...opts ,
207
+ get : ( ) => {
208
+ let value = getter ( )
209
+ if ( params && typeof params !== 'boolean' ) {
210
+ value = { ...value , ...params }
211
+ }
212
+ // we set the property on the object to avoid recalculating it
213
+ Object . defineProperty ( req , prop , { ...optsReset , value } )
214
+ return value
215
+ } ,
216
+ set : value => {
217
+ Object . defineProperty ( req , prop , { ...optsReset , value } )
218
+ } ,
219
+ } )
220
+ }
0 commit comments