Transform only transforms referenced schemas
LucaSchwan opened this issue · comments
Description
I'm using a small script with a transform function like in the example to transform schemas of type: string, format: binary
to Blob
s. However this only happens when it is within a schema that is referenced, not when I specify the schema in place.
Name | Version |
---|---|
openapi-typescript |
^7.0.0-next.8 |
Node.js | 21.7.1 |
OS + version | nixos unstable (24.05) |
Reproduction
I have created this simple spec.yml, which has one post route with the schema defined in place and one with the schema in a reference.
openapi: "3.0.0"
info:
version: 1.0.0
title: Schema issue
license:
name: MIT
url: https://opensource.org/license/mit
servers:
- url: something.com
paths:
/api/file-no-schema:
post:
security: []
summary: "no schema"
operationId: noSchema
requestBody:
content:
application/json:
schema:
type: string
format: binary
responses:
200:
description: "s3 url of the uploaded image"
content:
application/json:
schema:
$ref: "#/components/schemas/FileReturn"
400:
description: "bad request"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
default:
description: "unknown error"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/api/file-with-schema:
post:
security: []
summary: "with schema"
operationId: withSchema
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/File"
responses:
200:
description: "s3 url of the uploaded image"
content:
application/json:
schema:
$ref: "#/components/schemas/FileReturn"
400:
description: "bad request"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
default:
description: "unknown error"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
schemas:
File:
type: string
format: binary
FileReturn:
properties:
s3Url:
type: string
Error:
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string
and I'm transforming it with this script:
import fs from "node:fs";
import openapiTS, { astToString } from "openapi-typescript";
import ts from "typescript";
const BLOB = ts.factory.createIdentifier("Blob"); // `Blob`
const NULL = ts.factory.createLiteralTypeNode(ts.factory.createNull()); // `null`
let openapiPath = "../spec.yml";
console.log(`⌛Loading openapi schema from ${openapiPath}`);
console.log("✨Transforming binary data to file");
const ast = await openapiTS(new URL(openapiPath, import.meta.url), {
transform(schemaObject, metadata) {
if (schemaObject.format === "binary") {
return schemaObject.nullable
? ts.factory.createUnionTypeNode([BLOB, NULL])
: BLOB;
}
},
});
let contents = `/**
* This file was auto-generated by openapi-typescript.
* Do not make direct changes to the file.
*/
`;
contents += astToString(ast);
let path = "./generated/v1.d.ts";
console.log(`🖊️Writing schema to ${path}`);
fs.writeFileSync(path, contents);
Expected result
I'd expect the request Body of the noSchema
endpoint:
...
requestBody?: {
content: {
"application/json": string;
};
};
...
to not be of type string
, but of type Blob
, just like the generated type of the File
schema:
...
schemas: {
/** Format: binary */
File: Blob;
...
Checklist
- My OpenAPI schema passes the Redocly validator (
npx @redocly/cli@latest lint
) - I’m willing to open a PR (see CONTRIBUTING.md)
I digged through the code a bit and I think I found where this issue comes from. Thes only place where transform
is called seems to be here. This only happens if the schema object has includes the "properties"
, "additionalProperties"
, or "$defs"
. And then it only calls transform for for every one of those properties, while I think the transform should also be called for the schemaObject
itself. I'm trying this out currently. But I'm not sure how to handle the optional
yet.