-
Notifications
You must be signed in to change notification settings - Fork 498
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
One working example showing a controller serving an image from a stream or buffer #1686
Comments
Since this was a blocker for me, I continued my search. This time I used the ChatGPT model "o1-preview" for a conversation. After some suggestions with compile errors, I managed to get the following code out of it which appears to work as desired. I'm sharing this here, in case someone else has a similar issue. Note that this is for TSOA 6.4.0. import { Controller, Get, Route, Response, Path, SuccessResponse } from '@tsoa/runtime';
import { inject } from 'inversify';
import { Types } from '../config/ioc.types';
import { IEnvironment } from '../config/IEnvironment';
import path, { join } from 'path';
import { createReadStream } from 'fs';
import { stat } from 'fs/promises';
import { Readable } from 'stream';
import { provide } from 'inversify-binding-decorators';
@Route('/2024-09-06/images')
@provide(ImageController)
export class ImageController extends Controller {
public constructor(
@inject(Types.IEnvironment) environment: IEnvironment,
) {
super();
this._environment = environment;
}
@Get('{imageId}')
@SuccessResponse('200', 'OK')
@Response(404, 'Image not found')
public async getImage(
@Path() imageId: string,
): Promise<Readable> {
// Securely construct the full path to the image
const imageDirectory = this._environment.blogPostsDirectory;
const imagePath = join(imageDirectory, imageId);
// Prevent directory traversal attacks
if (!imagePath.startsWith(imageDirectory)) {
this.setStatus(400);
throw new Error('Invalid image path');
}
// Check if the file exists
try {
await stat(imagePath);
} catch (err) {
// File does not exist
this.setStatus(404);
throw new Error('Image not found');
}
// Determine the Content-Type based on the file extension
const fileExtension = path.extname(imagePath).toLowerCase();
let contentType = 'image/png'; // Default Content-Type
switch (fileExtension) {
case '.jpg':
case '.jpeg':
contentType = 'image/jpeg';
break;
case '.gif':
contentType = 'image/gif';
break;
case '.bmp':
contentType = 'image/bmp';
break;
case '.svg':
contentType = 'image/svg+xml';
break;
case '.webp':
contentType = 'image/webp';
break;
case '.png':
default:
contentType = 'image/png';
break;
}
// Set the Content-Type header
this.setHeader('Content-Type', contentType);
// Create a read stream and return it
return createReadStream(imagePath);
}
private _environment: IEnvironment;
} Note that this code was generated by AI. I merely edited it to some degree to fit into our environment. Happy for you to use it "as-is" but keep in mind that you are responsible and accountable for any bugs that may be left in this code snippet. Happy coding! |
Sorting
I'm submitting a ...
I confirm that I
I've also used standard internet search, Github Copilot and Perplexity.ai. I also consulted the documentation.
Expected Behavior
Current Behavior
Possible Solution
Steps to Reproduce
Context (Environment)
Version of the library: 6.4.0 (@tsoa/client and @tsoa/runtime)
Version of NodeJS: 20.17.0
I'm using pnpm but I don't think that has any material relevance.
Detailed Description
I'm trying to find one single and complete example for the following:
Here is an implementation that does most of it but returns it to the browser as a json object, not the image itself:
It appears to me that I am overlooking something completely obvious but I haven't been able to figure it out just yet.
Perhaps someone who has more experience with TSOA than me can point me in the right direction. To me it appears that downloading a file is something quite common, so I am hoping that TSOA offers some adquate solution for this.
Thank you!
Breaking change?
The text was updated successfully, but these errors were encountered: