vort
v0.2.2
Published
Flexible backend framework
Downloads
6
Readme
Vort backend framework
Flexible full type-safe backend framework based on express
TODO
- [ ] tests
- [ ] add example requests and responses
- [x] response body
zod
checking - [x] OpenAPI params (query, path, body)
Get started
yarn add vort
Config
export const config = {
routes: path.join(__dirname, './routes'), // routes folder
swaggerRoute: '/swagger', // route to render swagger
}
App
import { Vort } from 'vort'
import config from './vort.config'
const app = new Vort(config)
app
.title('Best app') // title for openapi
.description('App for testing') // description for openapi
.version('1.0.0') // version for openapi
.listen(3000, () => {
console.log('listen')
})
Routes
Vort has file base system routing
Folder structure
routes
- hello/
- world.get.ts
- here
- another
- get.ts
- post.ts
- all-methods
- all.ts
- all-methods
- with-name.all.ts
- user/
- [user]/
- create.post.ts
with such folder structure, will generate express routings:
GET /hello/world
GET /here/another
POST /here/another
GET /here/all-methods
POST /here/all-methods
PUT /here/all-methods
PATCH /here/all-methods
DELETE /here/all-methods
HEAD /here/all-methods
OPTIONS /here/all-methods
GET /here/all-methods/with-name
POST /here/all-methods/with-name
PUT /here/all-methods/with-name
PATCH /here/all-methods/with-name
DELETE /here/all-methods/with-name
HEAD /here/all-methods/with-name
OPTIONS /here/all-methods/with-name
POST /user/:user/create
You can add -
before any file name to exclude all handlers below
routes
- hello/
- world.get.ts
- here
- -another
- get.ts
- post.ts
- -all-methods
- all.ts
- all-methods
- with-name.all.ts
- user/
- [user]/
- create.post.ts
GET /hello/world
POST /user/:user/create
Typings
To use define handler use handler
function
import { defineHandler, HTTPError } from 'vort'
import { z } from 'zod'
export default defineHandler()
.description('Best handler ever') // description of handler (for openapi generator)
.query(z.object({ name: z.string() })) // type safe query parameters
.params(z.object({ user: z.string() })) // type safe path parameters
.body(z.object({ hello: z.string() })) // type safe body parameters
.output(z.string())
.handler(async (req, res) => {
const { name } = req.query
// ^ string
const { user } = req.params
// ^ string
const { hello } = req.body
// ^ string
if (isError) throw new HTTPError('FORBIDDEN', 'Only admin function')
res.send('Hello') // type checking
res.send(3) // Error (not a string)
})
Middlewares
To define middleware use defineMiddleware
function
import { defineMiddleware } from 'vort'
import { z } from 'zod'
const isAdmin = defineMiddleware()
.locals(
z.object({
isAdmin: z.boolean(),
})
)
.middleware((req, res, next) => {
const { userId } = req.query
res.locals.isAdmin = userId === '1'
// ^ boolean
next()
})
Now isAdmin
can be used in handler definition
import { defineHandler, HTTPError } from 'vort'
import { z } from 'zod'
import { isAdmin } from '@/middlewares'
export default defineHandler()
.use(isAdmin)
.query(z.object({ userId: z.string }))
.handler((req, res) => {
if (!res.locals.isAdmin) {
// ^ boolean
throw new HTTPError('FORBIDDEN', 'User is not admin')
}
})
Modifiers
Modifier is function which can execute asyncronise way handler function to achive whole control on result, and helps to proceed errors heppens inside handler function
import { defineHandler, HTTPError } from 'vort'
import { z } from 'zod'
export default defineHandler()
.query(z.object({ page: z.number() }))
.output(z.array(z.string()))
.modifier(async (_req, res, handler) => {
try {
await handler()
} catch (e) {
console.error(e)
res.send([])
}
})
.handler(async (req, res) => {
if (req.query.page > 100) throw new HTTPError('BAD_REQUEST')
return ['some']
})
Swagger doc support
Add Swagger doc host on /swagger
generated by zod schemas (Based on OpenAPI 3.0.0)