Document rate limit headers in OpenAPI spec
Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled
Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled
- Add reusable header components (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Retry-After) - Reference headers in 200 responses on all conversion and demo endpoints - Add Retry-After header to 429 responses - Update Rate Limits section in API description to mention response headers - Add comprehensive tests for header documentation (21 new tests) - All 809 tests passing
This commit is contained in:
parent
a3bba8f0d5
commit
70eb6908e3
18 changed files with 801 additions and 821 deletions
|
|
@ -15,4 +15,94 @@ describe("OpenAPI spec accuracy", () => {
|
|||
it("should mark /v1/signup/verify as deprecated", () => {
|
||||
expect(spec.paths["/v1/signup/verify"]?.post?.deprecated).toBe(true);
|
||||
});
|
||||
|
||||
describe("Rate limit headers", () => {
|
||||
it("should define rate limit header components", () => {
|
||||
expect(spec.components.headers).toBeDefined();
|
||||
expect(spec.components.headers["X-RateLimit-Limit"]).toBeDefined();
|
||||
expect(spec.components.headers["X-RateLimit-Remaining"]).toBeDefined();
|
||||
expect(spec.components.headers["X-RateLimit-Reset"]).toBeDefined();
|
||||
expect(spec.components.headers["Retry-After"]).toBeDefined();
|
||||
});
|
||||
|
||||
it("X-RateLimit-Limit should be integer type with description", () => {
|
||||
const header = spec.components.headers["X-RateLimit-Limit"];
|
||||
expect(header.schema.type).toBe("integer");
|
||||
expect(header.description).toContain("maximum");
|
||||
});
|
||||
|
||||
it("X-RateLimit-Remaining should be integer type with description", () => {
|
||||
const header = spec.components.headers["X-RateLimit-Remaining"];
|
||||
expect(header.schema.type).toBe("integer");
|
||||
expect(header.description).toContain("remaining");
|
||||
});
|
||||
|
||||
it("X-RateLimit-Reset should be integer type with Unix timestamp description", () => {
|
||||
const header = spec.components.headers["X-RateLimit-Reset"];
|
||||
expect(header.schema.type).toBe("integer");
|
||||
expect(header.description.toLowerCase()).toContain("unix");
|
||||
expect(header.description.toLowerCase()).toContain("timestamp");
|
||||
});
|
||||
|
||||
it("Retry-After should be integer type with description about seconds", () => {
|
||||
const header = spec.components.headers["Retry-After"];
|
||||
expect(header.schema.type).toBe("integer");
|
||||
expect(header.description.toLowerCase()).toContain("second");
|
||||
});
|
||||
|
||||
const conversionEndpoints = [
|
||||
"/v1/convert/html",
|
||||
"/v1/convert/markdown",
|
||||
"/v1/convert/url",
|
||||
];
|
||||
|
||||
const demoEndpoints = ["/v1/demo/html", "/v1/demo/markdown"];
|
||||
|
||||
const allRateLimitedEndpoints = [...conversionEndpoints, ...demoEndpoints];
|
||||
|
||||
allRateLimitedEndpoints.forEach((endpoint) => {
|
||||
describe(`${endpoint}`, () => {
|
||||
it("should include rate limit headers in 200 response", () => {
|
||||
const response200 = spec.paths[endpoint]?.post?.responses["200"];
|
||||
expect(response200).toBeDefined();
|
||||
expect(response200.headers).toBeDefined();
|
||||
expect(response200.headers["X-RateLimit-Limit"]).toBeDefined();
|
||||
expect(response200.headers["X-RateLimit-Remaining"]).toBeDefined();
|
||||
expect(response200.headers["X-RateLimit-Reset"]).toBeDefined();
|
||||
});
|
||||
|
||||
it("should reference header components in 200 response", () => {
|
||||
const headers = spec.paths[endpoint]?.post?.responses["200"]?.headers;
|
||||
expect(headers["X-RateLimit-Limit"].$ref).toBe(
|
||||
"#/components/headers/X-RateLimit-Limit"
|
||||
);
|
||||
expect(headers["X-RateLimit-Remaining"].$ref).toBe(
|
||||
"#/components/headers/X-RateLimit-Remaining"
|
||||
);
|
||||
expect(headers["X-RateLimit-Reset"].$ref).toBe(
|
||||
"#/components/headers/X-RateLimit-Reset"
|
||||
);
|
||||
});
|
||||
|
||||
it("should include Retry-After header in 429 response", () => {
|
||||
const response429 = spec.paths[endpoint]?.post?.responses["429"];
|
||||
expect(response429).toBeDefined();
|
||||
expect(response429.headers).toBeDefined();
|
||||
expect(response429.headers["Retry-After"]).toBeDefined();
|
||||
expect(response429.headers["Retry-After"].$ref).toBe(
|
||||
"#/components/headers/Retry-After"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should mention rate limit headers in API description", () => {
|
||||
const description = spec.info.description;
|
||||
expect(description).toContain("X-RateLimit-Limit");
|
||||
expect(description).toContain("X-RateLimit-Remaining");
|
||||
expect(description).toContain("X-RateLimit-Reset");
|
||||
expect(description).toContain("Retry-After");
|
||||
expect(description).toContain("429");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue