Guille
Guille

Reputation: 452

How to serve static images in NestJS

I'm started to learning MEAN stack and when I went to Express I saw that existed a extra layer in the express framework that is called NestJS. It had all what I wanted and it had an Angular-like syntax so was perfect to me.

But every new step is a nightmare documentation isn't usefull at all. Now I'm fighting with the framework to achieve to serve images and dont use the API for this kind of calls.

I tried all that I found on Internet, for example:

main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as bodyParser from 'body-parser';
import * as express from 'express';
import { join } from 'path';

import { NestExpressApplication } from '@nestjs/platform-express';



declare const module: any;

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  app.useStaticAssets(join(__dirname, '..', 'public'));




  app.enableCors({
    origin: true,
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
    credentials: true,
  });

//I tried this 2 options (https://docs.nestjs.com/techniques/mvc) (https://whatthecode.dev/serve-static-files-with-nest-js/)
  app.use('/resources', express.static(process.cwd() + '\\resources'));
  app.useStaticAssets(join(__dirname, '..', '\\public'));

  app.use(bodyParser.json({ limit: '50mb' }));
  app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
 
  //console.log(process.cwd());


  await app.listen(3000);

  if (module.hot) {
    module.hot.accept();
    module.hot.dispose(() => app.close());
  }

}
bootstrap();

I tried to put it in the app.module as this (it worked but is always looking for an index.html not images):


import { AnimalsModule } from './animals/animals.module';
import { SpeciesModule } from './species/species.module';
import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module';
import { BreedModule } from './breed/breed.module';
import { StateModule } from './state/state.module';
import { PhotoModule } from './photo/photo.module';


@Module({
  imports: [
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, '..', 'public'),   // <-- path to the static files
    }),
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: '',
      database: 'nest',
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      synchronize: true,
    }),
    AnimalsModule,
    SpeciesModule,
    BreedModule,
    StateModule,
    AuthModule,
    UsersModule,
    PhotoModule,
  ],
})

//It seems that ignores this register and just uses the method signature options
@Module({
  imports: [MulterModule.register({
    dest: './resources/tmp',
    limits: { fieldSize: 25 * 1024 * 1024 * 1024, fileSize: 25 * 1024 * 1024 * 1024 }
  })],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule { }

How the hell I can serve images or files and avoid the api routing?

Thanks to all.

Upvotes: 34

Views: 64761

Answers (15)

Ahmed Ali
Ahmed Ali

Reputation: 1

use this in main.ts

app.enableCors({
        origin: ['https://phish-orcin.vercel.app', 'http://localhost:3000','https://phish-orcin.vercel.app/', 'http://localhost:3000/'],
        methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
        credentials: true,
        allowedHeaders: ['Content-Type', 'Authorization'],
    });

// Use helmet with Cross-Origin-Resource-Policy header
app.use(
    helmet({
        crossOriginResourcePolicy: { policy: 'cross-origin' }, // Allow cross-origin resources
    }),
);
//app.module
ServeStaticModule.forRoot({
  rootPath: join(__dirname, '..', 'public'),
  serveRoot: '/', // Serve images from /images path
}),

Upvotes: 0

Krishna Jangid
Krishna Jangid

Reputation: 5410

My issue is resolve with i use like that :).

if you want to access your folder as different name then you can use like that.

enter image description here

Here my actual folder path is => assets/product_images/flower4.jpg
now i want to access like that => staticAssets/product_images/flower4.jpg

so using the above code i able to access my images using staticAssets/product_images/flower4.jpg this url

enter image description here

Upvotes: 1

import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';

@Module({
  imports: [
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, '..', '/uploads/public'),
      serveStaticOptions: { index: false },
    }),
  ],
})
export class AppModule {}

This will serve images from /dist/uploads/public/

You can access the files or images from, http://localhost:3000/x.jpg

Upvotes: 2

TungHarry
TungHarry

Reputation: 1161

To serve static files, including images, in a NestJS application, you can use the express.static middleware provided by the Express framework, which is integrated into NestJS. Here's how you can set it up:

  1. Create a folder in your project's directory to store your public images. For example, you can create a folder named public at the root level of your project.

  2. Move your images into the public folder. You can organize them into subdirectories if necessary.

  3. Open the main.ts (or main.js) file in the root directory of your NestJS application.

  4. Import the express module from the @nestjs/platform-express package and the join function from the path module.

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';
import * as express from 'express';
import { join } from 'path';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  // Add the following code
  app.use('/static', express.static(join(__dirname, '..', 'public')));

  await app.listen(3000);
}
bootstrap();
  1. In the code above, we're telling the application to serve static files from the public folder when the URL starts with /static. You can change the /static part to any URL prefix you desire.

  2. You can access your public images using the URL pattern: http://localhost:3000/static/image.jpg

Upvotes: 0

nicklee
nicklee

Reputation: 85

In app.module.ts:

@Module({
    imports: [
      ServeStaticModule.forRoot({
        rootPath: join(__dirname, ".."),
        renderPath: "public",
      }),
    ],
})
export class AppModule {}

