Skip to content

Commit c45278d

Browse files
committed
feat: useMethod/isMethod/assertMethod
1 parent 56d5bd5 commit c45278d

File tree

6 files changed

+1468
-1543
lines changed

6 files changed

+1468
-1543
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ Instead of adding helpers to `req` and `res`, h3 exposes them as composable util
100100
- `sendError(res, error, debug?)`
101101
- `defineHandle(handle)`
102102
- `defineMiddleware(middlware)`
103+
- `useMethod(req, default?)`
104+
- `isMethod(req, expected, allowHead?)`
105+
- `assertMethod(req, expected, allowHead?)`
103106

104107
👉 You can learn more about usage in [JSDocs Documentation](https://www.jsdocs.io/package/h3#package-functions).
105108

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"destr": "latest",
4040
"eslint": "latest",
4141
"express": "latest",
42-
"get-port": "latest",
42+
"get-port": "^5.0.0",
4343
"jest": "latest",
4444
"jiti": "latest",
4545
"listhen": "latest",

src/handle.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export function callHandle (handle: Middleware, req: IncomingMessage, res: Serve
2727
res.once('error', next)
2828
}
2929
} catch (err) {
30-
next(err)
30+
next(err as Error)
3131
}
3232
})
3333
}

src/utils/request.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,41 @@
11
import type { IncomingMessage } from 'http'
22
import { getQuery } from 'ufo'
3+
import { createError } from '../error'
34

45
export function useQuery (req: IncomingMessage) {
56
return getQuery(req.url || '')
67
}
8+
9+
// https://www.rfc-editor.org/rfc/rfc7231#section-4.1
10+
export type HTTPMethod = 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'CONNECT' | 'OPTIONS' | 'TRACE'
11+
12+
export function useMethod (req: IncomingMessage, defaultMethod: HTTPMethod = 'GET'): HTTPMethod {
13+
return (req.method || defaultMethod).toUpperCase() as HTTPMethod
14+
}
15+
16+
export function isMethod (req: IncomingMessage, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean) {
17+
const method = useMethod(req)
18+
19+
if (allowHead && method === 'HEAD') {
20+
return true
21+
}
22+
23+
if (typeof expected === 'string') {
24+
if (method === expected) {
25+
return true
26+
}
27+
} else if (expected.includes(method)) {
28+
return true
29+
}
30+
31+
return false
32+
}
33+
34+
export function assertMethod (req: IncomingMessage, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean) {
35+
if (!isMethod(req, expected, allowHead)) {
36+
throw createError({
37+
statusCode: 405,
38+
statusMessage: 'HTTP method is not allowed.'
39+
})
40+
}
41+
}

test/utils.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import supertest, { SuperTest, Test } from 'supertest'
2-
import { createApp, App, sendRedirect, useBase, useQuery } from '../src'
2+
import { createApp, App, sendRedirect, useBase, useQuery, useMethod, assertMethod } from '../src'
33

44
describe('', () => {
55
let app: App
@@ -51,4 +51,21 @@ describe('', () => {
5151
expect(result.text).toBe('200')
5252
})
5353
})
54+
55+
describe('useMethod', () => {
56+
it('can get method', async () => {
57+
app.use('/', req => useMethod(req))
58+
expect((await request.get('/api')).text).toBe('GET')
59+
expect((await request.post('/api')).text).toBe('POST')
60+
})
61+
})
62+
63+
describe('assertMethod', () => {
64+
it('only allow head and post', async () => {
65+
app.use('/post', (req) => { assertMethod(req, 'POST', true); return 'ok' })
66+
expect((await request.get('/post')).status).toBe(405)
67+
expect((await request.post('/post')).status).toBe(200)
68+
expect((await request.head('/post')).status).toBe(200)
69+
})
70+
})
5471
})

0 commit comments

Comments
 (0)