How to get respond object in service? - nestjs

I want to use this package https://github.com/mashpie/i18n-node/blob/master/README.md in nestjs project.
How to get respond object in service for init module ?
i18n.init(req, res);
For request, I found it https://docs.nestjs.com/fundamentals/injection-scopes#request-provider

pass it from the controller
import {Response, Request} from 'express'
#Get(#Req() req: Request, #Res() res: Response) {
myService.method(req, res);
}

Related

NestJs include TypeORM repository in middleware

I have the following middleware to log all http requests:
#Injectable()
export class RequestMiddleware implements NestMiddleware {
constructor(
#InjectRepository(Request) private requestsRepository: Repository<Request>,
) {}
private readonly logger = new Logger('HTTP');
use(request: Request, response: Response, next: NextFunction) {
response.on('finish', () => {
const { method, originalUrl } = request;
const { statusCode, statusMessage } = response;
const message = `${method} ${originalUrl} ${statusCode} ${statusMessage}`;
return this.logger.log(message);
});
next();
}
}
My goal is to log all requests to a database. I am using TypeORM so I would like to inject the Request repository and log each request that way. When I do this I receive the following error:
Error: Nest can't resolve dependencies of the class RequestMiddleware
The issue is that this middleware isn't part of a module, it's just a single typescript file so how do I import the TypeORM repo module into a normal typescript file so I can use it?
In the module where RequestMiddleware is defined and used, TypeormModule.forFeature([Request]) needs to be added to the imports array

Nestjs - how to get session in middleware

im trying to add graphql to nestjs app. I use postgraphile for the graphql server.
everything works, but i don't know how to protect the '/graphql' endpoint.
the login is done via session, through the nestjs app.
on the needed endpoints (in the existed nestjs app) there is a Session guard which works fine.
i want to add the same behavior to the graphql endpoint.
this is the graphql code:
export const graphqlBootstrap = async (app: INestApplication) => {
app.use(cors());
// what i want to achieve
app.use('/graphql', (req, res, next) => {
if (!req.session.user) res.send('Authetication Error`);
next();
})
app.use(
postgraphile(...)
and the nestjs code the init it:
const bootstrap = async () => {
const { app, start } = await createApplication(TearupsApplicationModule);
app.useGlobalInterceptors(new ApiResponseInterceptor());
configureHiddenFileUploadEndpoint(app.getHttpAdapter());
await Promise.all(app.get(INITIATION_SEQUENCE).map((fn) => fn()));
await graphqlBootstrap(app); // <--
await start();
app.get(EventsEmitter).init(app);
};
is it possible to use the session in a middleware?
I don't know how to reach the ExecutionContext that exist in the Guard.
I read in the docs that there is also ArgumentsHost which might hold the session, but i also don't know how to get it in simple middleware(app.use(...))
Edit 1
i tried to add a middleware to the app module, with forRoutes call.
but the middleware isn't called with the graphql route /graphql.
also, when using route: / - there is no session on the request.
middleware:
export function Logger(req: any, res: Response, next: NextFunction) {
if (req.session) console.log(`Request...`, req.session.user);
next();
}
App Module:
export class MyApp implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(Logger).forRoutes('/');
}
Edit 2
tried this now, still didn't work:
export class MyApp implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(logger)
.forRoutes({ path: 'api/tearups/graphql', method: RequestMethod.ALL });
}
}
Write a functional middleware as follow signature:
import { Request, Response, NextFunction } from 'express';
export function Logger(req: Request, res: Response, next: NextFunction) {
console.log(`Request...`, req.session.user);
next();
};
Or, a class-based middleware as:
#Injectable()
export class Logger implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
console.log('Request...', req.session.user);
next();
}
}
Now apply the middleware as follows:
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(Logger)
.forRoutes(CatsController);
}
}

How to use csurf middleware in tsoa express?

I am new to tsoa and I want to do CSRF implementation in my node app. I have been able to make api using app.use() but I want to write in tsoa. Is there any way?
In the pre-released version, you can use the #Middlewares() decorator.
Just put what you had in a app.use() to the #Middlewares() decorator.
You can define your Middleware / Middlewares like this:
import { Request, Response, NextFunction } from 'express';
// ... controller logic ...
// #Get('/endpoint') | #Post('/endpoint') etc.
#Middlewares([
(req: Request, res: Response, next: NextFunction) => {
console.log(req.headers);
next();
},
(req: Request, res: Response, next: NextFunction) => {
console.log('Second middleware, but we can also use only one!');
next();
},
])
// getEndpoint(): string {
// return 'Hello World!';
// }
// ... controller logic ...
Also remember to have set the experimentalDecorators to true in your tsconfig.json.1
1 https://github.com/lukeautry/tsoa/pull/1123#issuecomment-1018251162

How to access Response object in NestJS GraphQL resolver

How can I access pass #Res() into my graphql resolvers?
this doesn't work:
#Mutation(() => String)
login(#Args('loginInput') loginInput: LoginInput, #Res() res: Response) {
return this.authService.login(loginInput, res);
}
#Res() is for HTTP Requests. To access to res object you'd need to first make sure it is added to the context for graphql by using context: ({ req, res }) => ({ req, res }) in the GraphqlModule's options, and then you can use #Context() ctx to get the context and ctx.res to get the response object

Wrapper for async handlers in Express with custom request properties

As demonstrated on https://strongloop.github.io/strongloop.com/strongblog/async-error-handling-expressjs-es7-promises-generators/#using-es7-asyncawait, I wanted to use a wrapper for all my async Express handlers to catch any errors happening there, but in a typed version for TypeScript.
I came up with this: (wrap.ts)
import { NextFunction, RequestHandler, Response, Request } from 'express';
type AsyncRequestHandler = (req: Request, res: Response, next: NextFunction) => Promise<any>;
/**
* Catches errors and passes them to the next callback
* #param handler Async express request handler/middleware potentially throwing errors
* #returns Async express request handler with error handling
*/
export default (handler: AsyncRequestHandler): RequestHandler => {
return (req, res, next) => {
return handler(req, res, next).catch(next);
};
};
I want to build a REST API with some endpoints like PUT /users/:userId and DELETE /users/:userId. For convenience, I don't want to query the specific user with the ID userId from the database in every handler and instead store it in req using a middleware. That means I have to use a modified Request interface for the handler definition adding a user property, e.g. UserRequest.
import express, { Request } from 'express';
import wrap from './wrap';
const app = express();
app.use('/users/:userId', wrap(async (req, res, next) => {
// set req.user ...
}));
export interface UserRequest extends Request {
user: User;
}
app.put('/users/:userId', wrap(async (req: UserRequest, res) => {
// do something with req.user ...
}));
// ...
This would be possible when not using wrap, but not with this type definition of wrap. The TypeScript compiler produces the following error:
Argument of type '(req: UserRequest, res: Response) => Promise<void>' is not assignable to parameter of type 'AsyncRequestHandler'.
Types of parameters 'req' and 'req' are incompatible.
Type 'Request' is not assignable to type 'UserRequest'.
Property 'user' is missing in type 'Request'.
What is the "TypeScript way" to accomplish this?
I somehow didn't realize that the issue appears without wrap as well (as long as the strict compiler option is enabled). My solution was to extend the express.Request interface.

Resources