I've been a fan of ExpressJs for a long time but in a Youtube video I stumble upon Fastify and wanted to give it a try
I'm struggling in making the fastify-swagger plugin work as I assume it should work - dynamic setup to pick up the schema from each route, but I'm certainly missing something 😔
here's my test repo that after running, none of my routes appear
my setup for the plugin is the default one
but all I see is
I've read in the read me that because of OpenAPI specs, some properties, like description are mandatory or will not pick up the route, but I've added in one route, and still does not pick up, I've also added tags wondering if that was also mandatory, but nothing...
does anyone know what am I missing? must be a simple thing, but got me puzzled this last few days 😔
I ran into the same issue and ended up solving it by following the first Usage example line-by-line: https://github.com/fastify/fastify-swagger#usage
const fastify = require('fastify')()
(async () => {
// set up swagger
await fastify.register(require('#fastify/swagger'), {
...swagger config
});
// define all your routes
// then call these
await fastify.ready()
fastify.swagger()
})();
Consider the order in which your plugins are loaded, the routes need to be registered before fastify swagger. If fastify swagger comes first, it doesn't detect any route.
I encountered this issue in my project. In my case, I solved it using fastify-plugin. Looking at the source code for fastify-swagger, it seems to rely on a hook listening for onRoute events to detect routes. I'm thinking maybe encapsulation can interfere with the plugin's ability to receive the events.
Related
I've been working with Express for a couple of years now and recently got introduced to NestJS. I decided to experiment and write an application on this, as it seemed to me, interesting framework.
I want my application to be able to handle the following routes:
General routes
/policy, /docs
API routes (with versioning)
/api/v1/users, /api/v1/chats
In Express, this is very easy to do, but as I understand it, in NestJS everything is different. As I understand from the documentation, in NestJS you cannot set the path prefix for the entire module. You can only set a global prefix for the entire application.
The documentation also talked about the RouterModule. But I didn’t like it, because it won’t be possible to enable versioning specifically for routes /api and the use of RouterModule itself is very inconvenient. As the application grows, using the RouterModule becomes a pain.
Then I tried to convert the application to a monorepository. It seems to be possible to achieve the desired functionality, but it seems inconvenient for me to run each part of the application separately. Perhaps it would be worth using concurrently, but in my opinion, this is also not the best option.
As a result, I came to the following solution.
The structure of my project at the moment looks like this:
project structure
The api directory will contain all modules related to the api (it will process /api/v1/... routes), and everything else will be in the core (it will process /docs, /policy routes, etc.).
In fact, everything is the same as when creating a monorepository, but I decided to run all this from a single main.ts
main.ts
And I have a question, what are the pitfalls of this solution? Will it affect performance? Are there any better options for solving my problem?
To enable versioning with NestJS :
const app = await NestFactory.create(AppModule);
app.enableVersioning({
type: VersioningType.URI,
});
await app.listen(3000);
Then, it's true that every routes will need version in URL: /v1/...
But you can use VERSION_NEUTRAL to mark default endpoint version :
Some controllers or routes may not care about the version and would
have the same functionality regardless of the version. To accommodate
this, the version can be set to VERSION_NEUTRAL symbol.
An incoming request will be mapped to a VERSION_NEUTRAL controller or
route regardless of the version sent in the request in addition to if
the request does not contain a version at all.
So, for example, here, route /v1/users for Users V1 only :
#Controller({
version: '1',
})
export class UsersControllerV1 {
#Get()
getUsers()...
}
and another route (controller) without any version :
#Controller({
version: VERSION_NEUTRAL,
})
export class PolicyController {
#Get()
getPolicy()...
}
Note that it's possible to provide more than one unique version :
version: ['1', VERSION_NEUTRAL]
More details on official docs.
I want to extend this open topic: Add Routes at Runtime (ExpressJs) which sadly didn't help me enough.
I'm working on an application that allows the creation of different API's that runs on NodeJs. The UI looks like this:
As you can see, this piece of code contains two endpoints (GET, POST) and as soon as I press "Save", it creates a .js file located in a path where the Nodejs application is looking for its endpoints (e.g: myProject\dynamicRoutes\rule_test.js).
The problem that I have is that being that the Nodejs server is running while I'm developing the code, I'm not able to invoke these new endpoints unless I restart the server once again (and ExpressJs detects the file).
Is there a way to register new routes while the
NodeJs (ExpressJs) is running?
I tried to do the following things with no luck:
app.js
This works if the server is restarted. I tried to include this library (express-dynamic-router, but not working at runtime.)
//this is dynamic routing function
function handleDynamicRoutes(req,res,next) {
var path = req.path; //http://localhost:8080/api/rule_test
//LoadModules(path)
var controllerPath = path.replace("/api/", "./dynamicRoutes/");
var dynamicController = require(controllerPath);
dynamicRouter.index(dynamicController[req.method]).register(app);
dynamicController[req.method] = function(req, res) {
//invocation
}
next();
}
app.all('*', handleDynamicRoutes);
Finally, I readed this article (#NodeJS / #ExpressJS: Adding routes dynamically at runtime), but I couldn't figure out how this can help me.
I believe that this could be possible somehow, but I feel a bit lost. Anyone knows how can I achieve this? I'm getting a CANNOT GET error, after each file creation.
Disclaimer: please know that it is considered as bad design in terms of stability and security to allow the user or even administrator to inject executable code via web forms. Treat this thread as academic discussion and don't use this code in production!
Look at this simple example which adds new route in runtime:
app.get('/subpage', (req, res) => res.send('Hello subpage'))
So basically new route is being registered when app.get is called, no need to walk through routes directory.
All you need to do is simply load your newly created module and pass your app to module.exports function to register new routes. I guess this one-liner should work just fine (not tested):
require('path/to/new/module')(app)
Is req.params enough for you?
app.get('/basebath/:path, (req,res) => {
const content = require('content/' + req.params.path);
res.send(content);
});
So the user can enter whatever after /basepath, for example
http://www.mywebsite.com/basepath/bergur
The router would then try to get the file content/bergur.js
and send it's contents.
Is there a way to access or delete middleware in connect or express that you already defined on the same instance? I have noticed that under koa you can do this, but we are not going to use koa yet because it is so new, so I am trying to do the same thing in express. I also noticed that it is possible with connect, with somewhat more complicated output, but connect does not have all the features I want, even with middleware.
var express = require('express');
var connect = require('connect');
var koa = require('koa');
var server1 = express();
var server2 = connect();
var server3 = koa();
server1.use(function express(req, res, next) {
console.log('Hello from express!');
});
server2.use(function connect(req, res, next) {
console.log('Hello from connect!');
});
server3.use(function* koa(next) {
console.log('Hello from koa!');
});
console.log(server1.middleware);
// logs 'undefined'
console.log(server2.middleware);
// logs 'undefined'
console.log(server2.stack);
logs [ { route: '', handle: [Function: connect] } ]
console.log(server3.middleware);
// logs [ [Function: koa] ]
koa's docs say that it added some sugar to its middleware, but never explicitly mentions any sugar, and in particular does not mention this behavior.
So is this possible in express? If it is not possible with the vanilla version, how hard would it be to implement? I would like to avoid modifying the library itself. Also, what are the drawbacks for doing this, in any of the 3 libraries?
EDIT:
My use case is that I am essentially re-engineering gulp-webserver, with some improvements, as that plugin, and all others like it, are blacklisted. gulp is a task runner, that has the concept of "file objects", and it is possible to access their contents and path, so I basically want to serve each file statically when the user goes to a corresponding URL in the browser. The trouble is watching, as I need to ensure that the user gets the new file, and not the old version. If I just add an app.use each time, the server would see the file as it is originally, and never get to the middleware with the new version.
I don't want to restart the server every time a file changes, though I will if I can find no better way, so it seems I need to either modify the original middleware on the fly (not a good idea), delete it, or add it to the beginning instead of the end. Either way, I first need to know where it "lives".
You might be able to find what your looking for in server1._router.stack, but it's not clear what exactly you're trying to do (what do you mean "access"?).
In any case, it's not a good idea to do any of these, since that relies strictly on implementation, and not on specification / API. As a result any and all assumptions made regarding the inner implementation of a library is eventually bound to break. You will eventually have to either rewrite your code (and "reverse engineer" the library again to do so), or lock yourself to a specific library version which will result in stale code, with potential bugs and vulnerabilities and no new features / improvements.
I would like to return localized Strings for multilanguage business objects in our RestFul API based on node.js, restify and mongoose. I have the requirement to store the translated resources on our translation resource server, but also need to support dynamic creation of those business objects.
I found a solution to easily plugin the i18n process in the POST/PUT calls using a single pre-'save' mongoose middleware on all Schema, when creating or updating my multi-languate business objects - this works because I am able to pass the request context to the obj.save(req, callback) call.
But, I am struggling to plug in the i18n on simple GETs. I thought of and tried different ways where I can plugin the i18n before returning the response, but don't really find a good way. Options I thought of:
translate in a mongoose middleware pre /post ('init'):
Problem: I don't have access to the request context, and therefore
don't know the locale to return, so I cannot translate there.
translate in the toObject() / toJSON {transform: }:
Same issue - i don't have the request context in these hooks.
translate in the handler/controller methods for each ressource.
Problem: Duplication, I have to do it everywhere, I would really prefer a solution I can define on the model/Schema layer
translate in a restify / express middleware towards the end:
Problem: I don't have access to the mongoose schema metainformation anymore, so I don't know which attriutes to translate.
Edit: just found this additional way:
- translate in a custom restify responseFormatter:
This seems to work nicely, in the reponseformatter I have access to everything I need. It kind of seems a little weird from an architechtural point of view, but if nobody has a better idea, I will add this as an answer.
Maybe (hopefully) I am missing something obvious...
thanks for any hints
I'm working with expressjs and socket.io in nodejs. I'm looking into assign identical route handlers to requests made in either HTTP or via websockets/socket.io.
For instance:
var responder = function(req, res){
req.params //<-- {id: 'something...'}
}
app.get('/foo/:id', responder);
io.on('/foo/:id', responder);
socket.io doesn't appear to have this type of routing functionality. Does anyone know of a library/module to help with this?
There are several options.
If you'd like to keep using express, check out express.io.
If you don't mind using something a bit different, sails lets you do this sort of thing as well.
(Update: sails now uses express too)
Both have been used in production successfully.
Note that routing is also pretty simple to implement on your own. If you check out how express do it I'm sure you'll be able to figure out a slim implementation that would match you needs.
Good luck! Let me know what you ended up using and how it worked for you.