Closed ManfredLange closed 1 month ago
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?