import { HTTPStatus } from 'deps'; import { isSuccessfulStatus } from 'deps'; import { logger } from 'infra/logger.ts'; interface Options { status?: HTTPStatus; json?: boolean; } export default class Controller { constructor( public handlers: Record< string, ( req: Request, error?: string, headers?: Record, ) => Response | Promise >, ) {} public static response = ( req: Request, body: string, options: Options = {}, ) => { const url = new URL(req.url); const output = new TextEncoder().encode(body); const response = new Response(output, { status: options.status ?? HTTPStatus.OK, }); const userName = this.getUser(req); if (options.json) { response.headers.set('Content-Type', 'application/json'); } const userAgent = req.headers.get('User-Agent') ?? '-'; const logMessage = this.getLogMessage( req.method, url.pathname, response.status, output.byteLength, userAgent, userName, ); if (isSuccessfulStatus(response.status)) { if (this.isHealthCheck(userAgent)) { logger.debug(logMessage); } else { logger.info(logMessage); } } else { logger.error(logMessage); } return response; }; public static responseJSON = ( req: Request, body: unknown, options: Options = {}, ) => { options.json = true; return this.response(req, JSON.stringify(body), options); }; private static getUser = (req: Request): string | undefined => { const authHeader = req.headers.get('Authorization'); if (authHeader && authHeader.startsWith('Basic ')) { const base64Credentials = authHeader.slice(6); const credentials = atob(base64Credentials); const [userName] = credentials.split(':'); return userName; } return; }; private static getLogMessage( method: string, path: string, status: number, length: number, userAgent: string, userName?: string, ) { const user = userName ? userName + ' ' : ''; return `${method} ${path} ${user}${status} ${length} (${userAgent})`; } private static isHealthCheck(userAgent: string): boolean { return userAgent === Deno.env.get('DOCKER_USER_AGENT'); } }