1
Fork 0
mirror of https://github.com/Steffo99/festa.git synced 2024-12-23 15:14:23 +00:00
festa/utils/api/index.ts

87 lines
3.4 KiB
TypeScript
Raw Normal View History

2022-06-11 03:08:49 +00:00
import { NextApiRequest, NextApiResponse } from "next";
import { FestaAuthenticator } from "./authenticator";
import { FestaConfigurator } from "./configurator";
import { FestaExecutor } from "./executor";
import { Response as Response } from "./throwables";
import { FestaBodyValidator } from "./bodyValidator";
import { FestaQueryValidator } from "./queryValidator";
/**
* Parameters of {@link festaAPI}.
*/
type FestaAPI<Config, Auth, Query, Body, Response> = {
configurator: FestaConfigurator<Config>,
queryValidator: FestaQueryValidator<Config, Query>,
authenticator: FestaAuthenticator<Config, Auth>,
bodyValidator: FestaBodyValidator<Config, Body>,
executor: FestaExecutor<Config, Auth, Query, Body, Response>,
}
export async function festaAPI<Config, Query, Auth, Body, Response>(req: NextApiRequest, res: NextApiResponse, { configurator, authenticator, queryValidator, bodyValidator, executor }: FestaAPI<Config, Query, Auth, Body, Response>): Promise<void> {
await Response.handle(res, async () => {
// Set the Access-Control-Allow-Origin header
res.setHeader("Access-Control-Allow-Origin", "*")
// Set the WWW-Authenticate header
res.setHeader("WWW-Authenticate", authenticator.header)
// Set the Allow header
res.setHeader("Allow", ["HEAD", "OPTIONS", ...executor.methods].join(", "))
// Get configuration
const config = await Response.convertThrownErrors(
async () => await configurator.perform(),
"Server is not configured appropriately to handle this request"
)
// Validate the request query
const query = await Response.convertThrownErrors(
async () => await queryValidator.perform({ config, query: req.query }),
"Unexpected error occurred during validation of this request"
)
// Head requests cut-off here
if (req.method === "HEAD") {
throw new Response({ status: 204 })
}
// Options requests cut-off here
if (req.method === "OPTIONS") {
// If validation is not performed, no body is sent to OPTIONS requests
if (!bodyValidator.schema) {
throw new Response({ status: 204 })
}
else {
throw new Response({ status: 200, body: bodyValidator.schema })
}
}
// Perform user agent authentication
const auth = await Response.convertThrownErrors(
async () => await authenticator.perform({ config, header: req.headers.authorization }),
"Unexpected error occurred during authentication of this request"
)
// Get requests shouldn't have a body
let body: Body | undefined = undefined
if (req.method !== "GET") {
// Validate the request body
body = await Response.convertThrownErrors(
async () => await bodyValidator.perform({ config, body: req.body }),
"Unexpected error occurred during validation of this request"
)
}
// Act on the data and determine a response
const result = await Response.convertThrownErrors(
async () => await executor.perform({ config, auth, query, body, method: req.method! }),
"Unexpected error occurred during execution of this request"
)
throw new Response({ status: 200, body: result })
})
}