Skip to content

Commit

Permalink
#38
Browse files Browse the repository at this point in the history
- http: в ResponseError добавлен урл для редиректа (minor)
- tokens: добавлены токены для декомпозиции main-функции обработчика (minor)
  • Loading branch information
krutoo committed Mar 21, 2024
1 parent 144859c commit 610a46d
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 6 deletions.
20 changes: 20 additions & 0 deletions src/http/__test__/errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,24 @@ describe('ResponseError', () => {
expect(error.message).toBe('Hello!');
expect(error.statusCode).toBe(500);
});

it('should handle init', () => {
const error = new ResponseError('Need redirect', {
statusCode: 301,
redirectLocation: '/hello.php',
logLevel: 'debug',
});

expect(error.logLevel).toBe('debug');
expect(error.statusCode).toBe(301);
expect(error.redirectLocation).toBe('/hello.php');
});

it('should handle empty init', () => {
const error = new ResponseError('Need redirect', {});

expect(error.logLevel).toBe('error');
expect(error.statusCode).toBe(500);
expect(error.redirectLocation).toBe(null);
});
});
20 changes: 17 additions & 3 deletions src/http/errors.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import type { LogLevel } from '../log';
import type { ResponseErrorInit } from './types';

/**
* Ошибка валидации статуса ответа.
* @todo Переименовать в HttpStatusValidationError?
Expand Down Expand Up @@ -28,15 +31,26 @@ export class StatusError extends Error {
* Ошибка в процессе формирования ответа.
*/
export class ResponseError extends Error {
logLevel: LogLevel | null;
statusCode: number;
redirectLocation: string | null;

/**
* @param message Сообщение.
* @param statusCode Код ответа.
* @param statusCodeOrInit Код ответа.
*/
constructor(message: string, statusCode = 500) {
constructor(message: string, statusCodeOrInit: number | ResponseErrorInit = 500) {
super(message);
this.name = 'ResponseError';
this.statusCode = statusCode;

if (typeof statusCodeOrInit === 'number') {
this.logLevel = 'error';
this.statusCode = statusCodeOrInit;
this.redirectLocation = null;
} else {
this.logLevel = statusCodeOrInit.logLevel ?? 'error';
this.statusCode = statusCodeOrInit.statusCode ?? 500;
this.redirectLocation = statusCodeOrInit.redirectLocation ?? null;
}
}
}
1 change: 1 addition & 0 deletions src/http/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type {
EitherResponse,
ResponseDone,
ResponseFail,
ResponseErrorInit,
} from './types';
export { configureFetch, applyMiddleware, createCookieStore } from '@krutoo/fetch-tools';
export { log, cookie, defaultHeaders, validateStatus } from '@krutoo/fetch-tools/middleware';
Expand Down
8 changes: 8 additions & 0 deletions src/http/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { LogLevel } from '../log';

export type { Handler, Enhancer, Middleware, CookieStore } from '@krutoo/fetch-tools';
export type {
LogData,
Expand Down Expand Up @@ -26,3 +28,9 @@ export interface ResponseFail<T = unknown> {
}

export type EitherResponse<T> = ResponseDone<T> | ResponseFail<T>;

export interface ResponseErrorInit {
statusCode?: number;
redirectLocation?: string;
logLevel?: LogLevel | null;
}
3 changes: 2 additions & 1 deletion src/preset/bun/utils/get-stats-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import type { Handler } from '../../../http';
export function getStatsHandler(): Handler {
/** @inheritdoc */
const getHeapStats = async () => {
// ВАЖНО: должны быть именно кавычки "'" по причине https://github.com/web-infra-dev/rspack/issues/5938#issuecomment-2000393152
const jsc = await import(
/* webpackIgnore: true */
`bun:jsc`
'bun:jsc'
);

return jsc.heapStats();
Expand Down
6 changes: 6 additions & 0 deletions src/preset/server/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ export const PAGE_HANDLER_EVENT_TYPE = {
renderStart: 'isomorph/render:start',
renderFinish: 'isomorph/render:finish',
} as const;

/**
* Приоритет форматов ответа на запрос страницы.
* Нужен для использования вместе с пакетом accepts.
*/
export const PAGE_FORMAT_PRIORITY = ['json', 'html'];
22 changes: 20 additions & 2 deletions src/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,21 @@ import type { BridgeClientSide, BridgeServerSide } from './utils/ssr';
import type { Tracer } from '@opentelemetry/api';
import type { BasicTracerProvider, SpanExporter } from '@opentelemetry/sdk-trace-base';
import type { Resource } from '@opentelemetry/resources';
import type { ElementType, ReactNode } from 'react';
import type { ElementType, ReactNode, JSX } from 'react';
import type { KnownHttpApiKey, PageAssets } from './preset/isomorphic/types';
import type { ExpressHandlerContext } from './preset/node/types';
import type { SpecificExtras } from './preset/server/utils/specific-extras';
import type { CreateAxiosDefaults } from 'axios';
import type { AxiosInstanceWrapper, Middleware as AxiosMiddleware } from 'middleware-axios';
import type { CookieStore, Handler, LogHandler, LogHandlerFactory, Middleware } from './http';
import type { HttpApiHostPool } from './preset/isomorphic/utils/http-api-host-pool';
import type { ServerHandlerContext, ServerHandler, ServerMiddleware } from './preset/server/types';
import type {
ServerHandlerContext,
ServerHandler,
ServerMiddleware,
PageResponseFormatter,
RenderToString,
} from './preset/server/types';

/**
* Токены компонентов.
Expand Down Expand Up @@ -114,12 +120,18 @@ export const KnownToken = {

/** Токен компонентов входящего запроса. */
Request: {
/** Токен функции которая определяет возможные типы ответа и их приоритет. */
acceptType: createToken<(types: string[]) => string | string[] | false>('handler/accepts'),

/** Токен "специфичных" параметров запроса. В зависимости от реализации определит параметры на основе объекта запроса. */
specificParams: createToken<Record<string, unknown>>('request/specific-params'),
},

/** Токены компонентов исходящего ответа. */
Response: {
/** Токен объекта для подписки на события и вызова событий ответа. */
events: createToken<EventTarget>('response/events'),

/** Токен "специфичных" дополнительных данных. В зависимости от реализации сформирует дополнительные данные ответа. */
specificExtras: createToken<SpecificExtras>('response/specific-extras'),
},
Expand All @@ -134,6 +146,12 @@ export const KnownToken = {

/** Токен "шлема". Шлем - UI-компонент, внутри которого будет выведен результат render-функции. */
helmet: createToken<ElementType<{ children: ReactNode }>>('page/helmet'),

/** Токен функции, получающей jsx и возвращающей строку. */
elementToString: createToken<RenderToString>('page/element-to-string'),

/** Токен функции, которая вернёт данные для ответа. */
formatResponse: createToken<PageResponseFormatter>('page/format-response'),
},
},
},
Expand Down

0 comments on commit 610a46d

Please sign in to comment.