@antelopejs/interface-api-util 0.2.0 → 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/README.md +16 -12
- package/dist/index.d.ts +5 -3
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/rate-limit.js.map +1 -1
- package/dist/tests/index.test.js +20 -2
- package/dist/tests/index.test.js.map +1 -1
- package/dist/tests/rate-limit.test.js.map +1 -1
- package/docs/1.introduction.md +81 -48
- package/package.json +14 -8
- package/skills/api-util-interface/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@antelopejs/interface-api-util`
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
|
-
<a href="https://www.npmjs.com/package/@antelopejs/interface-api-util"><img alt="npm" src="https://img.shields.io/npm/v/@antelopejs/interface-api-util?style=for-the-badge&labelColor=000000&color=000000"></a>
|
|
5
|
-
<a href="./LICENSE"><img alt="License" src="https://img.shields.io/npm/l/@antelopejs/interface-api-util?style=for-the-badge&labelColor=000000&color=000000"></a>
|
|
6
|
-
<a href="https://discord.gg/
|
|
7
|
-
<a href="https://interfaces.antelopejs.com/docs/api-util"><img alt="Docs" src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000"></a>
|
|
4
|
+
<a href="https://www.npmjs.com/package/@antelopejs/interface-api-util"><img data-illustration alt="npm" src="https://img.shields.io/npm/v/@antelopejs/interface-api-util?style=for-the-badge&labelColor=000000&color=000000"></a>
|
|
5
|
+
<a href="./LICENSE"><img data-illustration alt="License" src="https://img.shields.io/npm/l/@antelopejs/interface-api-util?style=for-the-badge&labelColor=000000&color=000000"></a>
|
|
6
|
+
<a href="https://discord.gg/g4pFt6eXqu"><img data-illustration alt="Discord" src="https://img.shields.io/badge/Discord-18181B?logo=discord&style=for-the-badge&color=000000"></a>
|
|
7
|
+
<a href="https://interfaces.antelopejs.com/docs/api-util"><img data-illustration alt="Docs" src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000"></a>
|
|
8
8
|
</div>
|
|
9
9
|
|
|
10
10
|
Request validation and rate limiting helpers for handlers written against [`@antelopejs/interface-api`](https://github.com/AntelopeJS/interface-api). Every failure becomes an `HTTPResult` error response.
|
|
11
11
|
|
|
12
|
+
Part of [AntelopeJS](https://github.com/AntelopeJS/antelopejs). Used by [AntelopeJS DMS](https://github.com/AntelopeJS/dms), the open-source back office for your PostgreSQL, MongoDB or RethinkDB database.
|
|
13
|
+
|
|
12
14
|
## What it offers
|
|
13
15
|
|
|
14
16
|
- `assert(condition, code, message)` throws an `HTTPResult` when the condition is falsy and narrows its type when it holds.
|
|
15
|
-
- `assertValidation(body, validator)` runs a synchronous validator, such as a Zod `parse`, and turns a thrown error into
|
|
17
|
+
- `assertValidation(body, validator)` runs a synchronous validator, such as a Zod `parse`, and turns a thrown error into an error response, `400` by default.
|
|
16
18
|
- `@RateLimit(limit, windowMs)` caps calls to a handler per client in a fixed window and answers `429` beyond it.
|
|
17
19
|
|
|
18
20
|
## Implementations
|
|
@@ -69,14 +71,16 @@ Place `@RateLimit` directly below the route decorator. Placed above it, `@RateLi
|
|
|
69
71
|
|
|
70
72
|
## Compatibility
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
The module declares these peer dependencies:
|
|
75
|
+
|
|
76
|
+
<!-- antelopejs-docs-compat:start -->
|
|
73
77
|
|
|
74
|
-
|
|
78
|
+
| Package | Supported | Tested with |
|
|
79
|
+
| ---------------------------- | ---------------- | ----------- |
|
|
80
|
+
| `@antelopejs/interface-api` | `>=0.3.0 <1.0.0` | `0.2.0` |
|
|
81
|
+
| `@antelopejs/interface-core` | `>=0.2.4 <1.0.0` | `0.4.0` |
|
|
75
82
|
|
|
76
|
-
|
|
77
|
-
| ---------------------------- | ----------------- |
|
|
78
|
-
| `@antelopejs/interface-api` | `>=0.0.15 <1.0.0` |
|
|
79
|
-
| `@antelopejs/interface-core` | `>=0.2.4 <1.0.0` |
|
|
83
|
+
<!-- antelopejs-docs-compat:end -->
|
|
80
84
|
|
|
81
85
|
## Contributing
|
|
82
86
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type HTTPBody } from "@antelopejs/interface-api";
|
|
1
2
|
export * from "./rate-limit";
|
|
2
3
|
/**
|
|
3
4
|
* Assert a condition is truthy, throwing an HTTPResult error if false.
|
|
@@ -21,14 +22,15 @@ export * from "./rate-limit";
|
|
|
21
22
|
* }
|
|
22
23
|
* ```
|
|
23
24
|
*/
|
|
24
|
-
export declare function assert
|
|
25
|
+
export declare function assert(condition: unknown, code: number, message: string): asserts condition;
|
|
25
26
|
/**
|
|
26
27
|
* Executes a synchronous validator on a body, converting thrown errors to HTTPResult.
|
|
27
28
|
* The validator should return a validated object on success and throw on failure.
|
|
28
29
|
* Promises are returned unchanged; asynchronous rejections are not converted.
|
|
29
30
|
*
|
|
30
31
|
* The error thrown by the validator may be altered by passing an error handler.
|
|
31
|
-
* The result of this error handler will be passed directly as the body of the HTTPResult
|
|
32
|
+
* The result of this error handler will be passed directly as the body of the HTTPResult:
|
|
33
|
+
* a string is sent as is, any other `HTTPBody` as JSON, and `undefined` as an empty text body.
|
|
32
34
|
* If no error handler is given, assertValidation will resort to calling the error's toString() method if possible.
|
|
33
35
|
*
|
|
34
36
|
* The validator receives the body at the type of the argument you pass (`Input`, inferred from `body`;
|
|
@@ -54,4 +56,4 @@ export declare function assert<T>(condition: T, code: number, message: string):
|
|
|
54
56
|
* const { name } = assertValidation(requestBody, schema.parse);
|
|
55
57
|
* ```
|
|
56
58
|
*/
|
|
57
|
-
export declare function assertValidation<T, Input = unknown>(body: Input, validator: (body: Input) => T, errorFunc?: (err: unknown) =>
|
|
59
|
+
export declare function assertValidation<T, Input = unknown>(body: Input, validator: (body: Input) => T, errorFunc?: (err: unknown) => HTTPBody | undefined, code?: number): T;
|
package/dist/index.js
CHANGED
|
@@ -51,7 +51,8 @@ function assert(condition, code, message) {
|
|
|
51
51
|
* Promises are returned unchanged; asynchronous rejections are not converted.
|
|
52
52
|
*
|
|
53
53
|
* The error thrown by the validator may be altered by passing an error handler.
|
|
54
|
-
* The result of this error handler will be passed directly as the body of the HTTPResult
|
|
54
|
+
* The result of this error handler will be passed directly as the body of the HTTPResult:
|
|
55
|
+
* a string is sent as is, any other `HTTPBody` as JSON, and `undefined` as an empty text body.
|
|
55
56
|
* If no error handler is given, assertValidation will resort to calling the error's toString() method if possible.
|
|
56
57
|
*
|
|
57
58
|
* The validator receives the body at the type of the argument you pass (`Input`, inferred from `body`;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AA0BA,wBAQC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AA0BA,wBAQC;AAmCD,4CAYC;AAjFD,6DAAsE;AAEtE,+CAA6B;AAE7B;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,SAAgB,MAAM,CACpB,SAAkB,EAClB,IAAY,EACZ,OAAe;IAEf,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,0BAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,SAAgB,gBAAgB,CAC9B,IAAW,EACX,SAA6B,EAC7B,SAAkD,EAClD,IAAI,GAAG,GAAG;IAEV,IAAI,CAAC;QACH,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,CAAU,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACpD,MAAM,IAAI,0BAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;AACH,CAAC"}
|
package/dist/rate-limit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"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"}
|
package/dist/tests/index.test.js
CHANGED
|
@@ -14,6 +14,7 @@ class RawPayload {
|
|
|
14
14
|
this.active = active;
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
+
const MALFORMED_BODY = { malformed: true };
|
|
17
18
|
const BAD_REQUEST_CODE = 400;
|
|
18
19
|
const UNPROCESSABLE_ENTITY_CODE = 422;
|
|
19
20
|
const ASSERTION_ERROR_MESSAGE = "Missing payload";
|
|
@@ -37,6 +38,12 @@ function mapValidationError() {
|
|
|
37
38
|
detail: VALIDATION_ERROR_MESSAGE,
|
|
38
39
|
};
|
|
39
40
|
}
|
|
41
|
+
function mapIssueList() {
|
|
42
|
+
return [{ path: ["name"], message: "bad" }];
|
|
43
|
+
}
|
|
44
|
+
function refuseSilently() {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
40
47
|
describe("API Util Interface", () => {
|
|
41
48
|
describe("assert", () => {
|
|
42
49
|
it("returns when the condition is truthy", () => {
|
|
@@ -61,15 +68,26 @@ describe("API Util Interface", () => {
|
|
|
61
68
|
node_assert_1.default.equal(byteCount, "antelope".length);
|
|
62
69
|
});
|
|
63
70
|
it("throws HTTPResult with default code and serialized error message", () => {
|
|
64
|
-
const httpError = (0, capture_http_result_1.captureHTTPResult)(() => (0, __1.assertValidation)(
|
|
71
|
+
const httpError = (0, capture_http_result_1.captureHTTPResult)(() => (0, __1.assertValidation)(MALFORMED_BODY, parsePayload));
|
|
65
72
|
node_assert_1.default.equal(httpError.getStatus(), BAD_REQUEST_CODE);
|
|
66
73
|
node_assert_1.default.equal(httpError.getBody(), `Error: ${VALIDATION_ERROR_MESSAGE}`);
|
|
67
74
|
});
|
|
68
75
|
it("applies custom error mapper and status code", () => {
|
|
69
|
-
const httpError = (0, capture_http_result_1.captureHTTPResult)(() => (0, __1.assertValidation)(
|
|
76
|
+
const httpError = (0, capture_http_result_1.captureHTTPResult)(() => (0, __1.assertValidation)(MALFORMED_BODY, parsePayload, mapValidationError, UNPROCESSABLE_ENTITY_CODE));
|
|
70
77
|
node_assert_1.default.equal(httpError.getStatus(), UNPROCESSABLE_ENTITY_CODE);
|
|
71
78
|
node_assert_1.default.equal(httpError.getBody(), JSON.stringify(mapValidationError()));
|
|
72
79
|
});
|
|
80
|
+
it("answers a JSON array from the error handler as JSON text", () => {
|
|
81
|
+
const httpError = (0, capture_http_result_1.captureHTTPResult)(() => (0, __1.assertValidation)(MALFORMED_BODY, parsePayload, mapIssueList));
|
|
82
|
+
node_assert_1.default.equal(httpError.getBody(), '[{"path":["name"],"message":"bad"}]');
|
|
83
|
+
node_assert_1.default.equal(httpError.getContentType(), "application/json");
|
|
84
|
+
});
|
|
85
|
+
it("answers an empty text body when the error handler returns undefined", () => {
|
|
86
|
+
const httpError = (0, capture_http_result_1.captureHTTPResult)(() => (0, __1.assertValidation)(MALFORMED_BODY, parsePayload, refuseSilently));
|
|
87
|
+
node_assert_1.default.equal(httpError.getStatus(), BAD_REQUEST_CODE);
|
|
88
|
+
node_assert_1.default.equal(httpError.getBody(), "");
|
|
89
|
+
node_assert_1.default.equal(httpError.getContentType(), "text/plain");
|
|
90
|
+
});
|
|
73
91
|
});
|
|
74
92
|
});
|
|
75
93
|
//# sourceMappingURL=index.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/tests/index.test.ts"],"names":[],"mappings":";;;;;AAAA,8DAAiC;AACjC,0BAAiE;AACjE,+DAA0D;AAE1D,MAAM,UAAU;IAEH;IACA;IAFX,YACW,IAAY,EACZ,MAAe;QADf,SAAI,GAAJ,IAAI,CAAQ;QACZ,WAAM,GAAN,MAAM,CAAS;IACvB,CAAC;CACL;
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/tests/index.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.test.js","sourceRoot":"","sources":["../../src/tests/rate-limit.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,8DAAiC;AACjC,yCAA4D;AAC5D,uCAAkC;AAClC,+DAAyD;AACzD,6DASmC;AAEnC,8CAMuB;AACvB,+DAA0D;AAE1D,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAC9B,MAAM,KAAK,GAAG,CAAC,CAAC;AAChB,MAAM,SAAS,GAAG,MAAM,CAAC;AACzB,MAAM,kBAAkB,GAAG,aAAa,CAAC;AACzC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AACnD,MAAM,0BAA0B,GAAG,uBAAuB,CAAC;AAC3D,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"rate-limit.test.js","sourceRoot":"","sources":["../../src/tests/rate-limit.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,8DAAiC;AACjC,yCAA4D;AAC5D,uCAAkC;AAClC,+DAAyD;AACzD,6DASmC;AAEnC,8CAMuB;AACvB,+DAA0D;AAE1D,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAC9B,MAAM,KAAK,GAAG,CAAC,CAAC;AAChB,MAAM,SAAS,GAAG,MAAM,CAAC;AACzB,MAAM,kBAAkB,GAAG,aAAa,CAAC;AACzC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AACnD,MAAM,0BAA0B,GAAG,uBAAuB,CAAC;AAC3D,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAInD,SAAS,WAAW,CAAC,aAAsB;IACzC,MAAM,MAAM,GAAG,IAAI,iBAAM,EAAE,CAAC;IAC5B,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,eAAe,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;IACzE,MAAM,UAAU,GAAG,IAAI,2BAAe,CAAC,MAAM,CAAC,CAAC;IAC/C,OAAO;QACL,UAAU;QACV,WAAW,EAAE,IAAI,0BAAc,CAAC,UAAU,CAAC;QAC3C,GAAG,EAAE,IAAI,GAAG,CAAC,mBAAmB,CAAC;QACjC,eAAe,EAAE,EAAE;QACnB,QAAQ,EAAE,IAAI,0BAAU,EAAE;KAC3B,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,UAA2B;IACpD,MAAM,UAAU,GAAG,MAAM,CAAC,wBAAwB,CAChD,UAAU,CAAC,SAAS,EACpB,SAAS,CACV,CAAC;IACF,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,aAAa,CAAC,UAA2B;IAChD,MAAM,IAAI,GAAG,IAAA,4BAAW,EAAC,UAAU,EAAE,8BAAc,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC;IAC3D,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,eAAe;IACtB,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;YAC9D,MAAM,KAAK,GAAgB,IAAI,GAAG,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,IAAA,sBAAS,EAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YACzD,MAAM,MAAM,GAAG,IAAA,sBAAS,EAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;YAC3D,MAAM,KAAK,GAAG,IAAA,sBAAS,EAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;YAE1D,qBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAClC,qBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YACjC,qBAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YACnC,qBAAM,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YAClC,qBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACnC,qBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC5D,MAAM,KAAK,GAAgB,IAAI,GAAG,EAAE,CAAC;YACrC,IAAA,sBAAS,EAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;YAC9C,MAAM,QAAQ,GAAG,IAAA,sBAAS,EAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;YAE/D,qBAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,GAAG,GAAG,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;YAC/C,MAAM,KAAK,GAAgB,IAAI,GAAG,EAAE,CAAC;YACrC,IAAA,sBAAS,EAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YAC3C,IAAA,sBAAS,EAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YAC3C,MAAM,MAAM,GAAG,IAAA,sBAAS,EAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YAC1D,MAAM,UAAU,GAAG,IAAA,sBAAS,EAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC;YAE1E,qBAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACpC,qBAAM,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YACvC,qBAAM,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;YACvC,MAAM,KAAK,GAAgB,IAAI,GAAG,EAAE,CAAC;YACrC,IAAA,sBAAS,EAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YAC3C,IAAA,sBAAS,EAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YAC3C,MAAM,QAAQ,GAAG,IAAA,sBAAS,EAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YAE5D,qBAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YACrC,qBAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;YAC/D,MAAM,KAAK,GAAgB,IAAI,GAAG,EAAE,CAAC;YACrC,IAAA,sBAAS,EAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YAC7C,IAAA,sBAAS,EAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;YAEvD,IAAA,yBAAY,EAAC,KAAK,EAAE,SAAS,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC;YAE9C,qBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;YACtC,qBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,qBAAqB;IAC5B,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;QAC1B,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,OAAO,GAAqB,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;YAC1D,qBAAM,CAAC,KAAK,CAAC,IAAA,uBAAU,EAAC,WAAW,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACrC,qBAAM,CAAC,KAAK,CAAC,IAAA,uBAAU,EAAC,WAAW,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,qBAAM,CAAC,KAAK,CAAC,IAAA,uBAAU,EAAC,WAAW,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;YAClE,MAAM,OAAO,GAAqB,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;YAC3D,qBAAM,CAAC,KAAK,CAAC,IAAA,uBAAU,EAAC,WAAW,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC;QACvE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB;IACxB,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;YACpE,MAAM,OAAQ,SAAQ,IAAA,0BAAU,EAAC,kBAAkB,CAAC;gBAClD,OAAO,KAAI,CAAC;aACb;YACD,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC;YAChC,IAAA,oCAAoB,EAAC,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC;YAC5D,IAAA,sBAAS,EAAC,KAAK,EAAE,SAAS,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;YAE1E,MAAM,IAAI,GAAG,IAAA,4BAAW,EAAC,OAAO,EAAE,8BAAc,CAAC,CAAC;YAClD,qBAAM,CAAC,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;YACnE,MAAM,OAAQ,SAAQ,IAAA,0BAAU,EAAC,qBAAqB,CAAC;gBAErD,OAAO;oBACL,OAAO,IAAI,0BAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBACnC,CAAC;aACF;YAHC;gBADC,IAAA,sBAAS,EAAC,KAAK,EAAE,SAAS,CAAC;;;;kDAG3B;YAEH,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;YACxC,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;YAEvC,qBAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC;YAC3C,qBAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC;YAE3C,MAAM,KAAK,GAAG,IAAA,uCAAiB,EAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;YACzD,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC;YACnC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC;YACvD,qBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,iBAAiB,CAAC,CAAC;YACnD,qBAAM,CAAC,KAAK,CAAC,OAAO,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAC7D,qBAAM,CAAC,KAAK,CAAC,OAAO,CAAC,0BAA0B,CAAC,EAAE,GAAG,CAAC,CAAC;YACvD,qBAAM,CAAC,EAAE,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;YAC1B,qBAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;YAC7D,MAAM,OAAQ,SAAQ,IAAA,0BAAU,EAAC,oBAAoB,CAAC;gBAEpD,OAAO,KAAI,CAAC;aACb;YADC;gBADC,IAAA,sBAAS,EAAC,KAAK,EAAE,SAAS,CAAC;;;;kDAChB;YAEd,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;YACxC,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;YAEvC,qBAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC;YAE3C,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;YAC9C,qBAAM,CAAC,KAAK,CAAC,OAAO,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAC7D,qBAAM,CAAC,KAAK,CAAC,OAAO,CAAC,0BAA0B,CAAC,EAAE,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;YACrE,qBAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;YAClE,MAAM,MAAO,SAAQ,IAAA,0BAAU,EAAC,kBAAkB,CAAC;gBAEjD,OAAO,KAAI,CAAC;aACb;YADC;gBADC,IAAA,sBAAS,EAAC,KAAK,EAAE,SAAS,CAAC;;;;iDAChB;YAEd,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;YAEvC,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC;YACjC,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC;YACjC,qBAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;YACzE,MAAM,UAAW,SAAQ,IAAA,0BAAU,EAAC,qBAAqB,CAAC;gBACxD,OAAO,KAAI,CAAC;aACb;YACD,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC;YACnC,MAAM,UAAU,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAEjD,IAAA,mBAAG,GAAE,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;YAEpC,qBAAM,CAAC,MAAM,CACX,GAAG,EAAE,CAAC,IAAA,sBAAS,EAAC,KAAK,EAAE,SAAS,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,EAC/D,kBAAkB,CACnB,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,eAAe,EAAE,CAAC;IAClB,qBAAqB,EAAE,CAAC;IACxB,iBAAiB,EAAE,CAAC;AACtB,CAAC,CAAC,CAAC"}
|
package/docs/1.introduction.md
CHANGED
|
@@ -1,32 +1,36 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Validate and throttle API requests
|
|
3
|
+
description: Reference for assert, assertValidation, and the RateLimit decorator, which turn failed checks and excess requests into HTTPResult error responses.
|
|
4
|
+
mode: reference
|
|
5
|
+
---
|
|
2
6
|
|
|
3
7
|
## Overview
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
`@antelopejs/interface-api-util` holds three helpers for handlers written against `@antelopejs/interface-api`. `assert` checks a condition. `assertValidation` runs an input validator. The `@RateLimit` decorator limits how often a handler runs. Each one reports a failure by throwing an `HTTPResult` from `@antelopejs/interface-api`.
|
|
6
10
|
|
|
7
11
|
## Choose a guard
|
|
8
12
|
|
|
9
|
-
| Task | Use | Failure behavior
|
|
10
|
-
| -------------------------------- | --------------------------------------- |
|
|
11
|
-
| Require a resource or permission | [`assert`](#assert) | A falsy condition throws the status and message you supply.
|
|
12
|
-
| Parse an untrusted request body | [`assertValidation`](#assertvalidation) |
|
|
13
|
-
| Limit repeated calls | [`RateLimit`](#ratelimit) |
|
|
13
|
+
| Task | Use | Failure behavior |
|
|
14
|
+
| -------------------------------- | --------------------------------------- | ---------------------------------------------------------------------------------------- |
|
|
15
|
+
| Require a resource or permission | [`assert`](#assert) | A falsy condition throws the status and message you supply. |
|
|
16
|
+
| Parse an untrusted request body | [`assertValidation`](#assertvalidation) | An error thrown by a synchronous validator becomes an HTTP error, status 400 by default. |
|
|
17
|
+
| Limit repeated calls | [`RateLimit`](#ratelimit) | A request above the fixed-window limit receives 429 before the handler runs. |
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
Each helper covers one check. A rate limit does not authenticate a caller, and a TypeScript annotation on a body does not validate the incoming JSON.
|
|
16
20
|
|
|
17
|
-
## Getting
|
|
21
|
+
## Getting started
|
|
18
22
|
|
|
19
|
-
Install the package in your
|
|
23
|
+
Install the package in your module:
|
|
20
24
|
|
|
21
25
|
```bash
|
|
22
26
|
pnpm add @antelopejs/interface-api-util
|
|
23
27
|
```
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
The examples below use the helpers in an AntelopeJS API controller. `findUser`, `findPost`, `removePost`, and `saveUser` stand for your application's data access code. This package does not export them. The Zod examples also need `zod` in your project.
|
|
26
30
|
|
|
27
31
|
## Reject a bad request
|
|
28
32
|
|
|
29
|
-
This endpoint
|
|
33
|
+
This endpoint needs a non-empty `name` query parameter. With the API module listening, `GET /greet?name=Ada` returns a greeting. `GET /greet` and `GET /greet?name=` return HTTP 400. The example needs no database and no validation library.
|
|
30
34
|
|
|
31
35
|
```ts docs-check
|
|
32
36
|
import { Controller, Get, Parameter } from "@antelopejs/interface-api";
|
|
@@ -45,49 +49,62 @@ class GreetingController extends Controller("/greet") {
|
|
|
45
49
|
}
|
|
46
50
|
```
|
|
47
51
|
|
|
48
|
-
|
|
52
|
+
`assert` fits a condition you can write as an expression. `assertValidation` fits a schema parser. `RateLimit` bounds repeated requests. The sections below describe each one.
|
|
49
53
|
|
|
50
54
|
## `assert`
|
|
51
55
|
|
|
52
|
-
|
|
56
|
+
`assert` checks whether a condition is truthy. If the condition is falsy, it throws an `HTTPResult` with the given status code and message.
|
|
53
57
|
|
|
54
58
|
```typescript
|
|
55
|
-
function assert
|
|
56
|
-
condition:
|
|
59
|
+
declare function assert(
|
|
60
|
+
condition: unknown,
|
|
57
61
|
code: number,
|
|
58
62
|
message: string,
|
|
59
63
|
): asserts condition;
|
|
60
64
|
```
|
|
61
65
|
|
|
62
|
-
| Parameter | Type
|
|
63
|
-
| ----------- |
|
|
64
|
-
| `condition` | `
|
|
65
|
-
| `code` | `number`
|
|
66
|
-
| `message` | `string`
|
|
66
|
+
| Parameter | Type | Description |
|
|
67
|
+
| ----------- | --------- | ------------------------------------------------ |
|
|
68
|
+
| `condition` | `unknown` | The value to check. A falsy value throws. |
|
|
69
|
+
| `code` | `number` | HTTP status code of the error response |
|
|
70
|
+
| `message` | `string` | Body of the error response, sent as `text/plain` |
|
|
67
71
|
|
|
68
|
-
The
|
|
72
|
+
The return type is an `asserts condition` signature, so after the call the compiler narrows `condition` to its truthy type.
|
|
69
73
|
|
|
70
74
|
### Check that a resource exists
|
|
71
75
|
|
|
76
|
+
`findUser` stands for your own data access code.
|
|
77
|
+
|
|
72
78
|
```typescript
|
|
73
79
|
import { assert } from "@antelopejs/interface-api-util";
|
|
74
80
|
import { HTTPResult } from "@antelopejs/interface-api";
|
|
75
81
|
|
|
82
|
+
declare function findUser(
|
|
83
|
+
id: string,
|
|
84
|
+
): Promise<{ id: string; name: string } | undefined>;
|
|
85
|
+
|
|
76
86
|
async function getUser(id: string) {
|
|
77
87
|
const user = await findUser(id);
|
|
78
88
|
assert(user, 404, "User not found");
|
|
79
89
|
|
|
80
|
-
//
|
|
90
|
+
// `user` is defined here
|
|
81
91
|
return new HTTPResult(200, user);
|
|
82
92
|
}
|
|
83
93
|
```
|
|
84
94
|
|
|
85
95
|
### Validate permissions
|
|
86
96
|
|
|
97
|
+
`findPost` and `removePost` stand for your own data access code.
|
|
98
|
+
|
|
87
99
|
```typescript
|
|
88
100
|
import { assert } from "@antelopejs/interface-api-util";
|
|
89
101
|
import { HTTPResult } from "@antelopejs/interface-api";
|
|
90
102
|
|
|
103
|
+
declare function findPost(
|
|
104
|
+
id: string,
|
|
105
|
+
): Promise<{ id: string; authorId: string } | undefined>;
|
|
106
|
+
declare function removePost(id: string): Promise<void>;
|
|
107
|
+
|
|
91
108
|
async function deletePost(postId: string, currentUserId: string) {
|
|
92
109
|
const post = await findPost(postId);
|
|
93
110
|
assert(post, 404, "Post not found");
|
|
@@ -104,25 +121,27 @@ async function deletePost(postId: string, currentUserId: string) {
|
|
|
104
121
|
|
|
105
122
|
## `assertValidation`
|
|
106
123
|
|
|
107
|
-
|
|
124
|
+
`assertValidation` runs a synchronous validator on an input value. If the validator throws, `assertValidation` catches the error and throws an `HTTPResult` instead. It does not await a promise. A validator that returns a promise gets the promise back unchanged, and a rejection of that promise is not converted. Use a synchronous validator such as Zod's `parse`, not `parseAsync`.
|
|
108
125
|
|
|
109
126
|
```typescript
|
|
110
|
-
|
|
127
|
+
import type { HTTPBody } from "@antelopejs/interface-api";
|
|
128
|
+
|
|
129
|
+
declare function assertValidation<T, Input = unknown>(
|
|
111
130
|
body: Input,
|
|
112
131
|
validator: (body: Input) => T,
|
|
113
|
-
errorFunc?: (err: unknown) =>
|
|
132
|
+
errorFunc?: (err: unknown) => HTTPBody | undefined,
|
|
114
133
|
code?: number,
|
|
115
134
|
): T;
|
|
116
135
|
```
|
|
117
136
|
|
|
118
|
-
| Parameter | Type
|
|
119
|
-
| ----------- |
|
|
120
|
-
| `body` | `Input`
|
|
121
|
-
| `validator` | `(body: Input) => T`
|
|
122
|
-
| `errorFunc` | `(err: unknown) =>
|
|
123
|
-
| `code` | `number`
|
|
137
|
+
| Parameter | Type | Default | Description |
|
|
138
|
+
| ----------- | ----------------------------------------- | ------- | ------------------------------------------------------- |
|
|
139
|
+
| `body` | `Input` | | The input value to validate |
|
|
140
|
+
| `validator` | `(body: Input) => T` | | A function that returns the validated value or throws |
|
|
141
|
+
| `errorFunc` | `(err: unknown) => HTTPBody \| undefined` | | Maps the thrown error to the body of the error response |
|
|
142
|
+
| `code` | `number` | `400` | HTTP status code of the error response |
|
|
124
143
|
|
|
125
|
-
`Input`
|
|
144
|
+
TypeScript infers `Input` from `body`, with no constraint. When you write only `assertValidation<T>(...)`, `Input` is `unknown`. The validator receives the body at type `Input`, so a body typed `Buffer` reaches a `(body: Buffer) => T` validator without a cast. A validator that accepts a wider type, such as Zod's `parse(data: unknown)`, always fits. A validator that accepts a narrower type than the body does not compile. For example, a `(body: string) => T` validator does not accept a `string | Buffer` body. The exception is a body typed `any`, which fits every validator, so the compiler then does not check the validator's parameter type. When the validator's parameter has no annotation, a literal body such as `"lit"` gives it the widened type `string`.
|
|
126
145
|
|
|
127
146
|
```ts docs-check
|
|
128
147
|
import { Controller, Post, RawBody } from "@antelopejs/interface-api";
|
|
@@ -146,11 +165,13 @@ class ImportController extends Controller("import") {
|
|
|
146
165
|
}
|
|
147
166
|
```
|
|
148
167
|
|
|
149
|
-
|
|
168
|
+
On success, the function returns the validated value. On failure, it throws an `HTTPResult` with status `code`. Without `errorFunc`, the body is `String(err)`. With `errorFunc`, the body is its return value. A string is sent as `text/plain`, any other `HTTPBody` as JSON, and `undefined` as an empty `text/plain` body.
|
|
150
169
|
|
|
151
|
-
### Validate with
|
|
170
|
+
### Validate with `zod`
|
|
152
171
|
|
|
153
|
-
|
|
172
|
+
`zod` and `saveUser` belong to your project. This package depends on neither, so the two Zod examples are not compiled with the docs.
|
|
173
|
+
|
|
174
|
+
```typescript fragment
|
|
154
175
|
import { assertValidation } from "@antelopejs/interface-api-util";
|
|
155
176
|
import * as z from "zod";
|
|
156
177
|
|
|
@@ -169,9 +190,9 @@ function createUser(requestBody: unknown) {
|
|
|
169
190
|
|
|
170
191
|
### Custom error formatting
|
|
171
192
|
|
|
172
|
-
Pass an `errorFunc` to
|
|
193
|
+
Pass an `errorFunc` to set the body of the error response. This example also changes the status to 422.
|
|
173
194
|
|
|
174
|
-
```typescript
|
|
195
|
+
```typescript fragment
|
|
175
196
|
import { assertValidation } from "@antelopejs/interface-api-util";
|
|
176
197
|
import * as z from "zod";
|
|
177
198
|
|
|
@@ -194,18 +215,23 @@ function validateAge(requestBody: unknown) {
|
|
|
194
215
|
|
|
195
216
|
## `RateLimit`
|
|
196
217
|
|
|
197
|
-
`@RateLimit` counts requests per key
|
|
218
|
+
`@RateLimit` counts requests per key and per decorated handler, in a fixed time window held in process memory. A key's window starts with its first request. It is not aligned to the clock minute. Once the count exceeds `limit` within `windowMs`, the guard throws an `HTTPResult` with status `429` and a `Retry-After` header, and the handler does not run.
|
|
198
219
|
|
|
199
|
-
|
|
220
|
+
An allowed request adds `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` to `context.response`. A rejected request carries the same headers on the thrown response. `X-RateLimit-Reset` is the end of the window as a UNIX timestamp in seconds. `Retry-After` is the delay until then, in seconds. Both are rounded up. If a handler returns a new `HTTPResult` instead of `context.response`, whether the headers survive depends on the API module. Return the context response to keep them.
|
|
200
221
|
|
|
201
222
|
```typescript
|
|
202
|
-
|
|
223
|
+
import type { MethodDecorator } from "@antelopejs/interface-core/decorators";
|
|
224
|
+
import type { RateLimitOptions } from "@antelopejs/interface-api-util";
|
|
225
|
+
|
|
226
|
+
declare const RateLimit: (
|
|
203
227
|
limit: number,
|
|
204
228
|
windowMs: number,
|
|
205
229
|
options?: RateLimitOptions,
|
|
206
|
-
)
|
|
230
|
+
) => MethodDecorator;
|
|
207
231
|
```
|
|
208
232
|
|
|
233
|
+
`MethodDecorator` is the type from `@antelopejs/interface-core/decorators`, not the global TypeScript type of the same name.
|
|
234
|
+
|
|
209
235
|
| Parameter | Type | Description |
|
|
210
236
|
| ---------- | ------------------ | ---------------------------------------------------- |
|
|
211
237
|
| `limit` | `number` | Maximum number of requests allowed per window |
|
|
@@ -213,17 +239,24 @@ function RateLimit(
|
|
|
213
239
|
| `options` | `RateLimitOptions` | Optional custom key function and `429` response body |
|
|
214
240
|
|
|
215
241
|
```typescript
|
|
242
|
+
import type { RequestContext } from "@antelopejs/interface-api";
|
|
243
|
+
|
|
216
244
|
interface RateLimitOptions {
|
|
217
245
|
key?: (context: RequestContext) => string | null | undefined;
|
|
218
246
|
message?: string;
|
|
219
247
|
}
|
|
220
248
|
```
|
|
221
249
|
|
|
222
|
-
|
|
250
|
+
| Option | Default | Description |
|
|
251
|
+
| --------- | ----------------------------------------- | --------------------------------------------- |
|
|
252
|
+
| `key` | `context.rawRequest.socket.remoteAddress` | Returns the key that a request counts against |
|
|
253
|
+
| `message` | `"Too many requests"` | Body of the `429` response |
|
|
254
|
+
|
|
255
|
+
By default, the guard counts requests per client IP (`context.rawRequest.socket.remoteAddress`). If the socket has no remote address, the key is the string `"unknown"`, which all such requests share. Provide `options.key` to count by user id, API key, or a forwarded header instead. If the custom key function returns a falsy value, such as a missing route parameter, the guard uses the client IP for that request, so those requests do not all count against one key.
|
|
223
256
|
|
|
224
|
-
|
|
257
|
+
Place `@RateLimit` below the route decorator (`@Get`, `@Post`, and the others). Decorators apply from the bottom up, and the route decorator copies the handler's parameter list when it registers the route. A `@RateLimit` written above it would add its guard too late. `@RateLimit` detects this order and throws an `Error` when the class is defined, so the route never runs unprotected.
|
|
225
258
|
|
|
226
|
-
### Limit by client
|
|
259
|
+
### Limit by client address
|
|
227
260
|
|
|
228
261
|
```typescript
|
|
229
262
|
import { RateLimit } from "@antelopejs/interface-api-util";
|
|
@@ -244,7 +277,7 @@ class UsersController extends Controller("/users") {
|
|
|
244
277
|
}
|
|
245
278
|
```
|
|
246
279
|
|
|
247
|
-
|
|
280
|
+
The first 100 requests from one IP within its 60-second window pass, and request 101 receives 429. Each decorated handler has its own counter, so the same IP has a separate count on another handler.
|
|
248
281
|
|
|
249
282
|
### Limit by a custom key
|
|
250
283
|
|
|
@@ -272,6 +305,6 @@ class AuthController extends Controller("auth") {
|
|
|
272
305
|
| Behind a reverse proxy | The proxy's socket IP by default | Supply a key derived from a trusted proxy hop or an authenticated identity. |
|
|
273
306
|
| Multiple instances | Independent counters in each process | Enforce a shared limit at the edge or in a shared store. |
|
|
274
307
|
|
|
275
|
-
Counters reset
|
|
308
|
+
Counters reset when the process restarts. At most once per window, on a request, the guard drops every window that has ended. The store therefore holds only keys whose window started within the last two windows.
|
|
276
309
|
|
|
277
|
-
|
|
310
|
+
A client can set `X-Forwarded-For` to any value. A key read from that header without a trusted proxy lets a client evade the limit or create many keys. A stable custom key does not share the in-memory counter across processes.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/interface-api-util",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "AntelopeJS helpers for API handlers: request assertions, input validation and rate limiting",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antelopejs",
|
|
@@ -49,9 +49,7 @@
|
|
|
49
49
|
"prepare": "if git rev-parse --is-inside-work-tree >/dev/null 2>&1 && command -v lefthook >/dev/null 2>&1; then lefthook install; fi",
|
|
50
50
|
"checks": "antelopejs-checks",
|
|
51
51
|
"size": "antelopejs-check-size",
|
|
52
|
-
"ratchet": "antelopejs-ratchet",
|
|
53
52
|
"sync": "antelopejs-sync",
|
|
54
|
-
"ratchet:update": "antelopejs-ratchet --update",
|
|
55
53
|
"sync:check": "antelopejs-sync --check",
|
|
56
54
|
"typecheck": "tsc --noEmit",
|
|
57
55
|
"suppressions": "antelopejs-suppressions",
|
|
@@ -59,9 +57,9 @@
|
|
|
59
57
|
},
|
|
60
58
|
"devDependencies": {
|
|
61
59
|
"@antelopejs/core": "^1.16.0",
|
|
62
|
-
"@antelopejs/interface-api": "^0.0
|
|
63
|
-
"@antelopejs/interface-core": "^0.
|
|
64
|
-
"@antelopejs/tooling-configs": "^0.2.
|
|
60
|
+
"@antelopejs/interface-api": "^0.2.0",
|
|
61
|
+
"@antelopejs/interface-core": "^0.4.0",
|
|
62
|
+
"@antelopejs/tooling-configs": "^0.2.18",
|
|
65
63
|
"@types/mocha": "^10.0.10",
|
|
66
64
|
"@types/node": "^22.19.15",
|
|
67
65
|
"eslint-plugin-perfectionist": "^5.11.0",
|
|
@@ -76,14 +74,22 @@
|
|
|
76
74
|
"typescript": "^5.9.3"
|
|
77
75
|
},
|
|
78
76
|
"peerDependencies": {
|
|
79
|
-
"@antelopejs/interface-api": ">=0.0
|
|
77
|
+
"@antelopejs/interface-api": ">=0.3.0 <1.0.0",
|
|
80
78
|
"@antelopejs/interface-core": ">=0.2.4 <1.0.0"
|
|
81
79
|
},
|
|
82
80
|
"packageManager": "pnpm@10.6.5",
|
|
81
|
+
"pnpm": {
|
|
82
|
+
"overrides": {
|
|
83
|
+
"@antelopejs/interface-core": "0.4.0"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
83
86
|
"antelopeJs": {
|
|
84
87
|
"test": "src/antelope.test.ts",
|
|
85
88
|
"skills": [
|
|
86
89
|
"./skills"
|
|
87
|
-
]
|
|
90
|
+
],
|
|
91
|
+
"docs": {
|
|
92
|
+
"standard": true
|
|
93
|
+
}
|
|
88
94
|
}
|
|
89
95
|
}
|
|
@@ -75,7 +75,7 @@ class MembersController extends Controller("members") {
|
|
|
75
75
|
TypeScript `asserts condition`, so the compiler narrows after the call.
|
|
76
76
|
- `assertValidation<T, Input = unknown>(body, validator, errorFunc?, code = 400)` — returns the
|
|
77
77
|
validator's result; if the validator throws, rethrows an `HTTPResult` whose body is
|
|
78
|
-
`errorFunc(err)` if provided, otherwise `String(err)`. `Input` is the type of `body`, and the
|
|
78
|
+
`errorFunc(err)` (an `HTTPBody`, or `undefined` for an empty body) if provided, otherwise `String(err)`. `Input` is the type of `body`, and the
|
|
79
79
|
validator receives it at that type (a `Buffer` body needs no cast). A validator taking a wider
|
|
80
80
|
type (`schema.parse`) fits; one taking a narrower type than the body is a compile error, unless the body is typed `any`.
|
|
81
81
|
- `RateLimit(limit, windowMs, options?)` — fixed-window counter per key; over-limit requests throw
|