Skip to content

Commit

Permalink
fix: proper type inference for extended json mime types (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
christoph-fricke authored Sep 10, 2024
1 parent 0f799fe commit b9f4bea
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/kind-dancers-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"openapi-msw": patch
---

Fixed type inference for extended JSON mime types, such as `application/problem+json`. Previously, APIs like `response(...).json` would be typed as `never` for such mime types. Now, they will be properly typed.
3 changes: 2 additions & 1 deletion src/request.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { FilterKeys, JSONLike } from "openapi-typescript-helpers";
import type { FilterKeys } from "openapi-typescript-helpers";
import type { JSONLike } from "./type-utils.js";

/** A type-safe request helper that enhances native body methods based on the given OpenAPI spec. */
export interface OpenApiRequest<RequestMap> extends Request {
Expand Down
3 changes: 2 additions & 1 deletion src/response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import {
type HttpResponseInit,
type StrictResponse,
} from "msw";
import type { FilterKeys, JSONLike } from "openapi-typescript-helpers";
import type { FilterKeys } from "openapi-typescript-helpers";
import type { Wildcard } from "./http-status-wildcard.js";
import type { JSONLike } from "./type-utils.js";

/**
* Requires or removes the status code from {@linkcode HttpResponseInit} depending
Expand Down
8 changes: 8 additions & 0 deletions src/type-utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
import type { FilterKeys } from "openapi-typescript-helpers";

/**
* Returns any JSON mime type. Similar to `openapi-typescript-helpers`
* version but actually works with types like "application/problem+json".
*/
export type JSONLike<T> = FilterKeys<T, `${string}/${string}json`>;

/**
* Converts a type to string while preserving string literal types.
* {@link Array}s are unboxed to their stringified value.
Expand Down
13 changes: 13 additions & 0 deletions test/fixtures/request-body.api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@ paths:
responses:
204:
description: NoContent
/special-json:
post:
summary: Create for Special JSON
operationId: postSpecialJSON
requestBody:
required: true
content:
application/ld+json:
schema:
$ref: "#/components/schemas/NewResource"
responses:
204:
description: NoContent
components:
schemas:
Resource:
Expand Down
18 changes: 18 additions & 0 deletions test/fixtures/response-content.api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,24 @@ paths:
text/plain:
schema:
type: string
/special-json:
get:
summary: Get Special JSON Response
operationId: getSpecialJSON
responses:
200:
description: Success
content:
application/ld+json:
schema:
$ref: "#/components/schemas/Resource"

401:
description: Error
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Exception"
components:
schemas:
Resource:
Expand Down
11 changes: 11 additions & 0 deletions test/request-body.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ describe("Given an OpenAPI schema endpoint with request content", () => {
.returns.resolves.toEqualTypeOf<{ name: string; value: number }>();
});

test("When a request uses a special JSON mime type, Then the content is strict-typed", async () => {
type Endpoint = typeof http.post<"/special-json">;
const resolver = expectTypeOf<Endpoint>().parameter(1);
const request = resolver.parameter(0).toHaveProperty("request");

request.toHaveProperty("text").returns.toEqualTypeOf<never>();
request
.toHaveProperty("json")
.returns.resolves.toEqualTypeOf<{ name: string; value: number }>();
});

test("When a request content is optional, Then the content is strict-typed with optional", () => {
type Endpoint = typeof http.patch<"/resource">;
const resolver = expectTypeOf<Endpoint>().parameter(1);
Expand Down
12 changes: 12 additions & 0 deletions test/response-content.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,16 @@ describe("Given an OpenAPI schema endpoint with response content", () => {
>
>();
});

test("When special JSON mime types are used, Then the response json helper still works", async () => {
http.get("/special-json", ({ response }) => {
expectTypeOf(response(200).json).returns.toEqualTypeOf<
StrictResponse<{ id: string; name: string; value: number }>
>();

expectTypeOf(response(401).json).returns.toEqualTypeOf<
StrictResponse<{ error: string; code: number }>
>();
});
});
});

0 comments on commit b9f4bea

Please sign in to comment.