From 3e41fd650869e7bfdb875dccbc221cb3dd083832 Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Thu, 12 Sep 2024 11:51:16 +0330 Subject: [PATCH 1/9] feat(api-server): Add NanotronUrl class for handling client request URLs This commit adds a new file, `url.ts`, which contains the implementation of the `NanotronUrl` class. This class extends the `URL` class from the `node:url` module and provides additional functionality for handling client request URLs in the Nanotron API server. The `NanotronUrl` class includes a static property `versionPattern_` which is a regular expression used to match and replace the version prefix in the URL. It also has properties `method` and `debugId` which store the HTTP method and the debug ID of the request respectively. The constructor of the `NanotronUrl` class takes a `clientRequest` object of type `IncomingMessage` and a `prefix` parameter which represents the URL prefix. It modifies the URL by removing the prefix and replacing the version prefix with a single `/`. The modified URL is then passed to the `URL` constructor along with a default base URL. This commit enhances the functionality of the Nanotron API server by providing a dedicated class for handling client request URLs. This improves code organization and maintainability. --- packages/api-server/src/url.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 packages/api-server/src/url.ts diff --git a/packages/api-server/src/url.ts b/packages/api-server/src/url.ts new file mode 100644 index 0000000..0c4fef1 --- /dev/null +++ b/packages/api-server/src/url.ts @@ -0,0 +1,25 @@ +import {URL} from 'node:url'; + +import type {HttpMethod} from './type.js'; +import type {IncomingMessage} from 'node:http'; + +export class NanotronUrl extends URL { + protected static versionPattern_ = new RegExp('^/v[0-9]+/'); + + readonly method: HttpMethod; + readonly debugId: string; + + constructor(clientRequest: IncomingMessage, prefix: `/${string}/` | '/') { + let url = clientRequest.url ?? ''; + if (prefix !== '/' && url.indexOf(prefix) === 0) { + url = url.slice(prefix.length - 1); // include `/` + } + url = url.replace(NanotronUrl.versionPattern_, '/'); + + super(url, 'http://hostname/'); + + this.method = (clientRequest.method ?? 'GET').toUpperCase() as HttpMethod; + + this.debugId = `[${this.method}]${this.pathname}`; + } +} From 3e44a433f287c8d4c6fb18ac13cfa58805bb709b Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Thu, 12 Sep 2024 11:59:05 +0330 Subject: [PATCH 2/9] refactor(api-server): Update HttpResponseHeaders interface properties --- packages/api-server/src/type.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/api-server/src/type.ts b/packages/api-server/src/type.ts index a5b7b2d..0a84db7 100644 --- a/packages/api-server/src/type.ts +++ b/packages/api-server/src/type.ts @@ -24,12 +24,12 @@ export interface HttpResponseHeaders { /** * Specifies the time in seconds the object has been in a proxy cache. */ - 'age'?: string; + age?: string; /** * Lists the set of HTTP methods supported by the resource identified by the Request-URI. */ - 'allow'?: string; + allow?: string; /** * Specifies caching directives for both requests and responses. @@ -39,7 +39,7 @@ export interface HttpResponseHeaders { /** * Controls whether the network connection stays open after the current transaction. */ - 'connection'?: string; + connection?: string; /** * Suggests a filename for the downloaded resource or how the content should be displayed. @@ -79,17 +79,17 @@ export interface HttpResponseHeaders { /** * Indicates the date and time at which the message was originated. */ - 'date'?: string; + date?: string; /** * Provides the current value of the entity tag for the requested variant. */ - 'etag'?: string; + etag?: string; /** * Gives the date/time after which the response is considered stale. */ - 'expires'?: string; + expires?: string; /** * Indicates the date and time at which the origin server believes the variant was last modified. @@ -99,17 +99,17 @@ export interface HttpResponseHeaders { /** * Provides a list of URIs associated with the resource. */ - 'link'?: string; + link?: string; /** * Used in redirection, or when a new resource has been created. */ - 'location'?: string; + location?: string; /** * Used for backward compatibility with HTTP/1.0 caches. */ - 'pragma'?: string; + pragma?: string; /** * Requests authentication information from the client for a proxy server. @@ -124,7 +124,7 @@ export interface HttpResponseHeaders { /** * Contains information about the software used by the origin server to handle the request. */ - 'server'?: string; + server?: string; /** * Used to send cookies from the server to the user agent. @@ -139,7 +139,7 @@ export interface HttpResponseHeaders { /** * Allows the sender to include additional fields at the end of chunked messages. */ - 'trailer'?: string; + trailer?: string; /** * Specifies the form of encoding used to safely transfer the entity to the user. @@ -150,17 +150,17 @@ export interface HttpResponseHeaders { * Determines how to match future request headers to decide whether a cached response * can be used rather than requesting a fresh one from the origin server. */ - 'vary'?: string; + vary?: string; /** * Lists all intermediate proxies the message has traversed */ - 'via'?: string; + via?: string; /** * Contains additional information about the status or transformation of a message that might not be reflected in the status code. */ - 'warning'?: string; + warning?: string; /** * Indicates the authentication scheme that should be used to access the requested entity. From e6b62e50b8873fe77eb4bab084581b0c6c0d3c86 Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Thu, 12 Sep 2024 11:59:58 +0330 Subject: [PATCH 3/9] refactor(api-server): Update type.ts with NativeClientRequest and NativeServerResponse types --- packages/api-server/src/type.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/api-server/src/type.ts b/packages/api-server/src/type.ts index 0a84db7..2834d2d 100644 --- a/packages/api-server/src/type.ts +++ b/packages/api-server/src/type.ts @@ -1,6 +1,7 @@ -import type { NanotronClientRequest } from './api-client-request.js'; -import type { NanotronServerResponse } from './api-server-response.js'; -import type { Dictionary, Json, MaybePromise } from '@alwatr/type-helper'; +import type {NanotronClientRequest} from './api-client-request.js'; +import type {NanotronServerResponse} from './api-server-response.js'; +import type {Dictionary, Json, MaybePromise} from '@alwatr/type-helper'; +import type {IncomingMessage, ServerResponse} from 'node:http'; declare module 'http' { interface IncomingHttpHeaders { @@ -11,6 +12,9 @@ declare module 'http' { export type MatchType = 'exact' | 'startsWith'; export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'HEAD' | 'CONNECT' | 'TRACE'; +export type NativeClientRequest = IncomingMessage; +export type NativeServerResponse = ServerResponse; + /** * Represents the collection of HTTP response headers. From 46d74871631d47e7bc4c4b188367f4543915031f Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Thu, 12 Sep 2024 12:00:24 +0330 Subject: [PATCH 4/9] refactor(api-server): types --- packages/api-server/src/type.ts | 70 +++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/packages/api-server/src/type.ts b/packages/api-server/src/type.ts index 2834d2d..2a0c17a 100644 --- a/packages/api-server/src/type.ts +++ b/packages/api-server/src/type.ts @@ -12,9 +12,66 @@ declare module 'http' { export type MatchType = 'exact' | 'startsWith'; export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'HEAD' | 'CONNECT' | 'TRACE'; + +export type ErrorResponse = { + ok: false; + errorCode: Lowercase; + errorMessage: string; + meta?: Json; +}; + +export type RouteHandler = ( + clientRequest: NanotronClientRequest, + serverResponse: NanotronServerResponse, + sharedMeta: Dictionary, +) => MaybePromise; + export type NativeClientRequest = IncomingMessage; export type NativeServerResponse = ServerResponse; +/** + * Configuration options for defining a route. + */ +export interface DefineRouteOption { + /** + * The HTTP method for this route. + */ + method: HttpMethod; + + /** + * The URL path for this route. + */ + url: string; + + /** + * Specifies how the `url` should be matched against incoming requests. + * + * @default 'exact' + */ + matchType?: MatchType; + + /** + * The functions call before the main handler. + */ + preHandlers?: RouteHandler[]; + + /** + * The function to handle requests to this route. + */ + handler: RouteHandler; + + /** + * The functions call after the main handler. + */ + postHandlers?: RouteHandler[]; + + /** + * The maximum size of the request body in bytes. + * + * @default `1_048_576` (1MiB) or the value set in the server configuration. + */ + bodyLimit?: number; +} /** * Represents the collection of HTTP response headers. @@ -174,16 +231,3 @@ export interface HttpResponseHeaders { // Additional headers can be added here as needed [headerName: Lowercase]: string | string[] | number | undefined; } - -export type ErrorResponse = { - ok: false; - errorCode: Lowercase; - errorMessage: string; - meta?: Json; -} - -export type RouteHandler = ( - clientRequest: NanotronClientRequest, - serverResponse: NanotronServerResponse, - sharedMeta: Dictionary, -) => MaybePromise; From c94c9546927c13b3b72d24522bd1fc46ce4f6163 Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Thu, 12 Sep 2024 12:00:36 +0330 Subject: [PATCH 5/9] refactor(api-server): Update main.ts exports with NanotronClientRequest, NanotronServerResponse, and NanotronUrl types --- packages/api-server/src/main.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/api-server/src/main.ts b/packages/api-server/src/main.ts index f7d7c81..eaeff87 100644 --- a/packages/api-server/src/main.ts +++ b/packages/api-server/src/main.ts @@ -1,5 +1,6 @@ export * from './api-server.js'; -export * from './api-client-request.js'; -export * from './api-server-response.js'; +export type {NanotronClientRequest} from './api-client-request.js'; +export type {NanotronServerResponse} from './api-server-response.js'; +export type {NanotronUrl} from './url.js'; export * from './type.js'; export * from './const.js'; From 0f47dd7221a67f5a21269f76c60df125ac6e9c93 Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Thu, 12 Sep 2024 12:01:14 +0330 Subject: [PATCH 6/9] refactor(api-server): Update NanotronServerResponse class - Update import statements and types in NanotronServerResponse class - Add NanotronClientRequest and NativeServerResponse types to type imports - Remove unused import of ServerResponse from node:http - Update constructor parameters to store NanotronClientRequest and NativeServerResponse - Update logger method calls with debugId from clientRequest.url - Update replyErrorResponse and replyError methods to use clientRequest instead of config - Update replyJson method to use debugId from clientRequest.url in logger error call - Update reply method to use debugId from clientRequest.url in logger method call - Remove unnecessary error logging in replyJson and reply methods --- .../api-server/src/api-server-response.ts | 54 ++++++------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/packages/api-server/src/api-server-response.ts b/packages/api-server/src/api-server-response.ts index c14e8e3..5f47817 100644 --- a/packages/api-server/src/api-server-response.ts +++ b/packages/api-server/src/api-server-response.ts @@ -3,9 +3,8 @@ import {createLogger} from '@alwatr/logger'; import {type HttpStatusCode, HttpStatusCodes, HttpStatusMessages} from './const.js'; import type {NanotronClientRequest} from './api-client-request.js'; -import type {HttpResponseHeaders, ErrorResponse} from './type.js'; +import type {HttpResponseHeaders, ErrorResponse, NativeServerResponse} from './type.js'; import type {Json} from '@alwatr/type-helper'; -import type {ServerResponse} from 'node:http'; /** * Configuration options for the Nanotron Api Server Response. @@ -15,30 +14,27 @@ export interface NanotronServerResponseConfig { } export class NanotronServerResponse { - readonly raw_; + readonly clientRequest: NanotronClientRequest; + + readonly raw_: NativeServerResponse; readonly headers: HttpResponseHeaders; protected readonly logger_; - protected readonly config_; - protected hasBeenSent_ = false; get hasBeenSent(): boolean { return this.hasBeenSent_; } - constructor( - serverResponse: ServerResponse, - config: NanotronServerResponseConfig, - ) { - // Store the raw request object and configuration. - this.config_ = config; - this.raw_ = serverResponse; + constructor(nanotronClientRequest: NanotronClientRequest, nativeServerResponse: NativeServerResponse) { + // Store public properties. + this.clientRequest = nanotronClientRequest; + this.raw_ = nativeServerResponse; // Create logger. this.logger_ = createLogger('nt-server-response'); // TODO: add client ip - this.logger_.logMethod?.('new'); + this.logger_.logMethodArgs?.('new', this.clientRequest.url.debugId); // Set default reply headers. this.headers = { @@ -64,14 +60,14 @@ export class NanotronServerResponse { replyErrorResponse(errorResponse: ErrorResponse): void { this.logger_.logMethod?.('replyErrorResponse'); - this.config_.clientRequest.terminatedHandlers = true; + this.clientRequest.terminatedHandlers = true; this.replyJson(errorResponse); } replyError(error?: Error | string | Json | unknown): void { this.logger_.logMethodArgs?.('replyError', {error}); - this.config_.clientRequest.terminatedHandlers = true; + this.clientRequest.terminatedHandlers = true; let statusCode = this.statusCode; if (statusCode < HttpStatusCodes.Error_Client_400_Bad_Request) { @@ -81,13 +77,10 @@ export class NanotronServerResponse { if (error instanceof Error) { this.replyJson({ ok: false, - errorCode: error.name === 'Error' - ? ('error_' + statusCode) as Lowercase - : (error.name + '').toLowerCase(), + errorCode: error.name === 'Error' ? (('error_' + statusCode) as Lowercase) : (error.name + '').toLowerCase(), errorMessage: error.message, }); } - else if (typeof error === 'string') { this.replyJson({ ok: false, @@ -95,16 +88,14 @@ export class NanotronServerResponse { errorMessage: error, }); } - else if (typeof error === 'object' && error !== null) { this.replyJson(error as Json); } - else { this.replyJson({ ok: false, errorCode: ('error_' + statusCode) as Lowercase, - errorMessage: HttpStatusMessages[statusCode] + errorMessage: HttpStatusMessages[statusCode], } as ErrorResponse); } } @@ -117,10 +108,7 @@ export class NanotronServerResponse { responseString = JSON.stringify(responseJson); } catch (error) { - this.logger_.error('replyJson', 'reply_json_stringify_failed', error, { - url: this.config_.clientRequest.url.pathname, - method: this.config_.clientRequest.method, - }); + this.logger_.error('replyJson', 'reply_json_stringify_failed', error, this.clientRequest.url.debugId); this.statusCode = HttpStatusCodes.Error_Server_500_Internal_Server_Error; responseString = JSON.stringify({ ok: false, @@ -134,10 +122,7 @@ export class NanotronServerResponse { } reply(context: string | Buffer): void { - this.logger_.logMethodArgs?.('reply', { - url: this.config_.clientRequest.url.pathname, - method: this.config_.clientRequest.method, - }); + this.logger_.logMethodArgs?.('reply', this.clientRequest.url.debugId); if (this.raw_.writableFinished && this.hasBeenSent_ === false) { // The response has already been sent by direct access to the server api. @@ -147,8 +132,7 @@ export class NanotronServerResponse { if (this.hasBeenSent_) { this.logger_.accident('reply', 'reply_already_sent', { - url: this.config_.clientRequest.url.pathname, - method: this.config_.clientRequest.method, + url: this.clientRequest.url.debugId, replySent: this.hasBeenSent_, writableFinished: this.raw_.writableFinished, }); @@ -166,13 +150,9 @@ export class NanotronServerResponse { this.applyHeaders_(); this.raw_.end(context, 'binary'); - } catch (error) { - this.logger_.error('reply', 'server_response_error', error, { - url: this.config_.clientRequest.url.pathname, - method: this.config_.clientRequest.method, - }); + this.logger_.error('reply', 'server_response_error', error, this.clientRequest.url.debugId); this.hasBeenSent_ = false; } } From 468d3d910342a6963c07de18e9cccc933934a111 Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Thu, 12 Sep 2024 12:01:25 +0330 Subject: [PATCH 7/9] refactor(api-server): Update NanotronClientRequest class - Update imports and remove unused dependencies - Add type annotations for properties and parameters - Refactor constructor to accept NanotronUrl, NativeClientRequest, NativeServerResponse, and DefineRouteOption - Create NanotronServerResponse instance in constructor - Update logger method calls --- packages/api-server/src/api-client-request.ts | 60 +++++++------------ 1 file changed, 22 insertions(+), 38 deletions(-) diff --git a/packages/api-server/src/api-client-request.ts b/packages/api-server/src/api-client-request.ts index 59eb8d9..2867460 100644 --- a/packages/api-server/src/api-client-request.ts +++ b/packages/api-server/src/api-client-request.ts @@ -1,28 +1,17 @@ import {createLogger} from '@alwatr/logger'; -import type {HttpMethod, RouteHandler} from './type.js'; -import type {IncomingMessage} from 'node:http'; +import {NanotronServerResponse} from './api-server-response.js'; -/** - * Configuration options for the Nanotron Api Client Request. - */ -export interface NanotronClientRequestConfig { - /** - * A prefix to be added to the beginning of the `url` of all defined routes. - * - * @default '/api/' - */ - prefix: `/${string}/` | '/'; -} +import type {DefineRouteOption, NativeClientRequest, NativeServerResponse} from './type.js'; +import type {NanotronUrl} from './url.js'; +import type {Dictionary} from '@alwatr/type-helper'; export class NanotronClientRequest { - protected static versionPattern_ = new RegExp('^/v[0-9]+/'); - - readonly url; + readonly url: NanotronUrl; - readonly method; + readonly serverResponse: NanotronServerResponse; - readonly raw_; + readonly routeOption: DefineRouteOption | null; /** * A flag to indicate if the running handlers queue has been terminated. @@ -38,33 +27,28 @@ export class NanotronClientRequest { */ terminatedHandlers?: true; - readonly preHandlers_: RouteHandler[] = []; + readonly sharedMeta: Dictionary = {}; - protected readonly logger_; + readonly raw_: NativeClientRequest; - protected readonly config_; + protected readonly logger_; constructor( - clientRequest: IncomingMessage, - config: NanotronClientRequestConfig, + url: NanotronUrl, + nativeClientRequest: NativeClientRequest, + nativeServerResponse: NativeServerResponse, + routeOption: DefineRouteOption | null, ) { - // Store the raw request object and configuration. - this.config_ = config; - this.raw_ = clientRequest; - - // Parse request method. - this.method = (this.raw_.method ?? 'GET').toUpperCase() as HttpMethod; - - // Parse request URL. - let url = this.raw_.url ?? ''; - if (this.config_.prefix !== '/' && url.indexOf(this.config_.prefix) === 0) { - url = url.slice(this.config_.prefix.length - 1); - } - url = url.replace(NanotronClientRequest.versionPattern_, '/'); - this.url = new URL(url, 'http://hostname/'); + // Store public properties. + this.raw_ = nativeClientRequest; + this.url = url; + this.routeOption = routeOption; // Create logger. this.logger_ = createLogger('nt-client-request'); // TODO: add client ip - this.logger_.logMethodArgs?.('new', {method: this.method, url: this.url.pathname}); + this.logger_.logMethodArgs?.('new', url.debugId); + + // Create server response. + this.serverResponse = new NanotronServerResponse(this, nativeServerResponse); } } From 7b587e06dbcf493424dd0bd70de402f14e2e519a Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Thu, 12 Sep 2024 12:02:06 +0330 Subject: [PATCH 8/9] refactor(api-server): Update NanotronClientRequest class and NanotronServerResponse class - Removed unused imports and updated the imports for NanotronClientRequest and NanotronServerResponse classes in api-server.ts. - Added import for NanotronUrl in api-server.ts. - Updated the type definitions in type.ts to include NativeClientRequest and NativeServerResponse types. - Updated the bodyLimit default value in NanotronApiServer class to 1MiB. - Refactored the handleClientRequest_ method in NanotronApiServer class to use the new NativeClientRequest and NativeServerResponse types. - Updated the getRouteOption_ method in NanotronApiServer class to use the new NanotronUrl class. - Removed unused code and added error handling in the handleClientRequest_ method. - Updated the comments and log messages for better clarity and readability. --- packages/api-server/src/api-server.ts | 126 +++++++++----------------- 1 file changed, 42 insertions(+), 84 deletions(-) diff --git a/packages/api-server/src/api-server.ts b/packages/api-server/src/api-server.ts index 99bc2ad..8bf5ebb 100644 --- a/packages/api-server/src/api-server.ts +++ b/packages/api-server/src/api-server.ts @@ -1,12 +1,12 @@ -import {createServer, IncomingMessage, ServerResponse} from 'node:http'; +import {createServer} from 'node:http'; import {createLogger} from '@alwatr/logger'; import {NanotronClientRequest} from './api-client-request.js'; -import { NanotronServerResponse } from './api-server-response.js'; import {HttpStatusCodes} from './const.js'; +import {NanotronUrl} from './url.js'; -import type {HttpMethod, MatchType, RouteHandler} from './type.js'; +import type {DefineRouteOption, MatchType, NativeClientRequest, NativeServerResponse} from './type.js'; import type {Dictionary} from '@alwatr/type-helper'; import type {Duplex} from 'node:stream'; @@ -71,43 +71,13 @@ export interface NanotronApiServerConfig { * @default '/api/' */ prefix?: `/${string}/` | '/'; -} -/** - * Configuration options for defining a route. - */ -export interface DefineRouteOption { /** - * The HTTP method for this route. - */ - method: HttpMethod; - - /** - * The URL path for this route. - */ - url: string; - - /** - * Specifies how the `url` should be matched against incoming requests. + * The maximum size of the request body in bytes. * - * @default 'exact' - */ - matchType?: MatchType; - - /** - * The functions call before the main handler. - */ - preHandlers?: RouteHandler[]; - - /** - * The function to handle requests to this route. + * @default `1_048_576` (1MiB) */ - handler: RouteHandler; - - /** - * The functions call after the main handler. - */ - postHandlers?: RouteHandler[]; + bodyLimit?: number; } export class NanotronApiServer { @@ -120,9 +90,10 @@ export class NanotronApiServer { healthRoute: true, allowAllOrigin: false, prefix: '/api/', + bodyLimit: 1_048_576, // 1MiB }; - protected readonly config_; + readonly config_; protected readonly logger_; readonly httpServer; @@ -181,26 +152,26 @@ export class NanotronApiServer { this.httpServer.close(); } - protected getRouteOption_(option: Required>): Required | null { - this.logger_.logMethodArgs?.('getRouteOption_', option); + protected getRouteOption_(url: NanotronUrl): Required | null { + this.logger_.logMethod?.('getRouteOption_'); if ( - Object.hasOwn(this.routeHandlerList__.exact, option.method) && - Object.hasOwn(this.routeHandlerList__.exact[option.method], option.url) + Object.hasOwn(this.routeHandlerList__.exact, url.method) && + Object.hasOwn(this.routeHandlerList__.exact[url.method], url.pathname) ) { - return this.routeHandlerList__.exact[option.method][option.url]; + return this.routeHandlerList__.exact[url.method][url.pathname]; } - if (Object.hasOwn(this.routeHandlerList__.startsWith, option.method)) { - const routeList = this.routeHandlerList__.startsWith[option.method]; - for (const url in routeList) { - if (url.indexOf(option.url) === 0) { - return routeList[url]; + if (Object.hasOwn(this.routeHandlerList__.startsWith, url.method)) { + const routeList = this.routeHandlerList__.startsWith[url.method]; + for (const pathname in routeList) { + if (pathname.indexOf(url.pathname) === 0) { + return routeList[pathname]; } } } - this.logger_.incident?.('getRouteOption_', 'route_not_found', option); + this.logger_.incident?.('getRouteOption_', 'route_not_found', {method: url.method, url: url.pathname}); return null; } @@ -224,6 +195,7 @@ export class NanotronApiServer { matchType: 'exact', preHandlers: [], postHandlers: [], + bodyLimit: this.config_.bodyLimit, ...option, }; this.logger_.logMethodArgs?.('defineRoute', {...option_, handler: 'function'}); @@ -247,68 +219,54 @@ export class NanotronApiServer { socket.end('HTTP/1.1 400 Bad Request\r\n\r\n'); } - protected handleHttpError_(serverResponse: NanotronServerResponse, error?: unknown): void { - this.logger_.logMethod?.('handleHttpError_'); - // TODO: custom error template by the user. - serverResponse.replyError(error); - } - - protected async handleClientRequest_(clientRequest: IncomingMessage, serverResponse: ServerResponse): Promise { + protected async handleClientRequest_( + nativeClientRequest: NativeClientRequest, + nativeServerResponse: NativeServerResponse, + ): Promise { this.logger_.logMethod?.('handleClientRequest_'); - if (clientRequest.url === undefined) { + if (nativeClientRequest.url === undefined) { this.logger_.accident('handleClientRequest_', 'http_server_url_undefined'); return; } - if (clientRequest.method === undefined) { + if (nativeClientRequest.method === undefined) { this.logger_.accident('handleClientRequest_', 'http_server_method_undefined'); return; } - const nanotronClientRequest = new NanotronClientRequest(clientRequest, {prefix: this.config_.prefix}); - const nanotronServerResponse = new NanotronServerResponse(serverResponse, {clientRequest: nanotronClientRequest}); + const url = new NanotronUrl(nativeClientRequest, this.config_.prefix); - const routeOption = this.getRouteOption_({ - method: nanotronClientRequest.method, - url: nanotronClientRequest.url.pathname, - }); + const routeOption = this.getRouteOption_(url); + + const connection = new NanotronClientRequest(url, nativeClientRequest, nativeServerResponse, routeOption); if (routeOption === null) { - nanotronServerResponse.statusCode = HttpStatusCodes.Error_Client_404_Not_Found; - return this.handleHttpError_(nanotronServerResponse); + connection.serverResponse.statusCode = HttpStatusCodes.Error_Client_404_Not_Found; + connection.serverResponse.replyError(); + return; } - const sharedMeta = {}; - try { - for (const handler of nanotronClientRequest.preHandlers_) { - if (nanotronClientRequest.terminatedHandlers === true) return; - await handler(nanotronClientRequest, nanotronServerResponse, sharedMeta); - } - for (const handler of routeOption.preHandlers) { - if (nanotronClientRequest.terminatedHandlers === true) return; - await handler(nanotronClientRequest, nanotronServerResponse, sharedMeta); + if (connection.terminatedHandlers === true) return; + await handler(connection, connection.serverResponse, connection.sharedMeta); } - await routeOption.handler(nanotronClientRequest, nanotronServerResponse, sharedMeta); + await routeOption.handler(connection, connection.serverResponse, connection.sharedMeta); for (const handler of routeOption.postHandlers) { - if (nanotronClientRequest.terminatedHandlers === true) return; - await handler(nanotronClientRequest, nanotronServerResponse, sharedMeta); + if (connection.terminatedHandlers === true) return; + await handler(connection, connection.serverResponse, connection.sharedMeta); } } catch (error) { - this.logger_.error('handleClientRequest_', 'route_handler_error', error, { - url: nanotronClientRequest.url.pathname, - method: nanotronClientRequest.method, - }); + this.logger_.error('handleClientRequest_', 'route_handler_error', error, url.debugId); - if (nanotronServerResponse.statusCode < HttpStatusCodes.Error_Client_400_Bad_Request) { - nanotronServerResponse.statusCode = HttpStatusCodes.Error_Server_500_Internal_Server_Error; + if (connection.serverResponse.statusCode < HttpStatusCodes.Error_Client_400_Bad_Request) { + connection.serverResponse.statusCode = HttpStatusCodes.Error_Server_500_Internal_Server_Error; } - this.handleHttpError_(nanotronServerResponse, error); + connection.serverResponse.replyError(error); } // TODO: handled open remained connections. From d2dad04bd6e288b99e145a8af1bbadba8d6f7cbe Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Thu, 12 Sep 2024 12:09:00 +0330 Subject: [PATCH 9/9] refactor(api-server): Add new route for /hello endpoint --- packages/nanotron/demo/api-server.mjs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/nanotron/demo/api-server.mjs b/packages/nanotron/demo/api-server.mjs index 3da5982..2fd6828 100644 --- a/packages/nanotron/demo/api-server.mjs +++ b/packages/nanotron/demo/api-server.mjs @@ -25,3 +25,14 @@ apiServer.defineRoute({ }); } }); + +apiServer.defineRoute({ + method: 'GET', + url: '/hello', + handler (connection) { + connection.serverResponse.replyJson({ + ok: true, + message: 'Hello :)', + }); + } +});