rootPath - Static files root directory. Default: "client"
renderPath - Path to render static app (concatenated with the serveRoot value). Default: * (wildcard - all paths).
(https://www.npmjs.com/package/@nestjs/serve-static)

You should set rootPath to project root directory and renderPath to your static files.

Upvotes: 1

Neelansh Pandey
Neelansh Pandey

Reputation: 41

you can move to root directory, if your upload folder is in rootdir then put the path of folder in renderPath like this.

ServeStaticModule.forRoot({
  rootPath: join(__dirname, '../../'),
  renderPath: '/uploads',
})

Upvotes: 4

Vova
Vova

Reputation: 23

I had the same issue. I also struggled with this issue for a very long time. For example: you have uploads folder for picture. In App.module you need use it:

    ServeStaticModule.forRoot({
  rootPath: join(__dirname, '..', 'client'),
}),

localhost:3000/picture.png

if i use without 'client' folder, my picture is

ServeStaticModule.forRoot({
  rootPath: join(__dirname, '..'),
}),

localhost:3000/client/picture.png

Upvotes: 2

Hossein
Hossein

Reputation: 222

The main method of document nest using the module is as follows:


 ServeStaticModule.forRoot({
    rootPath: join(__dirname, '..', 'upload'),   //  path to the static files image
 }),

But if you get the error for searching the index.html, you can use this method, which I also used

main.ts

import * as express from 'express';

app.use(express.static(join(__dirname, '../upload')))

Upvotes: 0

zemil
zemil

Reputation: 5066

Separate module solution, then import it into AppModule.

import { Module } from '@nestjs/common';
import { ServeStaticModule } from '@nestjs/serve-static';
import { resolve } from 'path';

@Module({
    imports: [
        ServeStaticModule.forRoot(
            (() => {
                const publicDir = resolve('./public/files/');
                const servePath = '/files';

                return {
                    rootPath: publicDir,
                    // serveRoot - if you want to see files on another controller,
                    // e.g.: http://localhost:8088/files/1.png
                    serveRoot: servePath,
                    exclude: ['/api*'],
                };
            })()
        ),
    ],
})
export class PublicModule {}

Upvotes: 2

Abhay
Abhay

Reputation: 6760

There are two ways to serve static content in NestJs. Either use 1 OR 2.

1.Using ServeStaticModule in app.module.ts

import { Module } from '@nestjs/common';
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';
import { mainModule } from 'process'    
@Module({
  imports: [
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, '..', 'public'),
    }),
  ],
})
export class AppModule {}

2.Using NestExpressApplication in main.ts [Even by default Nest Js uses Express only]

import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(
    AppModule,
  );

  app.useStaticAssets(join(__dirname, '..', 'public'));

  await app.listen(3000);
}
bootstrap();

Upvotes: 9

Vikram Singh Shekhawat
Vikram Singh Shekhawat

Reputation: 764

You can use express static module in nest js too.

// ...imports
import * as express from 'express';
import { join } from 'path';

async function bootstrap() {
    const app = await NestFactory.create(AppModule);
  
    // serve static assets from the client/dist folder, change this to the correct path for your project
    app.use(express.static(join(process.cwd(), '../client/dist/')));
  
    //... you config

   await app.listen(process.env.PORT);
 }
bootstrap();

Credit to : https://whatthecode.dev/serve-static-files-with-nest-js/

Upvotes: -1

gehtmaguad
gehtmaguad

Reputation: 653

Use the useStaticAssets() method (the ServeStaticModule is for serving static content like SPAs). So as a minimal example, your main.ts should look like the following):

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

In the above example your assets are served from the root of your application (e.g. http://localhost:3000/example.png.

You can also pass options to the method in oder to configure the path from which the assets are served:

  app.useStaticAssets(join(__dirname, '..', 'public'), {
    prefix: '/public/',
  });

In this example your path is prefixed with public (e.g. http://localhost:3000/public/example.png)

Upvotes: 36

Hadrien TOMA
Hadrien TOMA

Reputation: 2723

The idea of @pzabrocki brings me to the following minimal working repository: https://gitlab.com/hadrien-toma/nest-static-files

To play with it:

git clone https://gitlab.com/hadrien-toma/nest-static-files
yarn install
yarn run start

Then the my-file.json is served at http://localhost:3333/my-file.json.

Upvotes: 0

mulwatech
mulwatech

Reputation: 9

add this to main.ts replace "uploads" with your directory name app.use('/uploads',express.static(join(process.cwd(), 'uploads')));

Upvotes: 0

pzabrocki
pzabrocki

Reputation: 297

This is what I've done:

  1. in app.module.ts

     import { ServeStaticModule } from '@nestjs/serve-static/dist/serve-static.module';
     import { join } from 'path';
    
     @Module({
         imports: [
             ServeStaticModule.forRoot({
                 rootPath: join(__dirname, '..', 'public'),
             }),
         ],
     })
    
  2. Then I created "public" dir on the same level as "src", "dir" etc.

  3. The file is available at: https://my-url/file.jpg

Upvotes: 27

Related Questions