Hapi catbox not able to connect to redis server - node.js

First of all, I would like to say that I'm new to Hapi so don't judge me hard.
I am following this tutorial trying to set up server-side caching based on Redis using catbox and catbox-redis npm packages, and I get the following error:
{
reason: Error: Connection is closed.
at Redis.connectionCloseHandler (/home/yuriy/dev/sources/all/hapi-getting-started/node_modules/ioredis/built/redis/index.js:305:24)
at Object.onceWrapper (events.js:300:26)
at Redis.emit (events.js:210:5)
at processTicksAndRejections (internal/process/task_queues.js:75:11)
}
As you can see it says that error is in ioredis (v4.14.1 according to package-lock.json) package which is dependency of catbox-redis.
I have Redis server running locally.
username#my-computer:~$ redis-cli -v
redis-cli 4.0.9
username#my-computer:~$ redis-cli
127.0.0.1:6379> ping
PONG
Here is my package.json:
{
"name": "hapi-getting-started",
"version": "1.0.0",
"description": "",
"main": "src/index.ts",
"scripts": {
"build": "rimraf dist && tsc",
"start": "rimraf dist && tsc && node dist/index.js",
"dev": "tsc -w | nodemon dist/index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"#hapi/catbox": "^10.2.3",
"#hapi/catbox-redis": "^5.0.5",
"#hapi/hapi": "^18.4.0",
"rimraf": "^3.0.0",
"typescript": "^3.7.2"
},
"devDependencies": {
"#types/hapi__catbox": "^10.2.2",
"#types/hapi__catbox-redis": "^5.0.0",
"#types/hapi__hapi": "^18.2.6",
"#types/node": "^12.12.14",
"nodemon": "^2.0.1"
}
}
And here is my src/index.ts:
const Hapi = require('#hapi/hapi');
const CatboxRedis = require('#hapi/catbox-redis');
console.log(`Running environment ${process.env.NODE_ENV || 'dev'}`);
// Catch uncaught exceptions
process.on('uncaughtException', (error: Error) => {
console.error(`uncaughtException ${error.message}`);
console.error({ reason });
});
// Catch unhandled rejected promises
process.on('unhandledRejection', (reason: any) => {
console.error(`unhandledRejection ${reason}`);
console.error({ error });
});
const init = async () => {
const server = Hapi.server({
host: 'localhost',
port: 8000,
cache: {
name: 'redis-cache',
provider: {
constructor: CatboxRedis,
options: {
partition: 'my_cached_data',
tls: {},
},
},
},
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
init();
Any ideas what I am doing wrong? I've spent a lot of time on this issue so any help would be very appreciated.

Okay, it appears that there is an issue in Hapi official docs on caching (Server-side Caching section). The solution was very simple but not obvious: I just removed tls: {},.
const server = Hapi.server({
host: 'localhost',
port: 8000,
cache: {
name: 'redis-cache',
provider: {
constructor: CatboxRedis,
options: {
partition: 'my_cached_data',
// tls: {}, <-- Here is a problem, remove this line
},
},
},
});
This is ioredis config params. From catbox-redis docs:
tls - an object representing TLS config options for ioredis.
You can find more details in ioredis docs.

Related

MangoDB Compass can not connect to my backend using TypeORM

I am trying to create a simple web application where I can diplay users from a MongoDB database on a React web application.
However I am stuck on a problem with TypeORM and my MongoDB database. Indeed, my backend repository can not access to the database.
Here is my package.json file :
{
"name": "backend",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"build": "tsc",
"dev": "nodemon index.ts",
"start": "node ./dist/index.js",
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/.bin/typeorm",
"migration:generate": "npm run typeorm -- migration:generate --config src/config/ormconfig.json --connection --name ",
"migration:run": "npm run typeorm -- migration:run"
},
"license": "UNLICENSED",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"mongodb": "^3.6.0",
"typeorm": "^0.3.11"
},
"devDependencies": {
"#types/cors": "^2.8.13",
"#types/express": "^4.17.14",
"#types/mongodb": "^4.0.7",
"#types/node": "^18.11.8",
"nodemon": "^2.0.20",
"ts-node": "^10.9.1",
"typescript": "^4.8.4"
}
}
Here is my connectionService.ts file, which is supposed to create the connection to the database :
import { DataSource, DataSourceOptions } from "typeorm"
import { Utilisateurs } from "../entities/utilisateurs";
class connectionServices{
public myDataSource:DataSource;
constructor(dbConfig: DataSourceOptions){
this.myDataSource = new DataSource(dbConfig)
}
public async getUsers (){
const myusers = this.myDataSource.getMongoRepository(Utilisateurs);
const data = await myusers.find({});
console.log (data);
return data;
}
}
export default (connectionServices);
Here is my index.ts file :
import express from 'express';
import cors from 'cors';
import connectionServices from "./service/connectionService";
function main() {
const app = express();
const service = new connectionServices({
type: "mongodb",
url: "mongodb://localhost:27017",
port: 27017,
database: "users",
synchronize: true,
entities: [
"src/entities/**/*.ts"
],
});
app.use(cors())
app.get('/users/:id', function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
app.get('/', (req, res) => {
res.send('Well done!');
})
app.listen(4321, () => {
console.log('The application is listening on port 4321!');
})
app.get('/users', (req,res) => {
res.send(service.getUsers());
})
}
main();
And finally here is my ormconfig.json file :
{
"type": "mongodb",
"host": "localhost",
"url": "mongodb://localhost:27017",
"port": 27017,
"database": "test",
"synchronize": true,
"logging": false,
"entities": [
"src/entity/**/*.ts"
],
"migrations": [ "src/migration/**/*.ts"
],
"subscribers": [ "src/subscriber/**/*.ts"
],
"cli": {
"entitiesDir": "src/entity", "migrationsDir": "src/migration", "subscribersDir": "src/subscriber"
}
}
The backend builds and launches properly :
However when I type in the url http://localhost:4321/users, I get this error in my terminal and the backend crashes :
I have tried to put the url of the data base, or put the parameter "host": "localhost" with the correct port but nothing worked.
I have looked on several tutorials, videos without success...
If someone sees the solution to my problem that would be great!
You didn't provide your entities. however, I think the problem occurred because typeorm couldn't find your entities.
try changing src/entity/**/*.ts to src/entity/**/*{.ts,.js}.
Do the same thing for migration and subscribers if needed.
In fact the problem was in the index.ts file and in the connectionService.ts file.
In the service, it was missing a function in order to connect to the data base :
import { createConnection, DataSource, DataSourceOptions } from "typeorm"
import { Utilisateurs } from "../entities/utilisateurs.entity";
class connectionServices{
public myDataSource:DataSource;
async connect(){
await this.myDataSource.connect();
}
constructor(dbConfig: DataSourceOptions){
this.myDataSource = new DataSource(dbConfig);
}
public async getUsers (){
const myusers = this.myDataSource.getMongoRepository(Utilisateurs);
const data = await myusers.find({});
console.log (data);
return data;
}
}
export default (connectionServices);
And in the index.ts file, I was calling the promise of a table containing the date, and not the data. Here is the working file :
import express from 'express';
import cors from 'cors';
import connectionServices from "./service/connectionService";
import { Utilisateurs } from './entities/utilisateurs.entity';
async function main() {
const app = express();
const service = new connectionServices({
type: "mongodb",
host: "localhost",
port: 27017,
database: "users",
synchronize: true,
entities: [
Utilisateurs
],
});
await service.connect();
app.use(cors())
app.get('/users/:id', function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
app.get('/', (req, res) => {
res.send('Well done!');
})
app.listen(4321, () => {
console.log('The application is listening on port 4321!');
})
app.get('/users', async(req,res) => {
res.send(await service.getUsers());
})
}
main();
With these modifications, everything works properly.

Error When Writing Files in Node Environment with Next.js Deployed on Serverless Cloud Functions

I am building a Next.js app using the version 12.1.6 and Firebase Cloud Functions as a serverless function.
In the local environment, it works without any problem, but after it's deployed, it returns Failed to load resource: the server responded with a status of 503 () to the client. And there is an error message in the functions log saying:
Error: EROFS: read-only file system, unlink '/workspace/dist/next/BUILD_ID'] {
errno: -30,
code: 'EROFS',
syscall: 'unlink',
path: '/workspace/dist/next/BUILD_ID'
}
From the error log, it seems that Next.js somehow tries to do write operations in the node environment. But Firebase Cloud Functions does not accept any writing operations except /temp directory. It only allows read operation.
Maybe I just should deploy to other hosting like Vercel.
But can older versions resolve this issue? Because I am using the version 9.3 in another Firebase project and it works fine.
I would like to know how to avoid this error using the latest Next version and Firebase Cloud Functions?
packag.json
"engines": {
"node": "16"
},
"dependencies": {
"firebase-admin": "^10.0.2",
"firebase-functions": "^3.20.1",
"next": "^12.1.6",
"react": "17.0.2",
"react-dom": "17.0.2"
},
"devDependencies": {
"#types/node": "17.0.13",
"#types/react": "17.0.38",
"eslint": "8.8.0",
"eslint-config-next": "12.0.9",
"typescript": "4.5.5"
}
firebase.json
{
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"functions": {
"source": ".",
"predeploy": ["npm run build"],
"runtime": "nodejs16"
},
"hosting": {
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{
"function": "nextHosting",
"source": "**"
}
]
}
}
upgrade to Cloud function v2 which allows writable actions everywhere.
const { join } = require('path')
const {onRequest} = require("firebase-functions/v2/https");
const { default: next } = require('next')
const nextjsDistDir = join('src', require('./src/next.config.js').distDir)
// https://stackoverflow.com/questions/65601999/fetching-an-image-from-firebase-storage-using-next-image-results-in-a-400-status
const nextjsServer = next({
dev: false,
conf: {
distDir: nextjsDistDir,
images: {
domains: [
'www.notion.so',
'notion.so',
'images.unsplash.com',
'pbs.twimg.com',
'abs.twimg.com',
's3.us-west-2.amazonaws.com',
'fiery-artifact-342404.web.app',
'yihui.dev',
'fiery-artifact-342404.firebaseapp.com',
'yihuihe.notion.site',
'localhost',
'127.0.0.1',
],
}
},
})
const nextjsHandle = nextjsServer.getRequestHandler()
exports.nextjsfunc = onRequest({cors: true}, (req, res) => {
return nextjsServer.prepare().then(() => nextjsHandle(req, res))
})
long answer here:
https://yihui.dev/firebase-hosting-with-nextjs-and-cloud-functions

How do I solve "Middleware "strapi::session": App keys are required" error in my deployment of Strapi to Heroku?

I'm following the official instructions to deploy my strapi starter app to Heroku. The app runs fine locally. The only thing I left out in my deployment instructions were installing the PG node module (it is already installed because my local app uses Postgresql).
Accessing the Heroku logs, I see this:
error: Middleware "strapi::session": App keys are required.
Please set app.keys in config/server.js (ex: keys: ['myKeyA', 'myKeyB'])
Maybe this is an important detail: I followed this process once, and everything worked. I was able to deploy to Heroku. I tried it again and it didn't work. I was thinking maybe Heroku had a problem with me re-using an app name, but I tried to name the app something different in Heroku and I still had the same error.
Is heroku looking in the wrong place for my server.js file? Should it be looking in my "./config/env/production" folder instead of my "./config" folder?
Per the instructions, here is my ./config/env/production/database.js
const parse = require('pg-connection-string').parse;
const config = parse(process.env.DATABASE_URL);
module.exports = ({ env }) => ({
connection: {
client: 'postgres',
connection: {
host: config.host,
port: config.port,
database: config.database,
user: config.user,
password: config.password,
ssl: {
rejectUnauthorized: false
},
},
debug: false,
},
});
Here is my ./config/env/production/server.js
module.exports = ({ env }) => ({
url: env('MY_HEROKU_URL'),
});
And here is my ./config/server.js
module.exports = ({ env }) => ({
host: env('HOST', '0.0.0.0'),
port: env.int('PORT', 1337),
app: {
keys: env.array('APP_KEYS'),
},
});
my package.json for good measure:
{
"dependencies": {
"#strapi/plugin-graphql": "^4.0.0",
"#strapi/plugin-i18n": "4.0.6",
"#strapi/plugin-users-permissions": "4.0.6",
"#strapi/strapi": "4.0.6",
"lodash.set": "^4.3.2",
"pg": "8.6.0",
"pg-connection-string": "^2.5.0"
},
"name": "backend",
"private": true,
"version": "0.1.0",
"description": "A Strapi application",
"scripts": {
"develop": "strapi develop",
"start": "strapi start",
"build": "strapi build",
"strapi": "strapi"
},
"devDependencies": {},
"author": {
"name": "A Strapi developer"
},
"strapi": {
"uuid": "f64b509e-2d95-4464-8d39-d6f0d1c7a31a",
"template": "#strapi/template-corporate#^1.0.0",
"starter": "#strapi/starter-next-corporate"
},
"engines": {
"node": ">=12.x.x <=16.x.x",
"npm": ">=6.0.0"
},
"license": "MIT"
}
I'm running Node v14.18.3 and NPM v6.14.15
I solved it with this in ./config/env/production/server.js
module.exports = ({ env }) => ({
url: env("MY_HEROKU_URL"),
proxy: true,
app: {
keys: env.array("APP_KEYS", ["testKey1", "testKey2"]),
},
});
testKey1, testKey2 are just placeholders and need to be replaced by 2 random keys via CONFIG VAR in heroku
APP_KEYS=someSecret,anotherSecret
proxy: true was also important. Else it throws a Cannot send secure cookie over unencrypted connection
just create .env file in root of your project like this:
HOST=0.0.0.0
PORT=1337
APP_KEYS=jP8pb1lYsAhnmURarewxhA==,34xnLMYHY5jiU7ONTstTqQ==
On Heroku, for that particular app, navigate to Settings->Config vars and add your environment variables there.
Adding the environment variables to your file as #Temo mentioned is not the right solution. Although it works it poses quite some security threats.
What you should do is add the APP_KEYS to your environment variables on Heroku.
You can generate a new key by creating a file with this code:
// filename: generateCode.js
const crypto = require('crypto')
console.log(crypto.randomBytes(16).toString('base64'))
and then running it from the console with:
node generateCode.js
The code it generates looks something like foP7OJcuRhCw1sTR6EfZPw==. Use that as your APP_KEY in Heroku.
So you just need to create a variable in Heroku settings->config vars called APP_KEYS. And value of this variable you can get from your .env file where you should have APP_KEYS variable with value.
Just remove .env from git ignore.
Then push again.

Is there any way to make an executable file (.exe) from a Nuxt+Node project?

I have a NuxtJS project that requires a NodeJS program running behind for some functions and logic. The project structure is as follows:
api
assets
components
layouts
middleware
pages
plugins
server
static
store
nuxt.config.js
package.json
nuxt.config.js
module.exports = {
head: {
titleTemplate: '%s',
title: 'Project',
htmlAttrs: {
lang: 'en'
},
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: '' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
css: [
'#/assets/css/main.scss'
],
plugins: [
],
components: true,
buildModules: [
'#nuxtjs/vuetify'
],
modules: [
'nuxt-socket-io',
'nuxt-i18n',
'#nuxtjs/axios',
'#nuxtjs/auth-next'
],
io: {
sockets: [
{
name: 'main',
url: process.env.APP_SERVER_URL,
default: true
}
]
},
i18n: {
locales: [
{
code: 'en',
file: 'en-US.js'
}
],
lazy: true,
langDir: 'lang/',
defaultLocale: 'en'
},
serverMiddleware: [
{ path: '/api', handler: '~/api/index.js' },
],
axios: {
baseURL: process.env.APP_SERVER_URL,
},
vuetify: {
customVariables: ['~/assets/variables.scss'],
theme: {
dark: true,
themes: {
dark: {},
light: {}
}
}
},
build: {
extend(config) {}
}
}
package.json
{
"name": "my-project",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "nodemon -w server -w nuxt.config.js server",
"build": "nuxt generate",
"start": "cross-env NODE_ENV=production node server",
"generate": "nuxt generate"
},
"dependencies": {
"#nuxtjs/auth-next": "5.0.0-1611574754.9020f2a",
"#nuxtjs/axios": "^5.12.5",
"body-parser": "^1.19.0",
"core-js": "^3.8.3",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"http": "0.0.1-security",
"moment": "^2.29.1",
"nuxt": "^2.14.12",
"nuxt-i18n": "^6.18.0",
"nuxt-socket-io": "^1.1.14"
},
"devDependencies": {
"#nuxtjs/vuetify": "^1.11.3",
"cross-env": "^7.0.3",
"nodemon": "^2.0.7"
}
}
server/index.js
require('dotenv').config();
const isProd = process.env.NODE_ENV === 'production'
const http = require('http')
const app = require('express')()
const server = http.createServer(app)
const io = require('socket.io')(server)
const axios = require('axios')
const { Nuxt, Builder } = require('nuxt')
const config = require('../nuxt.config.js');
config.dev = !isProd;
const nuxt = new Nuxt(config)
const { host, port } = nuxt.options.server
if (config.dev) {
const builder = new Builder(nuxt)
builder.build()
} else {
nuxt.ready()
}
app.use(nuxt.render)
server.listen(port, () => {
console.log(`Server listening on http://${host}:${port}`)
});
// other logic
I need an exe that can be installed in other computers for running the Nodejs server and the Nuxt stuff, like I run the code by npm run dev or npm run build/start in the development computer locally.
I have tried nexe by running nexe -i server but not succeeded. Is there any other way for me to do that?
Thank you.
I think you can take a look at pm2. You can run node server and other stuff with that.
Compiling a Node.js Application into an .exe File
Two of the most commonly used packages used to compile JavaScript files into executables are:
nexe: It is a simple command-line utility that compiles your Node.js application into a single executable file. By default, it converts it into a Windows executable.
pkg: It is a Node.js package that can convert your Node.js app into several executable files for various operating systems (all at once) or of an individual operating system.
enter link description here

How to install Deployd on AWS Elastic Beanstalk

I am trying to install deployd on AWS Elastic Beanstalk.
I created a node.js environment.
Locally, I did:
npm install depoyd -g
I also created a .dpd folder and did
dpd keygen
Here's my package.json file
{
"name": "my-api",
"version": "1.0.1",
"description": "My description",
"keywords": [],
"homepage": "http://www.example.com",
"author": "Me, Myslef and I",
"contributors": [],
"dependencies": {
"deployd": ">= 0"
},
"scripts": {
"start": "node server"
},
"engines": {
"node": "0.10.x",
"npm": "2.2.x"
}
}
Here's my server.js file
// requires
var deployd = require('deployd'); //API
// configure database etc.
var server = deployd({
port: process.env.PORT || 5000,
env: 'production',
db: {
host: 'ds12345.mongolab.com',
port: 12345,
name: 'my-api',
credentials: {
username: admin,
password: mypassword
}
}
});
// heroku requires these settings for sockets to work
server.sockets.manager.settings.transports = ["xhr-polling"];
// start the server
server.listen();
// debug
server.on('listening', function() {
console.log("Server is listening on port: " + process.env.PORT);
});
// Deployd requires this
server.on('error', function(err) {
console.error(err);
process.nextTick(function() { // Give the server a chance to return an error
process.exit();
});
});
Here is my ProcFile:
web: node server
When I create the zip file with the files and "upload and deploy" it into the dashboard, "Health" status is green but the app url shows
502 Bad Gateway
nginx/1.6.2
Thanks for your help
I just forgot the quotes in the credentials.
// configure database etc.
var server = deployd({
port: process.env.PORT || 5000,
env: 'production',
db: {
host: 'ds12345.mongolab.com',
port: 12345,
name: 'my-api',
credentials: {
username: 'admin',
password: 'mypassword'
}
}
});

Resources