Here's my problem: I have an API in NestJS, it is hosted on Firebase (Cloud functions). My client is an Ionic - Angular web interface.
"@nestjs/cli": "^7.5.1",
"@types/node": "^14.14.6",
"typescript": "^4.0.5"
When I test the application locally with the command npm run start
everything works fine.
When I test in production with firebase serve --only functions
or firebase deploy --only functions
, I get the following error (on browser) when launching the server :
Some of them are good, the other not.
here is a bad one:
and a good one:
Once the first slave of requests is made, everything will run again for the next 5 minutes.
You'll tell me that it's not serious, I just have to make the requests when I put the API in production and the users will be able to use it normally. Except that when the functions are not used for about 5 minutes, the API in production pauses, then it restarts as soon as it receives a request. This behavior seems normal to me, but because of errors and therefore inconsistencies in the results on the interface.
Here is my index.ts on my NestJS api:
const server = express();
export const createNestServer = async (expressInstance) => {
const app = await NestFactory.create(
AppModule,
new ExpressAdapter(expressInstance),
);
const whitelist = [
'http://localhost:8100/',
'http://localhost:8100',
'*',
undefined,
];
app.enableCors({
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
console.log('allowed cors for:', origin);
callback(null, true);
} else {
console.log('blocked cors for:', origin);
callback(new Error('Not allowed by CORS'));
}
},
allowedHeaders:
'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept, Observe',
methods: 'GET, OPTIONS',
credentials: true,
preflightContinue: true,
optionsSuccessStatus: 200,
});
return app.init();
}
createNestServer(server)
.then((v) => console.log('Nest Ready'))
.catch((err) => console.error('Nest broken', err));
export const api = functions.https.onRequest(server);
My question is this: How can I make sure that the cors are activated from the beginning when the server is launched and do not return an error at launch?
SOLUTION :
Thanks to NeatNerd, here is the solution : Tutorial to follow : https://softwarebrothers.co/blog/setting-up-nestjs-with-firebase-functions/
my new index.ts :
import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';
import { AppModule } from './app.module';
import * as express from 'express';
import * as functions from 'firebase-functions';
const server = express();
export const createNestServer = async (expressInstance) => {
const app = await NestFactory.create(
AppModule,
new ExpressAdapter(expressInstance),
);
const whitelist = [
'http://localhost:8100/',
'http://localhost:8100',
'*',
undefined,
];
app.enableCors({
origin: function (origin, callback) {
console.log(origin);
if (whitelist.filter((x) => x && x.startsWith(origin))) {
console.log('The CORS policy for this site allow access from ', origin);
callback(null, true);
} else {
console.log(
'\n\n\nThe CORS policy for this site does not allow access from ',
origin,
);
callback(
new Error(
'\n\n\n\n\n The CORS policy for this site does not allow access from ' +
origin,
),
false,
);
}
},
allowedHeaders:
'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept, Observe',
methods: 'GET, OPTIONS',
credentials: true,
preflightContinue: true,
optionsSuccessStatus: 200,
});
return app.init();
};
createNestServer(server)
.then((v) => console.log('Nest Ready'))
.catch((err) => console.error('Nest broken', err));
export const api = functions
.region('us-central1')
.https.onRequest(async (request, response) => {
await createNestServer(server);
server(request, response);
});
I was missing the reference to createNestServer for each call. The tutorial that allowed me to set it up doesn't have this part. However, it is still quite complementary. https://fireship.io/snippets/setup-nestjs-on-cloud-functions/
The following option is also part of the solution : (keepConnectionAlive)``
export const config: TypeOrmModuleOptions = {
type: 'mysql',
port: 3306,
host: 'xxx.xxx.xxx.xxxx',
database: 'name_of_the_database',
username: 'username',
password: 'password',
synchronize: false,
entities: [Entity1, Entity2],
autoLoadEntities: true,
keepConnectionAlive: true,
};
This allows to keep the connexion open.
You need to do two things:
firebase functions:log
. I am pretty sure there is something else going onWhen you start the deployment, the old function is up and running until the deployment is finished, so there will no disruption of service.
Additionally, since the error actually pointing out to CORS, you want also to have a look at how to set up this.