Routex Hooks are an alternative way to write server-side code, inspired by the great re-usability of React Hooks
You can use @routex/hooks for Hooks.
Unlike React Hooks, Routex Hooks can be called conditionally or in loops. Hook handlers must be wrapped by hooksHandler (see below)
Hooks should be prefixed with use as a convention, but it is not enforced. It is strongly recommended that the prefix is used for consistency
# InstallCopy yarn add @routex/hooks
npm add @routex/hooks
# UsageSetup your app:
Copy const { Routex , TextBody } = require ( "routex" ) ;
const { hooksHandler , useGetParam } = require ( "@routex/hooks" ) ;
const port = process . env . PORT || 3000 ;
const app = new Routex ( ) ;
app . get (
"/:name" ,
hooksHandler ( ( ) => {
const name = useGetParam ( "name" ) ;
return new TextBody ( name ) ;
} )
) ;
app . listen ( port ) . then ( ( ) => console . log ( ` Listening on ${ port } ` ) ) ;
# hooksHandlerAll handlers must be wrapped inside the hooksHandler function. This can optionally accept the standard ctx object, like a regular handler.
You can do anything a handler can do, including using a wrapped handled as a middleware or returning a body
# HooksMany Hooks are available for common uses. You can also create re-usable Custom Hooks (see below)
# useGetCtxGet the current ctx object for the request
Example:
Copy const { hooksHandler , useGetCtx } = require ( "@routex/hooks" ) ;
const handler = hooksHandler ( ( ) => {
const ctx = useGetCtx ( ) ;
} ) ;
# useGetParamGet a path parameter, such as /:name
Example:
Copy const { hooksHandler , useGetParam } = require ( "@routex/hooks" ) ;
const handler = hooksHandler ( ( ) => {
const name = useGetParam ( "name" ) ;
} ) ;
app . get ( "/:name" , handler ) ;
# useGetQueryGet a query parameter, such as /?name=john
Example:
Copy const { hooksHandler , useGetQuery } = require ( "@routex/hooks" ) ;
const handler = hooksHandler ( ( ) => {
const name = useGetQuery ( "name" ) ;
} ) ;
# useGetHeaderGet a request header, such as Authorization
Example:
Copy const { hooksHandler , useGetHeader } = require ( "@routex/hooks" ) ;
const handler = hooksHandler ( ( ) => {
const token = useGetHeader ( "Authorization" ) ;
} ) ;
# useGetAllDataGet ctx.data
Example:
Copy const { hooksHandler , useGetAllData } = require ( "@routex/hooks" ) ;
const handler = hooksHandler ( ( ) => {
const data = useGetAllData ( ) ;
} ) ;
# useGetDataGet a field from ctx.data
Example:
Copy const { hooksHandler , useGetData } = require ( "@routex/hooks" ) ;
const handler = hooksHandler ( ( ) => {
const user = useGetData ( "user" ) ;
} ) ;
# useSetDataSet a field in ctx.data
Example:
Copy const { hooksHandler , useSetData } = require ( "@routex/hooks" ) ;
const handler = hooksHandler ( ( ) => {
useSetData ( "user" , { name : "john" } ) ;
} ) ;
# useGetAllProvidersGet ctx.providers
Example:
Copy const { hooksHandler , useGetAllProviders } = require ( "@routex/hooks" ) ;
const handler = hooksHandler ( ( ) => {
const providers = useGetAllProviders ( ) ;
} ) ;
# useGetProviderGet a provider from ctx.providers
Example:
Copy const { hooksHandler , useGetProvider } = require ( "@routex/hooks" ) ;
const handler = hooksHandler ( ( ) => {
const userRepository = useGetProvider ( "userRepository" ) ;
} ) ;
# useGetMethodGet the request method, such as get or post
Example:
Copy const { hooksHandler , useGetMethod } = require ( "@routex/hooks" ) ;
const handler = hooksHandler ( ( ) => {
const method = useGetMethod ( ) ;
} ) ;
# useSetStatusCodeSet the response status code, such as 200 or 404
Example:
Copy const { hooksHandler , useSetStatusCode } = require ( "@routex/hooks" ) ;
const handler = hooksHandler ( ( ) => {
useSetStatusCode ( 404 ) ;
} ) ;
# useSetBodySet the response body.
It is recommended to use return for bodies.
Example:
Copy const { hooksHandler , useSetBody } = require ( "@routex/hooks" ) ;
const handler = hooksHandler ( ( ) => {
useSetBody ( new JsonBody ( { name : "john" } ) ) ;
} ) ;
# Custom HooksYou can extract common functionality inside custom hooks, which can replace middlewares at the route level (middlewares are still preferred when used at the router level).
For example, if you often need to check if a parameter is set, and exists in the database, you can turn this:
Copy const { hooksHandler , useGetQuery } = require ( "@routex/hooks" ) ;
const getNameHandler = hooksHandler ( async ( ) => {
const id = useGetQuery ( "id" ) ;
if ( ! id ) {
throw new ErrorWithBody ( 200 , new JsonBody ( { error : "ID is required" } ) ) ;
}
const user = await useGetProvider ( "userRepository" ) . getUser ( id ) ;
if ( ! user ) {
throw new ErrorWithBody ( 200 , new JsonBody ( { error : "User not found" } ) ) ;
}
return new JsonBody ( { name : user . name } ) ;
} ) ;
const getAgeHandler = hooksHandler ( async ( ) => {
const id = useGetQuery ( "id" ) ;
if ( ! id ) {
throw new ErrorWithBody ( 200 , new JsonBody ( { error : "ID is required" } ) ) ;
}
const user = await useGetProvider ( "userRepository" ) . getUser ( id ) ;
if ( ! user ) {
throw new ErrorWithBody ( 200 , new JsonBody ( { error : "User not found" } ) ) ;
}
return new JsonBody ( { age : user . age } ) ;
} ) ;
Into the following:
Copy const { hooksHandler , useGetQuery } = require ( "@routex/hooks" ) ;
async function useGetUser ( id ) {
const id = useGetQuery ( "id" ) ;
if ( ! id ) {
throw new ErrorWithBody ( 200 , new JsonBody ( { error : "ID is required" } ) ) ;
}
const user = useGetProvider ( "userRepository" ) . getUser ( id ) ;
if ( ! user ) {
throw new ErrorWithBody ( 200 , new JsonBody ( { error : "User not found" } ) ) ;
}
return user ;
}
const getNameHandler = hooksHandler ( async ( ) => {
const user = await useGetUser ( ) ;
return new JsonBody ( { name : user . name } ) ;
} ) ;
const getAgeHandler = hooksHandler ( async ( ) => {
const user = await useGetUser ( ) ;
return new JsonBody ( { age : user . age } ) ;
} ) ;