Remi
Remi

Reputation: 5367

Storing and serving images in NestJS

I'm figuring out how to enable a local upload folder for a profile image.

Now, i've come as far as storing a file in the uploads folder. However, when I return that file it has no extension and its a JFIF binary file:

���� JFIF     �� cmp3.10.3.3Lq4 0xa61382cc�� C 
// etcetera...

The controller I've created is:

./src/controllers/user-profile.controller.ts

@Controller('user-profile')
export class UserProfileController {
    @Post('/:id/upload-photo')
    @UseInterceptors(FileInterceptor('image', { dest: './uploads' }))
    uploadSinglePhoto(
        @Param('id', ParseIntPipe) id: number,
        @UploadedFile() image
    ) {
        console.log('===> ', image);
        return this.userProfileService.saveUserProfilePhotoLocation(id, image.path);
    }

    @Get('/:id/profile-photo')
    getUserProfilePhoto(
    ): any {
        // '15c924f42ffaa67b3f14a5be05f0a312' is the file name that is created by the upload
        return new StreamableFile(createReadStream(join(process.cwd(), 'uploads', '15c924f42ffaa67b3f14a5be05f0a312')))
    }
}

The image object in the console log is:

===> {
  fieldname: 'image',
  originalname: '526dad4edd250b689eeb1394c3c6eb41.jpg',
  encoding: '7bit',
  mimetype: 'image/jpeg',
  destination: './uploads',
  filename: '590b454b4315009660273deac082b4ed',
  path: 'uploads\\590b454b4315009660273deac082b4ed',
  size: 45842
}

Then I store the path to the database.

./src/services/user-profile.service.ts

@Injectable()
export class UserProfileService {
    constructor(
        @InjectRepository(UserProfileEntity)
        private userProfileRepostory: Repository<UserProfileEntity>
    ) {}

    async saveUserProfilePhotoLocation(id, path): Promise<UserProfileEntity> {
        const result = await this.userProfileRepostory.createQueryBuilder()
            .update(UserProfileEntity)
            .set({
                photo: path
            })
            .where({id})
            .returning('*')
            .execute();

      return result.raw;
    }
}

And finally I've configured the express server to be able to serve static files from the uploads folder:

./src/main.ts

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  app.useStaticAssets(join(__dirname, '..', 'uploads'), {
    index: false,
    prefix: 'uploads',
  });
  await app.listen('3000');
}
bootstrap();

Now when I do a get on the end point /:id/profile-photo it does not return me a rendered image. Ïnstead it returns a file with a random set of characters in it which is probably because of the encoding.

What should I do so that I can serve an jpeg file to my application?

What is happening here?

Upvotes: 2

Views: 5974

Answers (1)

Remi
Remi

Reputation: 5367

When setting the content header (thanks Jay McDoniel) to 'image/jpeg' and creating a readable stream it returns the image:

    @Get('/:id/profile-photo')
    getUserProfilePhoto(
        @Res({ passthrough: true }) res: Response
    ): StreamableFile {

        res.set({'Content-Type': 'image/jpeg'});

        const imageLocation = join(process.cwd(), 'uploads', '15c924f42ffaa67b3f14a5be05f0a312');
        const file = createReadStream(imageLocation);
        return new StreamableFile(file);
    }

Upvotes: 3

Related Questions