@ololoepepe/controllers 0.2.38 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,54 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.3.0] - 2026-08-28
11
+
12
+ ### Changed
13
+
14
+ - Rewritten in TypeScript. The package now ships compiled ESM plus type declarations
15
+ under `dist/node/` instead of raw sources, so consumers get types without a separate
16
+ `@types/…` package. Runtime behaviour is unchanged.
17
+ - The request and the response are type parameters defaulting to Express's `Request`
18
+ and `Response`, so callbacks need no annotation on Express and the controllers still
19
+ accept any object of the right shape elsewhere.
20
+ - `stringController` now requires its callback to return a `string` or `undefined`.
21
+ Returning an object used to compile and made Express send JSON from a controller
22
+ whose whole purpose is text.
23
+ - The test suite drives a real Express app over real HTTP instead of asserting on stub
24
+ objects, and covers what was previously untested: failures reaching the error
25
+ middleware, a promise result being awaited, and `stringController` at all — its tests
26
+ existed but were never registered with the runner, and their assertions were wrong.
27
+ - Migrated from mocha and chai to the built-in `node:test` runner.
28
+ - ESLint config replaced with `@ololoepepe/eslint-config-typescript` on the ESLint 10
29
+ flat format, and the code style violations it surfaced were fixed.
30
+ - CI image bumped to `node:24-alpine`; the pipeline now also runs `typecheck` and
31
+ `build`.
32
+ - Dependencies updated.
33
+
34
+ ### Added
35
+
36
+ - `engines` field: Node.js >= 24.
37
+ - `exports` map, `sideEffects: false`, and per-target `package.json` in the build
38
+ output that remaps `#src/*.ts` to the compiled files.
39
+ - `npm run build` and `npm run typecheck`.
40
+ - Exported types: `Controller`, `ControllerCallback`, `ControllerRequest`,
41
+ `JsonResponse`, `NextFunction`, `NoContentResponse`, `StringResponse`.
42
+ - Full README, and this changelog.
43
+
44
+ ### Removed
45
+
46
+ - The `main` field, replaced by the `exports` map. Deep imports into the package are
47
+ no longer possible; import the package root.
48
+ - `body-parser`, `chai`, `chai-http` and `mocha`, along with `.mocharc.yml` and the
49
+ `.ncurc.yml` that existed to hold chai and ESLint back.
50
+ - `.npmignore`, replaced by the `files` field.
51
+ - The runtime check for a non-string request method in the status code helper — the
52
+ type says `string`, and the only caller is Express, which always sets it.
53
+ - The undocumented fallback in `noContentController` where an explicit `statusCode` of
54
+ `0` selected the code by request method instead. `0` is not a status code.
package/README.md CHANGED
@@ -1 +1,182 @@
1
- # Common Express controllers library
1
+ # @ololoepepe/controllers
2
+
3
+ Express route handlers built from plain functions.
4
+
5
+ You write a function that takes the request and returns the data. The controller
6
+ sends that data, picks the status code from the HTTP method, and routes any
7
+ failure to your error middleware. What disappears from every route is the
8
+ `try`/`catch` around the handler, the `next(error)` inside it, and the decision
9
+ of whether this particular route answers with 200 or 201.
10
+
11
+ ## Installation
12
+
13
+ ```sh
14
+ npm install @ololoepepe/controllers
15
+ ```
16
+
17
+ Requires Node.js >= 24. Written in TypeScript — the declarations ship with the
18
+ package, so there is no `@types/…` to install.
19
+
20
+ ## Usage
21
+
22
+ ```ts
23
+ import express, {type Request} from 'express';
24
+ import {jsonController, noContentController, stringController} from '@ololoepepe/controllers';
25
+
26
+ const app = express();
27
+
28
+ app.use(express.json());
29
+
30
+ app.get('/users', jsonController(() => listUsers()));
31
+ app.post('/users', jsonController(request => createUser(request.body)));
32
+ app.delete('/users/:id', noContentController((request: Request<{id: string}>) => deleteUser(request.params.id)));
33
+ app.get('/health', stringController(() => 'ok'));
34
+
35
+ app.use(errorHandler);
36
+ ```
37
+
38
+ `GET /users` answers `200` with the array as JSON. `POST /users` answers `201`
39
+ with the created user. `DELETE /users/:id` answers `204` with an empty body. If
40
+ `createUser` throws or rejects, `errorHandler` gets the error and the client
41
+ never sees a hung request.
42
+
43
+ The callbacks are mostly unannotated and do not need to be: `request` and
44
+ `response` are Express's own `Request` and `Response` by default. The one
45
+ annotation above is about route parameters — see
46
+ [Route parameters](#route-parameters).
47
+
48
+ ## The three controllers
49
+
50
+ Each one takes a callback and returns an Express handler. The callback receives
51
+ the request and the response, and may return a promise — the controller waits
52
+ for it.
53
+
54
+ ### `jsonController(callback, statusCode?)`
55
+
56
+ Sends the callback's result as JSON. `undefined` is sent as `{}`; `null` is sent
57
+ as `null`, since only `undefined` stands for "nothing to send".
58
+
59
+ ```ts
60
+ app.get('/settings', jsonController(async () => loadSettings()));
61
+ ```
62
+
63
+ ### `stringController(callback, statusCode?)`
64
+
65
+ Sends the callback's result as text. The callback must return a `string` or
66
+ `undefined`; `undefined` is sent as an empty string.
67
+
68
+ ```ts
69
+ app.get('/robots.txt', stringController(() => 'User-agent: *\nDisallow:'));
70
+ ```
71
+
72
+ ### `noContentController(callback, statusCode = 204)`
73
+
74
+ Runs the callback and answers with a status code and an empty body. Whatever the
75
+ callback returns is discarded.
76
+
77
+ ```ts
78
+ app.post('/cache/flush', noContentController(async () => flushCache()));
79
+ ```
80
+
81
+ ## Status codes
82
+
83
+ `jsonController` and `stringController` choose the code from the request method
84
+ unless you pass one explicitly:
85
+
86
+ | Method | Status code |
87
+ | --- | --- |
88
+ | `POST`, `PUT` | `201` |
89
+ | everything else | `200` |
90
+
91
+ `noContentController` does not look at the method: it answers `204` unless told
92
+ otherwise.
93
+
94
+ To override, pass the code as the second argument:
95
+
96
+ ```ts
97
+ app.post('/jobs', jsonController(request => enqueue(request.body), 202));
98
+ ```
99
+
100
+ ## Errors
101
+
102
+ Anything the callback throws or rejects with is passed to `next`, so it reaches
103
+ the next error-handling middleware in the chain. So is a failure of the response
104
+ itself — including the `ERR_HTTP_HEADERS_SENT` you get when the callback has
105
+ already answered on its own. Nothing is swallowed, and nothing escapes as an
106
+ unhandled promise rejection.
107
+
108
+ The library does not format error responses; that is the job of your error
109
+ middleware. [`@ololoepepe/middlewares`](https://www.npmjs.com/package/@ololoepepe/middlewares)
110
+ ships one.
111
+
112
+ ## Route parameters
113
+
114
+ Express types `request.params` from the route string, but only when it can see
115
+ the handler and the route together. A controller is built before it reaches
116
+ `app.get`, so that link is broken and `request.params.id` falls back to Express's
117
+ own default, `string | string[]`.
118
+
119
+ Name the parameters on the callback to get them back:
120
+
121
+ ```ts
122
+ import type {Request} from 'express';
123
+
124
+ app.get('/users/:id/posts/:postId', jsonController((request: Request<{id: string; postId: string}>) => {
125
+ return loadPosts(request.params.id, request.params.postId);
126
+ }));
127
+ ```
128
+
129
+ Properties your own middleware puts on the request are a different matter: they
130
+ belong on Express's `Request` itself, through declaration merging, and then every
131
+ callback sees them with no annotation at all.
132
+
133
+ ```ts
134
+ declare global {
135
+ namespace Express {
136
+ interface Request {
137
+ currentUser: User;
138
+ }
139
+ }
140
+ }
141
+
142
+ app.get('/me', jsonController(request => request.currentUser));
143
+ ```
144
+
145
+ ## Types
146
+
147
+ The request and the response are type parameters, defaulting to Express's
148
+ `Request` and `Response`. On Express you rarely name them. Anywhere else, pass
149
+ your own shapes — the controllers only require what they actually use:
150
+
151
+ ```ts
152
+ import {jsonController, type ControllerRequest, type JsonResponse} from '@ololoepepe/controllers';
153
+
154
+ interface TenantRequest extends ControllerRequest {
155
+ tenantId: string;
156
+ }
157
+
158
+ const controller = jsonController<TenantRequest, JsonResponse>(request => loadTenant(request.tenantId));
159
+ ```
160
+
161
+ Exported types: `Controller`, `ControllerCallback`, `ControllerRequest`,
162
+ `JsonResponse`, `NextFunction`, `NoContentResponse`, `StringResponse`.
163
+
164
+ ## Development
165
+
166
+ | Command | What it does |
167
+ | --- | --- |
168
+ | `npm run lint` | ESLint over the whole repository. |
169
+ | `npm run typecheck` | `tsc` over `src`, `test`, `test-support` and `scripts`, no emit. |
170
+ | `npm test` | The `node:test` suite; Node runs the TypeScript sources directly. |
171
+ | `npm run build` | Compiles `src` into `dist/node/` — the ESM and `.d.ts` that get published. |
172
+
173
+ The tests drive a real Express app over real HTTP, so they assert what a client
174
+ sees rather than which methods were called on a stub.
175
+
176
+ Internal imports go through the `#src/*.ts` subpath map rather than relative
177
+ paths. `dist/node/` gets its own `package.json` remapping `#src/*.ts` to the
178
+ compiled files, which is what makes those imports resolve for consumers.
179
+
180
+ ## License
181
+
182
+ UNLICENSED — private package.
@@ -0,0 +1,3 @@
1
+ export { default as jsonController } from '#src/controllers/json-controller.ts';
2
+ export { default as noContentController } from '#src/controllers/no-content-controller.ts';
3
+ export { default as stringController } from '#src/controllers/string-controller.ts';
@@ -0,0 +1,3 @@
1
+ export { default as jsonController } from '#src/controllers/json-controller.ts';
2
+ export { default as noContentController } from '#src/controllers/no-content-controller.ts';
3
+ export { default as stringController } from '#src/controllers/string-controller.ts';
@@ -0,0 +1,17 @@
1
+ import type { Request, Response } from 'express';
2
+ import type { Controller, ControllerCallback, ControllerRequest, JsonResponse } from '#src/types.ts';
3
+ /**
4
+ * Создает контроллер, который вызывает `callback` на каждый запрос и отправляет его результат
5
+ * в виде JSON.
6
+ *
7
+ * Если `callback` вернул `undefined`, вместо него отправляется пустой объект `{}`. Если вернул
8
+ * промис — контроллер дожидается его результата.
9
+ *
10
+ * Код ответа по умолчанию — 201 для POST и PUT и 200 для остальных запросов.
11
+ *
12
+ * Ошибка `callback`, как и ошибка самой отправки ответа, передается следующему обработчику
13
+ * ошибок в цепочке.
14
+ * @param callback - функция, вызываемая на входящий запрос
15
+ * @param statusCode - код ответа, если нужен не тот, что выбирается по методу запроса
16
+ */
17
+ export default function jsonController<TRequest extends ControllerRequest = Request, TResponse extends JsonResponse = Response>(callback: ControllerCallback<TRequest, TResponse>, statusCode?: number): Controller<TRequest, TResponse>;
@@ -0,0 +1,28 @@
1
+ import selectStatusCode from '#src/lib/select-status-code.ts';
2
+ /**
3
+ * Создает контроллер, который вызывает `callback` на каждый запрос и отправляет его результат
4
+ * в виде JSON.
5
+ *
6
+ * Если `callback` вернул `undefined`, вместо него отправляется пустой объект `{}`. Если вернул
7
+ * промис — контроллер дожидается его результата.
8
+ *
9
+ * Код ответа по умолчанию — 201 для POST и PUT и 200 для остальных запросов.
10
+ *
11
+ * Ошибка `callback`, как и ошибка самой отправки ответа, передается следующему обработчику
12
+ * ошибок в цепочке.
13
+ * @param callback - функция, вызываемая на входящий запрос
14
+ * @param statusCode - код ответа, если нужен не тот, что выбирается по методу запроса
15
+ */
16
+ export default function jsonController(callback, statusCode) {
17
+ return async (request, response, next) => {
18
+ try {
19
+ const result = await callback(request, response);
20
+ // Пустым объектом подменяется только `undefined`: `null` — осмысленное тело ответа
21
+ const body = (result === undefined) ? {} : result;
22
+ response.status(statusCode ?? selectStatusCode(request.method)).json(body);
23
+ }
24
+ catch (error) {
25
+ next(error);
26
+ }
27
+ };
28
+ }
@@ -0,0 +1,13 @@
1
+ import type { Request, Response } from 'express';
2
+ import type { Controller, ControllerCallback, ControllerRequest, NoContentResponse } from '#src/types.ts';
3
+ /**
4
+ * Создает контроллер, который вызывает `callback` на каждый запрос и отправляет один только код
5
+ * ответа. Тело ответа остается пустым, что бы `callback` ни вернул. Если он вернул промис —
6
+ * контроллер дожидается его результата.
7
+ *
8
+ * Ошибка `callback`, как и ошибка самой отправки ответа, передается следующему обработчику
9
+ * ошибок в цепочке.
10
+ * @param callback - функция, вызываемая на входящий запрос
11
+ * @param statusCode - код ответа (по умолчанию 204)
12
+ */
13
+ export default function noContentController<TRequest extends ControllerRequest = Request, TResponse extends NoContentResponse = Response>(callback: ControllerCallback<TRequest, TResponse>, statusCode?: number): Controller<TRequest, TResponse>;
@@ -0,0 +1,22 @@
1
+ const NO_CONTENT = 204;
2
+ /**
3
+ * Создает контроллер, который вызывает `callback` на каждый запрос и отправляет один только код
4
+ * ответа. Тело ответа остается пустым, что бы `callback` ни вернул. Если он вернул промис —
5
+ * контроллер дожидается его результата.
6
+ *
7
+ * Ошибка `callback`, как и ошибка самой отправки ответа, передается следующему обработчику
8
+ * ошибок в цепочке.
9
+ * @param callback - функция, вызываемая на входящий запрос
10
+ * @param statusCode - код ответа (по умолчанию 204)
11
+ */
12
+ export default function noContentController(callback, statusCode = NO_CONTENT) {
13
+ return async (request, response, next) => {
14
+ try {
15
+ await callback(request, response);
16
+ response.sendStatus(statusCode);
17
+ }
18
+ catch (error) {
19
+ next(error);
20
+ }
21
+ };
22
+ }
@@ -0,0 +1,17 @@
1
+ import type { Request, Response } from 'express';
2
+ import type { Controller, ControllerCallback, ControllerRequest, StringResponse } from '#src/types.ts';
3
+ /**
4
+ * Создает контроллер, который вызывает `callback` на каждый запрос и отправляет его результат
5
+ * в виде строки.
6
+ *
7
+ * Если `callback` вернул `undefined`, отправляется пустая строка. Если вернул промис —
8
+ * контроллер дожидается его результата.
9
+ *
10
+ * Код ответа по умолчанию — 201 для POST и PUT и 200 для остальных запросов.
11
+ *
12
+ * Ошибка `callback`, как и ошибка самой отправки ответа, передается следующему обработчику
13
+ * ошибок в цепочке.
14
+ * @param callback - функция, вызываемая на входящий запрос
15
+ * @param statusCode - код ответа, если нужен не тот, что выбирается по методу запроса
16
+ */
17
+ export default function stringController<TRequest extends ControllerRequest = Request, TResponse extends StringResponse = Response>(callback: ControllerCallback<TRequest, TResponse, string | undefined>, statusCode?: number): Controller<TRequest, TResponse>;
@@ -0,0 +1,26 @@
1
+ import selectStatusCode from '#src/lib/select-status-code.ts';
2
+ /**
3
+ * Создает контроллер, который вызывает `callback` на каждый запрос и отправляет его результат
4
+ * в виде строки.
5
+ *
6
+ * Если `callback` вернул `undefined`, отправляется пустая строка. Если вернул промис —
7
+ * контроллер дожидается его результата.
8
+ *
9
+ * Код ответа по умолчанию — 201 для POST и PUT и 200 для остальных запросов.
10
+ *
11
+ * Ошибка `callback`, как и ошибка самой отправки ответа, передается следующему обработчику
12
+ * ошибок в цепочке.
13
+ * @param callback - функция, вызываемая на входящий запрос
14
+ * @param statusCode - код ответа, если нужен не тот, что выбирается по методу запроса
15
+ */
16
+ export default function stringController(callback, statusCode) {
17
+ return async (request, response, next) => {
18
+ try {
19
+ const result = await callback(request, response);
20
+ response.status(statusCode ?? selectStatusCode(request.method)).send(result ?? '');
21
+ }
22
+ catch (error) {
23
+ next(error);
24
+ }
25
+ };
26
+ }
@@ -0,0 +1,2 @@
1
+ export { jsonController, noContentController, stringController } from '#src/controllers/index.ts';
2
+ export type { Controller, ControllerCallback, ControllerRequest, JsonResponse, NextFunction, NoContentResponse, StringResponse } from '#src/types.ts';
@@ -0,0 +1 @@
1
+ export { jsonController, noContentController, stringController } from '#src/controllers/index.ts';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Возвращает код ответа, подходящий методу запроса: 201 для POST и PUT, 200 для остальных.
3
+ * Регистр не имеет значения.
4
+ * @param method - метод HTTP-запроса
5
+ */
6
+ export default function selectStatusCode(method: string): number;
@@ -0,0 +1,12 @@
1
+ const CREATED = 201;
2
+ const OK = 200;
3
+ // Методы, для которых успешный ответ означает, что что-то было создано
4
+ const CREATING_METHODS = new Set(['POST', 'PUT']);
5
+ /**
6
+ * Возвращает код ответа, подходящий методу запроса: 201 для POST и PUT, 200 для остальных.
7
+ * Регистр не имеет значения.
8
+ * @param method - метод HTTP-запроса
9
+ */
10
+ export default function selectStatusCode(method) {
11
+ return CREATING_METHODS.has(method.toUpperCase()) ? CREATED : OK;
12
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "imports": {
3
+ "#src/*.ts": "./*.js"
4
+ },
5
+ "type": "module"
6
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Общие типы контроллеров.
3
+ *
4
+ * Запрос и ответ везде остаются параметрами типа. По умолчанию это `Request` и `Response` из
5
+ * Express, поэтому в обычном случае аннотировать ничего не нужно. Подставить можно любые объекты
6
+ * подходящей формы — из другого фреймворка или из теста.
7
+ */
8
+ /** Продолжение цепочки Express. Аргумент — ошибка, если она произошла. */
9
+ export type NextFunction = (error?: unknown) => void;
10
+ /** Минимальная часть запроса, которая нужна контроллерам: по методу выбирается код ответа. */
11
+ export interface ControllerRequest {
12
+ method: string;
13
+ }
14
+ /** Ответ, умеющий отдать тело в виде JSON. */
15
+ export interface JsonResponse {
16
+ status: (statusCode: number) => {
17
+ json: (body: unknown) => unknown;
18
+ };
19
+ }
20
+ /** Ответ, умеющий отдать тело в виде строки. */
21
+ export interface StringResponse {
22
+ status: (statusCode: number) => {
23
+ send: (body: string) => unknown;
24
+ };
25
+ }
26
+ /** Ответ, умеющий отдать один только код без тела. */
27
+ export interface NoContentResponse {
28
+ sendStatus: (statusCode: number) => unknown;
29
+ }
30
+ /** Готовый обработчик Express — то, что возвращает каждый контроллер. */
31
+ export type Controller<TRequest, TResponse> = (request: TRequest, response: TResponse, next: NextFunction) => Promise<void>;
32
+ /** Функция, которую контроллер вызывает на каждый входящий запрос. */
33
+ export type ControllerCallback<TRequest, TResponse, TResult = unknown> = (request: TRequest, response: TResponse) => Promise<TResult> | TResult;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Общие типы контроллеров.
3
+ *
4
+ * Запрос и ответ везде остаются параметрами типа. По умолчанию это `Request` и `Response` из
5
+ * Express, поэтому в обычном случае аннотировать ничего не нужно. Подставить можно любые объекты
6
+ * подходящей формы — из другого фреймворка или из теста.
7
+ */
8
+ export {};
package/package.json CHANGED
@@ -1,23 +1,39 @@
1
1
  {
2
2
  "name": "@ololoepepe/controllers",
3
- "version": "0.2.38",
3
+ "version": "0.3.0",
4
4
  "description": "Common Express controllers library",
5
- "main": "src/index.js",
5
+ "type": "module",
6
6
  "imports": {
7
- "#src/*.js": "./src/*.js"
7
+ "#src/*.ts": "./src/*.ts",
8
+ "#test-support/*.ts": "./test-support/*.ts"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/node/index.d.ts",
13
+ "default": "./dist/node/index.js"
14
+ },
15
+ "./package.json": "./package.json"
16
+ },
17
+ "sideEffects": false,
18
+ "engines": {
19
+ "node": ">=24"
8
20
  },
9
- "type": "module",
10
21
  "scripts": {
11
- "lint": "eslint ./src",
12
- "test": "mocha ./test/*"
22
+ "build": "npm run build:node",
23
+ "build:node": "node scripts/build-node.ts",
24
+ "lint": "eslint .",
25
+ "prepack": "npm run build",
26
+ "test": "node --test",
27
+ "typecheck": "tsc"
13
28
  },
14
29
  "publishConfig": {
15
30
  "registry": "https://registry.npmjs.com"
16
31
  },
17
32
  "files": [
18
- "src",
33
+ "dist",
19
34
  "package.json",
20
- "README.md"
35
+ "README.md",
36
+ "CHANGELOG.md"
21
37
  ],
22
38
  "repository": {
23
39
  "type": "git",
@@ -29,13 +45,14 @@
29
45
  "url": "https://gitlab.void-walkers.com/libs/node.js/controllers/issues"
30
46
  },
31
47
  "homepage": "https://gitlab.void-walkers.com/libs/node.js/controllers#README",
48
+ "dependencies": {
49
+ "@types/express": "^5.0.6"
50
+ },
32
51
  "devDependencies": {
33
- "@ololoepepe/eslint-config": "^0.0.20",
34
- "body-parser": "^2.2.0",
35
- "chai": "^4.4.1",
36
- "chai-http": "^4.4.0",
37
- "eslint": "^8.57.0",
38
- "express": "^5.1.0",
39
- "mocha": "^11.4.0"
52
+ "@ololoepepe/eslint-config-typescript": "^0.2.0",
53
+ "@types/node": "^26.4.0",
54
+ "eslint": "^10.9.1",
55
+ "express": "^5.2.1",
56
+ "typescript": "^6.0.3"
40
57
  }
41
58
  }
@@ -1,5 +0,0 @@
1
- import jsonController from './json-controller.js';
2
- import noContentController from './no-content-controller.js';
3
- import stringController from './string-controller.js';
4
-
5
- export {jsonController, noContentController, stringController};
@@ -1,32 +0,0 @@
1
- import {selectStatusCode} from '#src/lib/helper.js';
2
-
3
- /**
4
- * Создает функцию-контроллер, вызывающую переданный callback при запросах
5
- * и отправляющую результат ее выполнения в виде JSON.
6
- *
7
- * Если функция-callback возвращает undefined, вместо этого значения подставляется пустой объект {}.
8
- *
9
- * Если функция-callback возвращает экземпляр Promise, контроллер будет ожидать его результат.
10
- *
11
- * По умолчанию HTTP-код ответа (statusCode) устанавливается в 201, если запрос POST или PUT,
12
- * и в 200 в остальных случаях.
13
- *
14
- * При ошибке вызывается следующий middleware или контроллер в цепочке.
15
- *
16
- * @param {function} callback - функция, вызываемая для входящих запросов
17
- * @param {number} [statusCode] - HTTP-код ответа (по умолчанию 201 для POST и PUT и 200 для остальных запросов)
18
- *
19
- * @return {function} - функция-контроллер
20
- */
21
-
22
- export default (callback, statusCode) => async (req, res, next) => {
23
- try {
24
- const result = await callback(req, res);
25
-
26
- const json = (result === undefined) ? {} : result;
27
-
28
- res.status(statusCode || selectStatusCode(req.method)).json(json);
29
- } catch (err) {
30
- next(err);
31
- }
32
- };
@@ -1,26 +0,0 @@
1
- import {selectStatusCode} from '#src/lib/helper.js';
2
-
3
- /**
4
- * Создает функцию-контроллер, вызывающую переданный callback при запросах
5
- * и устанавливающую код ответа после ее выполнения. Тело ответа оставляется пустым.
6
- * Если функция-callback возвращает экземпляр Promise, контроллер будет ожидать его результат.
7
- *
8
- * По умолчанию HTTP-код ответа (statusCode) устанавливается в 204.
9
- *
10
- * При ошибке вызывается следующий middleware или контроллер в цепочке.
11
- *
12
- * @param {function} callback - функция, вызываемая для входящих запросов
13
- * @param {number} [statusCode=204] - HTTP-код ответа
14
- *
15
- * @return {function} - функция-контроллер
16
- */
17
-
18
- export default (callback, statusCode = 204) => async (req, res, next) => {
19
- try {
20
- await callback(req, res);
21
-
22
- res.sendStatus(statusCode || selectStatusCode(req.method));
23
- } catch (err) {
24
- next(err);
25
- }
26
- };
@@ -1,32 +0,0 @@
1
- import {selectStatusCode} from '#src/lib/helper.js';
2
-
3
- /**
4
- * Создает функцию-контроллер, вызывающую переданный callback при запросах
5
- * и отправляющую результат ее выполнения в виде строки.
6
- *
7
- * Если функция-callback возвращает undefined, вместо этого значения подставляется пустая строка.
8
- *
9
- * Если функция-callback возвращает экземпляр Promise, контроллер будет ожидать его результат.
10
- *
11
- * По умолчанию HTTP-код ответа (statusCode) устанавливается в 201, если запрос POST или PUT,
12
- * и в 200 в остальных случаях.
13
- *
14
- * При ошибке вызывается следующий middleware или контроллер в цепочке.
15
- *
16
- * @param {function} callback - функция, вызываемая для входящих запросов
17
- * @param {number} [statusCode] - HTTP-код ответа (по умолчанию 201 для POST и PUT и 200 для остальных запросов)
18
- *
19
- * @return {function} - функция-контроллер
20
- */
21
-
22
- export default (callback, statusCode) => async (req, res, next) => {
23
- try {
24
- const result = await callback(req, res);
25
-
26
- const string = (result === undefined) ? '' : result;
27
-
28
- res.status(statusCode || selectStatusCode(req.method)).send(string);
29
- } catch (err) {
30
- next(err);
31
- }
32
- };
package/src/index.js DELETED
@@ -1 +0,0 @@
1
- export {jsonController, noContentController, stringController} from './controllers/index.js';
package/src/lib/helper.js DELETED
@@ -1,26 +0,0 @@
1
- /**
2
- * Возвращает HTTP-код ответа в зависимости от типа запроса:
3
- * 201, если запрос POST или PUT, и в 200 в остальных случаях.
4
- *
5
- * Не зависит от регистра.
6
- *
7
- * @param {string} method - тип HTTP-запроса
8
- *
9
- * @return {number} - HTTP-код ответа
10
- */
11
-
12
- export function selectStatusCode(method) {
13
- if (typeof method === 'string') {
14
- method = method.toUpperCase();
15
- }
16
-
17
- switch (method) {
18
- case 'POST':
19
- case 'PUT':
20
- return 201;
21
- case 'GET':
22
- case 'DELETE':
23
- default:
24
- return 200;
25
- }
26
- }