controller.class.ts 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import { HTTPStatus } from 'deps';
  2. import { isSuccessfulStatus } from 'deps';
  3. import { logger } from 'infra/logger.ts';
  4. interface Options {
  5. status?: HTTPStatus;
  6. json?: boolean;
  7. }
  8. export default class Controller {
  9. constructor(
  10. public handlers: Record<
  11. string,
  12. (
  13. req: Request,
  14. error?: string,
  15. headers?: Record<string, string>,
  16. ) => Response | Promise<Response>
  17. >,
  18. ) {}
  19. public static response = (
  20. req: Request,
  21. body: string,
  22. options: Options = {},
  23. ) => {
  24. const url = new URL(req.url);
  25. const output = new TextEncoder().encode(body);
  26. const response = new Response(output, {
  27. status: options.status ?? HTTPStatus.OK,
  28. });
  29. const userName = this.getUser(req);
  30. if (options.json) {
  31. response.headers.set('Content-Type', 'application/json');
  32. }
  33. const userAgent = req.headers.get('User-Agent') ?? '-';
  34. const logMessage = this.getLogMessage(
  35. req.method,
  36. url.pathname,
  37. response.status,
  38. output.byteLength,
  39. userAgent,
  40. userName,
  41. );
  42. if (isSuccessfulStatus(response.status)) {
  43. if (this.isHealthCheck(userAgent)) {
  44. logger.debug(logMessage);
  45. } else {
  46. logger.info(logMessage);
  47. }
  48. } else {
  49. logger.error(logMessage);
  50. }
  51. return response;
  52. };
  53. public static responseJSON = (
  54. req: Request,
  55. body: unknown,
  56. options: Options = {},
  57. ) => {
  58. options.json = true;
  59. return this.response(req, JSON.stringify(body), options);
  60. };
  61. private static getUser = (req: Request): string | undefined => {
  62. const authHeader = req.headers.get('Authorization');
  63. if (authHeader && authHeader.startsWith('Basic ')) {
  64. const base64Credentials = authHeader.slice(6);
  65. const credentials = atob(base64Credentials);
  66. const [userName] = credentials.split(':');
  67. return userName;
  68. }
  69. return;
  70. };
  71. private static getLogMessage(
  72. method: string,
  73. path: string,
  74. status: number,
  75. length: number,
  76. userAgent: string,
  77. userName?: string,
  78. ) {
  79. const user = userName ? userName + ' ' : '';
  80. return `${method} ${path} ${user}${status} ${length} (${userAgent})`;
  81. }
  82. private static isHealthCheck(userAgent: string): boolean {
  83. return userAgent === Deno.env.get('DOCKER_USER_AGENT');
  84. }
  85. }