How does nestjs get the cookie in the request?
import { Get, Controller, Response, Request } from '#nestjs/common';
import { AppService } from './app.service';
const l = console.log
#Controller()
export class AppController {
#Get('json')
json(#Request() req){
console.log(req.cookies) // undefined
}
}
You have to install cookie-parser middleware.
$ npm install --save cookie-parser
once the installation process is completed, simply bind middleware to your application:
const app = await NestFactory.create(ApplicationModule);
app.use(cookieParser());
read more here: https://expressjs.com/en/resources/middleware/cookie-parser.html
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
import * as cookieParser from 'cookie-parser'
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(cookieParser());
await app.listen(5000);
}
bootstrap();
For everyone, who is looking at this question in 2022.
You can find it in the docs:
https://docs.nestjs.com/techniques/cookies
The other answers don't work, if you use Typescript.
You need to run (according to docs):
$ npm i cookie-parser
$ npm i -D #types/cookie-parser
Related
Auth0 provides express-openid-connect, which produces global middleware with routes. I'd like to make NestJS Middleware that wraps it.
I've created my middleware wrapper:
import { Inject, Injectable, NestMiddleware } from '#nestjs/common';
import { RequestHandler } from 'express';
import { auth } from 'express-openid-connect';
import { OidcOptions, OIDC_MODULE_OPTIONS } from './oidc';
#Injectable()
export class OidcMiddleware implements NestMiddleware {
private middleware: RequestHandler;
constructor(#Inject(OIDC_MODULE_OPTIONS) oidcOptions: OidcOptions) {
this.middleware = auth({
...oidcOptions.configParams
})
}
use(req: any, res: any, next: () => void) {
this.middleware(req, res, next);
}
}
and I apply it on the consumer:
#Module({
imports: [HttpModule],
controllers: [OidcController]
})
export class OidcModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(OidcMiddleware)
.forRoutes('*')
}
}
The problem is that the express middleware has routes, and they aren't being applied in the same way they are when I register the express middleware directly with the app in main.ts with the app.use(auth({...}) pattern. When registered from main.ts the /login and /callback are working. In both cases I've enabled DEBUG and confirmed that express-openid-connect middleware objects contains the routes; but when using the NestMiddleware pattern I think NestJS just returns 404 Not Found responses since the routes aren't registered with the framework.
I tried registering dummy routes on a dummy controller, but then inside of the use method the req has already been rewritten, and manually calling the pieces started feeling way too hacky.
What is the conventional method used by NestJS developers to wrap express middleware in a NestJS compatible module?
I have written this method here
In redisController.js
export default getAllKeysWithValue = async (req,res) => {
client.keys('*', (err, keys)=> {
if (err) return console.log(err);
for(let i =0;i<keys.length;i++){
client.get(keys[i],function(err,data){
console.log(`key is ${keys[i]} and value is ${data}`);
res.send("LOOK AT YOUR LOG :)")
})
}
});
}
And in the routes.js
import express from 'express'
import getAllKeysWithValue from "../controllers/redisController"
import getRedisValue from "../controllers/redisController";
import postRedisValue from "../controllers/redisController";
var router = express.Router();
router.get("/getAll",getAllKeysWithValue)
router.get('/getKey/:keyRedis',getRedisValue);
router.post('/createKeyValue',postRedisValue);
export default router;
And in the server.js
import express from 'express'
import bodyParser from 'body-parser';
import redisRoute from './routes/routes';
const app = express();
const PORT = 3001;
bodyParser.urlencoded({extended : false})
app.use(express.json())
app.use("/redisLogic",redisRoute);
app.listen(PORT,() =>{
console.log("SERVER r");
})
But iam getting Cannot find module 'C:\Users\me\OneDrive\Desktop\firstTask\routes\routes' imported from C:\Users\me\OneDrive\Desktop\firstTask\server.js
Did you mean to import ../routes/routes.js?
!Structure]1
A default import can be imported in another file as import myDefaultImport from './myFile.js'
You cannot have multiple default exports in one file. So in redisController.js export your functions as
// declare function
export function getAllKeysWithValue() { ... }
export function postRedisValue () { ... }
// the one allowed default export per file
export default myFunction() { ... }
In other file you import them as
import myFunction, { getAllKeysWithValue, postRedisValue } from `path-to-controller`
These are ES6 in/exports and straightforward.
The path and usage of your redisRouter is correct. I guess the error happens cause you have mutliple default exports.
It can be so simple as a piece of cake.
You're using the CommonJS in your back-end side.
Try using ES6 method.
Syntax :
const . . . = require('./')
Hint: If you want to have multiple defaults in JavaScript, you can do it through this syntax:
export default { Function1, Function2 }
Hint:
In NodeJS, It's better to use module.exports and exports.Function = ..
However, There's a difference between them that you can surf the Internet to check it out.
I have a Nodejs with express application. I register my routes using tsoa.
When i add swagger-ui-express to my nodejs application I get the following error Error: TypeError: Router.use() requires a middleware function but got a undefined
I initialize the app as follows:
app.ts
import config from './api/build/config';
import express from 'express';
function startServer() {
const app = express();
require('./api/loaders').default(app);
app.listen(config.port, () => {
console.log(`
################################################
🛡️ Server listening on port: ${config.port} 🛡️
################################################
`);
});
}
startServer();
loaders\index.ts
import {Express} from 'express';
export default (app: Express) => {
require('./express').default(app);
console.log('✌️ Express loaded');
require('./swagger').default(app);
console.log('✌️ Swagger loaded');
};
express.ts
import bodyParser from 'body-parser';
import {Express, Request, Response, NextFunction} from 'express';
import logger from 'morgan';
import { RegisterRoutes } from '../routes';
import cors from 'cors';
export default function startExpress(app: Express) {
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(cors());
//register all routes from the routes generated by tsoa
RegisterRoutes(app);
// catch 404 and forward to error handler
app.use((request: Request, response: Response, next: NextFunction) => {
const error = new Error('404 Not Found');
error['status'] = 404;
next(error);
});
// error handlers
// error handler will print stacktrace only in development
app.use((error: any, request: Request, response: Response) => {
response.locals.message = error.message;
response.locals.error = request.app.get('env') === 'development' ? error : {};
response.status(error.status || 500);
response.send(error.message);
});
}
swagger.ts
import { Express } from 'express';
import swaggerUi from 'swagger-ui-express';
export default function startSwagger(app: Express) {
try{
const swaggerDocument = require('../build/swagger.json');
var options = {
explorer: true
};
app.use('/swagger', swaggerUi.server, swaggerUi.setup(swaggerDocument, options));
}
catch(error){
throw new Error(error);
}
}
I also tried to use import statements instead of require, but it doesn't make a difference. Why does my compiler suddenly say my app Express object is a Router object and how do I set up nodejs with express and registering routes in different files?
To answer your question...
Why does my compiler suddenly say my app Express object is a Router object...
It doesn't. You can see a reference to the Router.use() function because it is just eventually called inside the app.use() function.
The actual issue here as mentioned in the error message is the middleware function being undefined. This is because inside your swagger.ts file, you specified swaggerUi.server as the middleware function but it needs to be changed to swaggerUi.serve.
import { Express } from 'express';
import swaggerUi from 'swagger-ui-express';
export default function startSwagger(app: Express) {
try{
const swaggerDocument = require('../build/swagger.json');
var options = {
explorer: true
};
// The problem was here... change server to serve
app.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerDocument, options));
}
catch(error){
throw new Error(error);
}
}
I'm trying to run my Angular app in Server Side Rendering via Angular Universal.
This is the JS file that Angular Universal generated, I just edited the path and port:
import 'zone.js/dist/zone-node';
import { ngExpressEngine } from '#nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import { AppServerModule } from './src/main.server';
import { APP_BASE_HREF } from '#angular/common';
import { existsSync } from 'fs';
// The Express app is exported so that it can be used by serverless Functions.
export function app() {
const server = express();
const distFolder = process.cwd();
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
// Our Universal express-engine (found # https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
server.set('view engine', 'html');
server.set('views', distFolder);
// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}));
// All regular routes use the Universal engine
server.get('*', (req, res) => {
res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
});
return server;
}
function run() {
const port = process.env.PORT || 4001;
// Start up the Node server
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run();
}
export * from './src/main.server';
The folder structure is fine, I run this on server:
> node .\server.js
Node Express server listening on http://localhost:4001
When I hit the site it just shows loading until it timeouts.
Express logs this on console:
DEPRECATED: DI is instantiating a token "ngmodule_material_carousel_MatCarouselHammerConfig" that inherits its #Injectable decorator but does not provide one itself.
This will become an error in v10. Please add #Injectable() to the "ngmodule_material_carousel_MatCarouselHammerConfig" class.
(node:6896) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
DEPRECATED: DI is instantiating a token "ngmodule_material_carousel_MatCarouselHammerConfig" that inherits its #Injectable decorator but does not provide one itself.
This will become an error in v10. Please add #Injectable() to the "ngmodule_material_carousel_MatCarouselHammerConfig" class.
Edit:
After removing the #ngmodule/material-carousel library from project I still get the Buffer warning but now I can see the website.
There is an open issue on github for that, it looks like the library does not support angular universal.
As a workaround, if you really want to use that library, you can avoid rendering the carousel if you are server side
component.html
<mat-carousel *ngIf="isBrowser" ></mat-carousel>
component.ts
import { isPlatformBrowser } from '#angular/common';
import {PLATFORM_ID} from '#angular/core';
public isBrowser: boolean;
constructor( #Inject(PLATFORM_ID) public platformId)
{
this.isBrowser = isPlatformBrowser(this.platformId);
}
The problem was the material-carousel library. I had to copy the necessary files from the project's GitHub to my project. The following files were needed:
carousel-slide.component.html
carousel-slide.component.scss
carousel-slide.component.ts
carousel-slide.ts
carousel.component.html
carousel.component.scss
carousel.component.ts
carousel.ts
_mixins.scss
These components require Angular Material so if you are not using the Angular Material in your project instead of ng add #angular/material which changes your project, run the following:
npm install #angular/material #angular/cdk #angular/animations
And finally add the necessary components to your module:
#NgModule({
declarations: [
...
MatCarouselComponent,
MatCarouselSlideComponent
],
imports: [
...
MatButtonModule,
MatIconModule
],
...
})
export class AppModule { }
I am trying to send a file to a NestJS controller but keep getting a too many parameters exception. I have installed bodyParser and updated the request size limit to get around a request too large exception.
main.ts:
import { NestFactory } from "#nestjs/core";
import { ApplicationModule } from "./app/app.module";
import * as express from "express";
import * as bodyParser from "body-parser";
async function bootstrap() {
const server = express();
server.use(bodyParser({limit: '50mb'}));
console.log(server);
const app = await NestFactory.create(ApplicationModule, server);
await app.listen(process.env.PORT || 3000);
}
bootstrap();
Controller:
import { Get, Controller, Query, Post, Request } from "#nestjs/common";
import { CloudVisionLogoService } from "./logos.component";
#Controller("logos")
export class LogoRecognitionController {
public constructor(
private readonly _logoRecognition: CloudVisionLogoService
) {
}
#Post()
public async detectLogos(#Request() req) {
console.log(req.files[0]);
// return await this._logoRecognition.detectLogos(imageUri);
}
}
Postman request (not shown, binary attachment of image):
POST /logos HTTP/1.1
Host: localhost:3000
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
Postman-Token: c95da069-c602-58a9-1e05-36456a527f02
undefined
The following is from body-parser docs:
This does not handle multipart bodies, due to their complex and
typically large nature. For multipart bodies, you may be interested in
the following modules:
busboy and connect-busboy
multiparty and connect-multiparty
formidable
multer
I suggest you to use multer package because it's easy and many users use it