Can't find a way to return a pdf binary
See original GitHub issueSorting
-
I’m submitting a …
- bug report
- feature request
- support request
-
I confirm that I
- used the search to make sure that a similar issue hasn’t already been submit
Expected Behavior
I’d like to return a PDF from an endpoint and have the Swagger UI reflect the Media Type for that endpoint is " application/pdf".
"/document": {
"get": {
"operationId": "Get",
"responses": {
"200": {
"description": "Ok",
"content": {
"`application/pdf`": {
"schema": {
"type": "string",
"format": "byte"
}
}
}
}
},
}
}
ℹ️I don’t know swagger spec very well so I’m just guessing above that I’d like content to be application/pdf
Current Behavior
I’ve tried a plain return, e.g. the controller looks like this:
@Get("/")
public async getDocument(
): Promise<Readable> {
const buffer = Buffer.from(readFileSync(join(__dirname, "minimal.pdf")));
return Readable.from(buffer);
}
This works ✅, but in Swagger UI the Media Type is application/json
❌
I’ve also tried using a TsoaResponse
pattern, like this:
@Get("/")
public async getDocument(
@Res() res: TsoaResponse<200, Readable, { "content-type": "application/pdf" }>
): Promise<void> {
const buffer = Buffer.from(readFileSync(join(__dirname, "minimal.pdf")));
await res(200, Readable.from(buffer), {
"content-type": "application/pdf",
});
}
This also works ✅, but the Swagger UI says application/json
❌ the UI show two responses: One 200, and one 204 (b/c of
the void return) ❌
"/documents": {
"get": {
"operationId": "Get",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string",
"format": "byte"
}
}
},
"headers": {
"content-type": {
"schema": {
"type": "string",
"enum": [
"application/pdf"
],
"nullable": false
},
"required": true
}
}
},
"204": {
"description": "No content"
}
},
}
}
Steps to Reproduce
Download this example pdf file: https://brendanzagaeski.appspot.com/minimal.pdf
Add this route:
import { Readable } from "stream";
import {
Controller,
Get,
Route,
} from "tsoa";
@Route("document")
export class DocumentController extends Controller {
@Get("/1") public async getDocument1(
): Promise<Readable> {
const pdfBuffer = Buffer.from(readFileSync(join(__dirname, "minimal.pdf")))
return Readable.from(buffer);
}
}
@Route('document')
export class DocumentController extends Controller {
@Get('/2')
public async getDocument2(@Res() res: TsoaResponse<200, Readable, { 'content-type': 'application/pdf' }>): Promise<void> {
const pdfBuffer = Buffer.from(readFileSync(join(__dirname, 'minimal.pdf')))
return Readable.from(buffer)
}
}
Context (Environment)
Version of the library: tsoa@3.11.2 Version of NodeJS: v16.1.0
- Confirm you were using yarn not npm: [😬] (I’m using pnpm, hope that’s not a problem!)
Detailed Description
I’m too new to TSOA + OpenAPI to make a truly specific proposal, but I think I expected either a content-type decorator
or some way to use TsoaResponse
to specify that this endpoint’s only response is a PDF binary.
And thanks for making tsoa available!
Issue Analytics
- State:
- Created 2 years ago
- Comments:5
Top GitHub Comments
Yes, that’s how we should support it.
I use tsoa with express.
The express router from tsoa calls pipe if the Object has the right properties. https://github.com/lukeautry/tsoa/blob/master/packages/cli/src/routeGeneration/templates/express.hbs#L210
My current solution is to an Object like: