Search code examples
node.jsexpressfile-uploadswaggertsoa

uploading files - nodejs with typescript and tsoa and swagger


I build a web api with nodejs and express. I used tsoa to generate my routes and a swagger.json file. I want to be able to upload files via the swagger landing page. I followed the instructions on this page: https://tsoa-community.github.io/docs/file-upload.html

My tsoa.json looks like this:

{
"entryFile": "src/app.ts",
"noImplicitAdditionalProperties": "throw-on-extras",
"controllerPathGlobs": [
  "src/**/*.controller.ts"
],
"spec": {
  "basePath" : "/",
  "description": "",
  "outputDirectory": "dist/api/public",
  "specVersion": 3,
  "specMerging": "recursive",
  "paths": {
    "/admin/commands/create": {
      "post": {
        "consumes": [
          "multipart/form-data"
        ],
        "parameters": [
          {
            "in": "formData",
            "name": "randomFileIsHere",
            "required": true,
            "type": "file"
          }
        ]
      }
    }
  }
},
"routes": {
  "routesDir": "src/api"
}

}

My controller:

@Tags("Admin Commands")
@Route("admin/commands")
export class AdminCommandController extends Controller 
{

    @Post('create')
    public async CreateCommand(@Request() request: express.Request): Promise<void> 
    {
        try{
            await this.handleFile(request);
        }
        catch {
            throw new Error("Error uploading file.");
        }

        console.log("No error");

    }
private handleFile(request: express.Request): Promise<any> {
        const multerSingle = multer().single("randomFileIsHere");
        return new Promise((resolve, reject) => {
          multerSingle(request, undefined, async (error: Error) => {
            if (error) {
              reject("error");
            }
            resolve("file will be in request.randomFileIsHere");
          });
        });
      }

}

but when I use the tsoa swagger command to generate the the swagger.json the multipart/form-data is not added to my swagger.json. If I manually add the multipart/form-data to my swagger.json the input field on my swagger landing page is a text field instead of a file field.

    "paths": {
        "/admin/commands/create": {
            "post": {
                "operationId": "CreateCommand",
                "consumes": [
                    "multipart/form-data"
                  ],
                  "parameters": [
                    {
                      "in": "formData",
                      "name": "randomFileIsHere",
                      "required": true,
                      "type": "file"
                    }
                  ],
                "responses": {
                    "204": {
                        "description": "No content"
                    }
                },
                "tags": [
                    "Admin Commands"
                ],
                "security": []
            }
        }
}

What am I missing or doing wrong? Furthermore, if this would work, how do i extract the file from the request. The documentation says the file will be added to the randomFileIsHere property of the request object, but if i call request.randomFileIsHere it will obviously throw an error.


Solution

  • I also tried to follow official documents. I was able to save the uploaded file, but codes didnt looked clean to me. Then I realised there is a @UploadedFile decorator. You can add it and read file directly.

    @Post("profile-photo")
    public async uploadProfilePhoto(@UploadedFile() profilePhoto) {
    console.log(profilePhoto)
    }
    

    Using a HTTP testing tool ,like Postman, define a field named "profilePhoto" and select a file. You should be able to see it on server terminal.