Running two NestJS applications in the same process - node.js

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.

Related

fastify-swagger is not picking up my dynamic routes

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.

Nodej.s routing with express.js and TypeScript

I have question about node.js routes. Which routing version is correct?
First version it's a standard version in express.js:
router.get('/packages/:name', (req, res) => {
//my example code
);
Second version with TypeScript. This version is from typeorm init command.
export const Routes = [{
method: "post",
route: "/user",
controller: CustomerController,
action: "createUser"
}];
Which version is better and why? About the second version, how i can add custom middleware? What is difference between first and second version?
Both the approaches are same. When you have a lot of routes for a single point like root/apiv1/[here all the routes] then the second
one is preferable, if you have many dynamic routes, so its better to
go with the first approach.
Talking about the language, you can achieve both kind of routing in
plane JS and also in JS. But due to typecasting and validations,
preferred language is typescript and way of routing depends on the situation.
Talking about the middleware, for the first approach we will pass the
middleware just before the controller function, and for the second
approach, we are bascially creating structures for our routes and we need to
pass these routes to some route() end point, there we will
define the middleware just like we are doing in the first approach.

Axios calls not working with localhost in production

My title states my problem, but I'm actually looking for a best practice. In the case of my current project I'm using a vue.js app to call out to a nodejs server I have running on the same box. In development I just hardcoded http://localhost/api/etc.... into my axios calls and figured since I was deploying both in production to live on the same box too, that would be fine, but once I deployed I started getting 404s for the axios calls. I had to refactor my code to use the actual dns name of the server.
It works now because of that, but I feel like I'm missing something. I'm not sure if it's a node (for api server) or apache (hosting frontend) issue.
What's the best way to deal with urls?
Usually people create a module which exports a custom axios instance with a baseUrl. I think that it is a good practice because you can call the endpoints with the relative url only and centralize the api url in a single place as well, making it easier to switch between development and production urls.
my-api-client.js
import axios from 'axios';
export const MyApiClient = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
app.js
import { MyApiClient } from './my-api.js';
MyApiClient.get('my-collection').then(...
If your javascript version doesn't support import and export statements, you can use require and module.exports respectively.

How to use CAS authentication with angular2 webpack starter typescript?

I am using the following:
https://github.com/gdi2290/angular-starter
I start the application with npm start that uses webpack dev server. My issue is I want to add CAS authentication, but have no idea where what goes. This is the library I am trying to use:
https://github.com/TencentWSRD/connect-cas2
All the examples appear to use express, though I am not sure if I can use this with the webpack-dev-server as is with the starter I am using? If so, how do I use it? Or do I need a different CAS library that is compatible with the npm start?
Webpack is more of a build tool with minimal server capability. It can serve static content making it perfect for updating content on the fly and put together simple websites with basic routing and client side side logic.
If you want anything even a little more complex you will need a server side technology. So the connect-cas2 will require you to use node.js and express. The documentation shows you exactly how to set it up.
I don't know anything about connect-cas2 but I know passport for authentication, but they wouldn't be terribly different. I would follow the quick start and if you have any issues then edit your question with the code that you are having issues with or have trouble understanding.
I have been digging around and you might be able to proxy the authentication if you already have a CAS server setup somewhere. I would try the following:
// the proxy option is part of the devServer in your webpack.config.js
devServer: {
contentBase: 'public',
// setup a proxy
proxy: {
// just replace the /cas/validate endpoint to the endpoint in your
// website that will trigger the api call
'/cas/validate': 'https://url-to-your-cas-server.com'
}
},

Sails.js: best way to package DB and surrounding API models as module

I'm new to Sails, but have used Express, and am considering Sails for my upcoming project. I particularly like that it makes the CRUD API for me and connects Socket.io automatically.
The next application I'm planning to work on has an indeterminate size; if it works well, we want to separate our CRUD/JSON API from our Web/HTTP server and load balance the Web/HTTP server. This would allow us to utilize the CRUD/JSON API in other adjacent applications, like code for statistical analysis, or external data parsers which import data, or other things which have nothing to do with Web/HTTP servicing.
In express I would consider making the API section a module then export the express.router with all the api calls like so
//appAPI.js
var routes = require('express').router();
routes.get('/user/:id', function(request, reply){
// assume db is connected database object
// and request.params.id is as expected
db.getUser(request.params.id, function(u){
reply.json(u);
});
})
module.exports = routes;
//app.js
var app = require('express')(),
api = require('appAPI');
app.use('/api', api);
Then in my application, if I want to separate the Web from the API, I can package up the appAPI.js, and associated model code, and make a small connector to redirect all routes /api/* to the ip address and port of the api server, or other possibilities.
Can I do something like this in Sails? It seems that the automated model creation and the socket.io automation would make this difficult. Alternatively, I might be able to make a module for the API with a whole sails server then embed it in the main Web/HTTP server, which has its own sails objects running, but this seems like it either would not work, break the socket.io connections, or work, but be horribly inefficient as it would have multiple instances of sails running.
Any recommendations would be helpful and I'm willing to consider alternative ways of working this. Thank you all for any help you might provide and have a wonderful day.

Resources