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
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.
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
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.
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
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'
}
}
});