In my Node.js application I´m using fastify as framework together with some plugins (i18next).
I´m using i18next for translation (is working properly in preHandler and handler hooks) and want to customize all errors by using my translations via i18next in my custom error handler (via fastify setErrorHandler method).
Here is my coding so far (from top to bottom):
import fastify from "fastify";
import routes from "./routes/routes.js";
import i18next from "./config/i18next.js";
import i18nextMiddleware from "i18next-http-middleware";
const app = fastify({
logger: true,
ajv: {
customOptions: {
allErrors: true,
$data: true
}
},
});
app.register(i18nextMiddleware.plugin, { i18next });
app.register(routes, { prefix: '/api/v1' });
app.setErrorHandler((error, request, reply) => {
console.log('request.t: ', request.t);
if (error.validation) {
// other coding ...
reply.send(error);
}
});
(async () => {
try {
await app.listen(process.env.PORT);
console.log(`Server started listening on port ${process.env.PORT}`);
} catch (err) {
app.log.error(err);
}
})();
Inside the setErrorHandler (which is sync) I want to use the initialized t() method from i18next instance passed to request object (this is working for all my routes in the preHandler and handler hooks) but is not working in the setErrorHandler, as I´ll get undefined when an error occours.
I know the setErrorHandler is sync and all plugin registration will be handled async, but didn´t solved it yet.
What I´ve also tried is to do the setErrorHandler call in the after() hook when registering the i18next plugin, but the result is the same. I know I´m missing a small detail, but any tips are appreciated, as I´m spinning my head around this since hours.
This happens because the i18next-http-middleware plugin adds the t method to the request object on a preHandler hook that is executed after the JSON validation step:
export function plugin (instance, options, next) {
const middleware = handle(options.i18next, options)
instance.addHook('preHandler', (request, reply, next) => middleware(request, reply, next))
return next()
}
source
You should be able to write a workaround like this:
import i18nextMiddleware from "i18next-http-middleware";
// ....
const middleware = i18nextMiddleware.handle({})
app.addHook('preValidation', (request, reply, next) => middleware(request, reply, next))
I think that is a bug of the module tho
Related
I am working with NestJS and I need to know when a client has forced the disconnection or has canceled it. (either by mistake or because they wanted to).
For exaple, in Express it's as easy as:
const express = require('express')
const app = express()
const port = 3000
app.get('/', (expressRequest, expressResponse) => {
// Detecting close event
expressRequest.on('close', function() {
console.log('Client connection closed....!');
});
// Detecting end event
expressRequest.on('end', function() {
console.log('Client connection end....!');
});
expressResponse.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
The question is: working with NestJS, what is the correct way to do it?
The first thing I would try is using the #Req() param decorator. Assuming you're using Nests default Express adapter, then the request object received is the Express req object.
The following should work for you. The rest of this post is just cleaning it up and making it more "Nest".
import { Controller, Get, Req } from '#nestjs/common';
import { Request } from 'express';
#Controller()
export class AppController{
#Get()
test(#Req() req: Request): string {
req.on('close', () => console.log('Doing something with closed connection'))
return "Hello, world!"
}
}
If you're planning to reuse this logic in a few controller methods, then I would also consider creating a custom decorator for it:
import { createParamDecorator, ExecutionContext } from '#nestjs/common';
import { Observable } from 'rxjs';
import { Request } from 'express';
export const OnConnectionClosed = createParamDecorator(
(data: unknown, ctx: ExecutionContext) =>
new Observable((observer) => {
const request = ctx.switchToHttp().getRequest<Request>();
request.on('close', () => observer.complete());
}),
);
And then using it like the following:
#Controller()
export class AppController{
#Get()
test(#OnConnectionClosed() onClosed: Observable<void>): string {
onClosed.subscribe({
complete: () => console.log('Connection closed'),
});
return 'Hello, world!';
}
}
And with that, you've created your own "Nest" way to listen for close events on the incoming request.
Nestjs has many different components that are executed at different times during the life cycle of a request.
The order in which these components are executed would be the following
NestJs request Life cycle
Incoming request
Globally bound middleware
Module bound middleware
Global guards
Controller guards
Route guards
Global interceptors (pre-controller)
Controller interceptors (pre-controller)
Route interceptors (pre-controller)
Global pipes
Controller pipes
Route pipes
Route parameter pipes
Controller (method handler)
Service (if exists)
Route interceptor (post-request)
Controller interceptor (post-request)
Global interceptor (post-request)
Exception filters (route, then controller, then global)
Server response**
The answer to your question:
I think it should be detected in the following points
Global interceptor (post-request)
Controller interceptor (post-request)
I have a simple Express application that exposes a RESTful API. It uses Knex and Objection to access the database, and Jest / Supertest for testing the API.
I have a test that starts the server, fetches the available data from a given route and asserts the received values. Everything works fine, except that Jest never exits after executing this test.
This is my test:
import { app } from "../../src/application.js";
import { describe, expect, test } from "#jest/globals";
import request from "supertest";
describe("Customer Handler", () => {
test("should retrieve all existing customer(s)", async () => {
const expected = [
// ...real values here; omitted for brevity
];
const response = await request(app).get(`/api/customers`);
expect(response.statusCode).toStrictEqual(200);
expect(response.headers["content-type"]).toContain("application/json");
expect(response.body).toStrictEqual(expected);
});
});
The application.js file looks very much like a usual Express setup/configuration file:
import { CustomerHandler } from "./handler/customer.handler.js";
import connection from "../knexfile.js";
import express from "express";
import Knex from "knex";
import { Model } from "objection";
const app = express();
Model.knex(Knex(connection[process.env.NODE_ENV]));
// ...removed helmet and some other config for brevity
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use("/api/customers", CustomerHandler);
app.use((err, req, res, next) => {
res.status(err.status || 500);
res.json({
errors: {
error: err,
message: err.message,
},
});
next();
});
export { app };
I've tried --detectOpenHandles, but nothing else is printed in the console, so I can't see any hints about what the issue might be — which I suspect it's Knex / Objection because I'm using SQLite, so probably the connection to the database is not getting closed.
In the meantime I'm using --forceExit, but I would like to figure it out why is Jest not able to exit.
OK, looks like I was on the right track for this one.
Refactoring application.js to export the Knex object (after it's configured), and calling knex.destroy() after the test passes is the solution for this setup.
// application.js
...
const knex = Knex(connection[process.env.NODE_ENV]);
Model.knex(knex);
...
export { app, knex };
...then in the test(s), make sure you import knex and call destroy():
// customer.handler.test.js
import { app, knex } from "../../src/application.js";
import { afterAll, describe, expect, test } from "#jest/globals";
import request from "supertest";
describe("Customer Handler", () => {
afterAll(async () => {
await knex.destroy();
});
test("should retrieve all existing customer(s)", async () => {
const expected = [ /* ...real values here */ ];
...
expect(response.body).toStrictEqual(expected);
});
});
I was used to do the following in some of my express routes.
return res.sendStatus(200);
But the res object from NextApiHandlerType does not allow that method.
What would be the equivalent, in this case?
import { NextApiHandler } from "next";
const handler: NextApiHandler = async (req, res) => {
// DO STUFF
return res.??? // WHAT SHOULD I PUT HERE TO RETURN THE status CODE WITH THE STANDARD CODE MSG ?
};
I'm currently doing this, but it seems redundant.
return res.status(200).send("Ok");
From: http://expressjs.com/en/api.html
To anyone seeing this now, I was wondering the same thing. The docs aren't 100% clear IMO. This sends a status code and closes out the request.
res.status(200).end();
Here is what you can find in the documentation :
https://nextjs.org/docs/api-routes/response-helpers
The response (res) includes a set of Express.js-like methods to improve the developer experience and increase the speed of creating new API endpoints, take a look at the following example:
export default function handler(req, res) {
res.status(200).json({ name: 'Next.js' })
}
AFAIK, this is currently not possible inside a Next.js serverless function. I'm using "next": "10.1.3".
The closest alternative is, indeed:
return res.status(200).send("Ok");
I have a Bot running on botbuilder V3 where I am using a middleware explained here to intercept the messages.
bot.use({
botbuilder: function (session, next) {
myMiddleware.logIncomingMessage(session, next);
},
send: function (event, next) {
myMiddleware.logOutgoingMessage(event, next);
}
})
We are planning to migrate on sdk v4 so looking for similar capabilities in sdk v4. Are there any ?
I didn't find example on this page.
The BotAdapter base class exposes the use method to register middleware. So in your startup logic you'll create a specific implementation of a BotAdapter, typically BotFrameworkAdapter, and then add the middleware to it. Like so:
const botAdapter = new BotFrameworkAdapter( { /* credential stuff here*/ });
// Simple handler based
botAdapter.use(async (turnContext, next) => {
// pre logic
await next();
// post logic
});
// Or class based
botAdapter.use(new MyMiddleware());
I'm new to GraphQL and using graphqlExpress in my nodejs project.
const buildOptions = async (req, res) => {
const user = await authenticate(req, mongo.Users);
return {
formatError,
schema,
context: {dataloaders: buildDataloaders(mongo),mongo, user}, // This context object is passed to all resolvers.
};
};
app.use('/api', bodyParser.json(), graphqlExpress(buildOptions));
Resolver methods for Query, Mutations are implemented, but when I throw an Error object from any of the resolver methods then the error is not handled by graphqlExpress and node process is crashing. On debugging it stops at 'emitDestroyScript' method in async_hooks.js file of nodejs.
Any help to appreciated to address this issue.
Thanks