Skip to content

Commit

Permalink
feat: useMethod/isMethod/assertMethod
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Nov 24, 2021
1 parent 56d5bd5 commit c45278d
Show file tree
Hide file tree
Showing 6 changed files with 1,468 additions and 1,543 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ Instead of adding helpers to `req` and `res`, h3 exposes them as composable util
- `sendError(res, error, debug?)`
- `defineHandle(handle)`
- `defineMiddleware(middlware)`
- `useMethod(req, default?)`
- `isMethod(req, expected, allowHead?)`
- `assertMethod(req, expected, allowHead?)`

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

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"destr": "latest",
"eslint": "latest",
"express": "latest",
"get-port": "latest",
"get-port": "^5.0.0",
"jest": "latest",
"jiti": "latest",
"listhen": "latest",
Expand Down
2 changes: 1 addition & 1 deletion src/handle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function callHandle (handle: Middleware, req: IncomingMessage, res: Serve
res.once('error', next)
}
} catch (err) {
next(err)
next(err as Error)
}
})
}
Expand Down
35 changes: 35 additions & 0 deletions src/utils/request.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,41 @@
import type { IncomingMessage } from 'http'
import { getQuery } from 'ufo'
import { createError } from '../error'

export function useQuery (req: IncomingMessage) {
return getQuery(req.url || '')
}

// https://www.rfc-editor.org/rfc/rfc7231#section-4.1
export type HTTPMethod = 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'CONNECT' | 'OPTIONS' | 'TRACE'

export function useMethod (req: IncomingMessage, defaultMethod: HTTPMethod = 'GET'): HTTPMethod {
return (req.method || defaultMethod).toUpperCase() as HTTPMethod
}

export function isMethod (req: IncomingMessage, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean) {
const method = useMethod(req)

if (allowHead && method === 'HEAD') {
return true
}

if (typeof expected === 'string') {
if (method === expected) {
return true
}
} else if (expected.includes(method)) {
return true
}

return false
}

export function assertMethod (req: IncomingMessage, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean) {
if (!isMethod(req, expected, allowHead)) {
throw createError({
statusCode: 405,
statusMessage: 'HTTP method is not allowed.'
})
}
}
19 changes: 18 additions & 1 deletion test/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import supertest, { SuperTest, Test } from 'supertest'
import { createApp, App, sendRedirect, useBase, useQuery } from '../src'
import { createApp, App, sendRedirect, useBase, useQuery, useMethod, assertMethod } from '../src'

describe('', () => {
let app: App
Expand Down Expand Up @@ -51,4 +51,21 @@ describe('', () => {
expect(result.text).toBe('200')
})
})

describe('useMethod', () => {
it('can get method', async () => {
app.use('/', req => useMethod(req))
expect((await request.get('/api')).text).toBe('GET')
expect((await request.post('/api')).text).toBe('POST')
})
})

describe('assertMethod', () => {
it('only allow head and post', async () => {
app.use('/post', (req) => { assertMethod(req, 'POST', true); return 'ok' })
expect((await request.get('/post')).status).toBe(405)
expect((await request.post('/post')).status).toBe(200)
expect((await request.head('/post')).status).toBe(200)
})
})
})

0 comments on commit c45278d

Please sign in to comment.