Unable to connect to AWS RDS using Sequelize ORM - node.js

I am working on an application which uses the Sequelize ORM to connect to AWS RDS. I have my connection set up as such:
Connection
import {Sequelize} from 'sequelize-typescript';
// Instantiate new Sequelize instance!
export const sequelize = new Sequelize({
"username": "AWS RDS USER",
"password": "AWS RDS PASS",
"database": "postgres",
"host": "******.******.us-east-1.rds.amazonaws.com",
dialect: 'postgres',
storage: ':memory:',
});
I also have defined a model to represent the database table which is defined as such:
Model
import {Table, Column, Model, CreatedAt, UpdatedAt} from 'sequelize-typescript';
#Table
export class FeedItem extends Model<FeedItem> {
#Column
public caption!: string;
#Column
public url!: string;
#Column
#CreatedAt
public createdAt: Date = new Date();
#Column
#UpdatedAt
public updatedAt: Date = new Date();
}
and exported as such:
import { FeedItem } from './feed/models/FeedItem';
export const V0MODELS = [ FeedItem ];
Then within my server.ts I import my sequelize connection and model and attempt to connect to my AWS RDS as such:
server.ts
import express from 'express';
import { sequelize } from './sequelize';
import { IndexRouter } from './controllers/v0/index.router';
import { V0MODELS } from './controllers/v0/model.index';
(async () => {
try {
await sequelize.authenticate();
console.log('Connection has been established successfully.');
await sequelize.addModels(V0MODELS);
await sequelize.sync({ force: true, logging: console.log });
} catch (error) {
console.error(error);
}
const app = express();
const port = process.env.PORT || 8080; // default port to listen
app.use(express.json());
//CORS Should be restricted
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:8100");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
next();
});
app.use('/api/v0/', IndexRouter)
// Root URI call
app.get( "/", async ( req, res ) => {
res.send( "/api/v0/" );
} );
// Start the Server
app.listen( port, () => {
console.log( `server running http://localhost:${ port }` );
console.log( `press CTRL+C to stop server` );
} );
})();
When I run the program no connection is established, and the server fails to start. When I remove the sequelize.sync method, the server will start but my tables are not created. No error is caught by the catch block so I do not suspect there is an error. Currently I do believe this is connection issue dealing with postgres and AWS, but I cannot seem to pinned it down. All feedback and direction are appreciated.

I have found the issue. The problem was due to the node version I was using, which at the time was 14.15.3. This version is not compatible with my current version of postgres 13.1 so I used nvm and downgraded to node 11.15.0 and now my sequelize commands are working.

My node version is 16 and I am guessing Postgres 13 is not compatible with it hence, I had to downgrade my node version to 11.15.0.
Downgrade your node version to 11.15.0 by downloading nvm from here
Unzip the downloaded zip file and install. Click next and accept all default settings -- Do not customize the settings. If you have node already installed it might detect your current node version and ask to take control of it click yes.
After the installation process is done, open CMD or Powershell and type
nvm list
This is will show you the list of node versions installed, then type
nvm install 11.15.0
After installing the node 11.15.0 type
nvm list
To list the newly installed node version along with your previously installed node and then type
nvm use 11.15.0
Then go back to your vscode and run your project again.
#EDIT
If you're from ALX-Cloud Developer Program I suggest you downgrade your node version to 12 because Angular CLI version is only compatible with node v12 and above(at the time of writing this). Good luck!!!

Related

Error with pg-connection-string and sequelize in a React application

I am trying to use the sequelize ORM with a React application. I've installed the sequelize and pg-connection-string packages, but I am getting an error when trying to connect to the database. The error message is:
ERROR in ./node_modules/pg-connection-string/index.js 4:9-22
Module not found: Error: Can't resolve 'fs'
I've tried uninstalling and reinstalling the packages, clearing the npm cache, and using a different version of the packages, but I am still getting the same error.
I am using the following versions:
React: 16.13.1
Sequelize: 6.3.5
pg-connection-string: 2.0.0
Here is my code:
const Sequelize = require('sequelize');
const sequelize = new Sequelize('texteditor', 'root', '', {
host: 'localhost',
dialect: 'mysql'
});
const Database = sequelize.define('database', {
title: {
type: Sequelize.STRING
},
content: {
type: Sequelize.TEXT
}
});
sequelize
.authenticate()
.then(() => {
console.log('Connection has been established successfully.');
})
.catch(err => {
console.error('Unable to connect to the database:', err);
});
sequelize.sync();
I would greatly appreciate any help or suggestions on how to resolve this issue.
So typically you do not connect to databases in the UI layer of an application. Likely the reason it can't retrieve the fs module is that you're running in a browser, where the sequelize package expects you to be using the node runtime. This is where you would build a backend server using Node.JS, which would connect to the DB and in turn respond to the UI with the information it needs.

Apollo Server Express - Playground cannot be reached

I am trying to follow this tutorial https://www.youtube.com/watch?v=I6ypD7qv3Z8&t=48972s but I am stuck on trying to make the playground work.
I get to the playground on "http://localhost:4000/graphql" but somehow I get the "Server cannot be reached" error. In the network inspector I see "Cannot POST /" 404s.
Here's my code (app.ts):
import { ApolloServer } from "apollo-server-express";
import { ApolloServerPluginLandingPageGraphQLPlayground } from "apollo-server-core";
import { buildSchema } from "type-graphql";
import { PORT } from "./constants";
import { HelloResolver } from "./graphql/resolvers";
export const main = async () => {
const app = express();
const apolloServer = new ApolloServer({
schema: await buildSchema({ resolvers: [HelloResolver], validate: false }),
plugins: [ApolloServerPluginLandingPageGraphQLPlayground],
});
await apolloServer.start();
apolloServer.applyMiddleware({ app });
app.listen(PORT, () => {
console.log(
`Server started on http://localhost:${PORT}${apolloServer.graphqlPath}`
);
});
};
Things I did extra from the tut:
Made PORT a variable with value 4000
Added the "ApolloServerPluginLandingPageGraphQLPlayground" for the old school playground (newest doesn't work either)
Added the "await apolloServer.start();" line as specified on the doc, I get an error if I don't
Things I tried:
Using the http server stuff from the doc (https://www.apollographql.com/docs/apollo-server/integrations/middleware/#apollo-server-express) -> same issue
Any idea on where could be the issue? Seems like express didn't create the POST endpoint for the /graphql route.
EDIT: It works if I change this:
apolloServer.applyMiddleware({ app });
to this:
apolloServer.applyMiddleware({ app, path: "/" });
I found the answer here! helpful. Do check it out!
Try using 127.0.0.1 instead of localhost. It worked for me. Also If you have cached queries and mutations that you still want to use, switching back to localhost from 127.0.0.1 will have the localhost working again.
I recently had this issue too. This was the case where the
Server cannot be reached/no visible schema but still able to execute a query
To fix this you should have this as in your ApolloServer initializer:
const server = new ApolloServer({
csrfPrevention: true,
plugins: [
ApolloServerPluginLandingPageGraphQLPlayground(),
],
instrospection: true,
})
Read more about instrospection here and this github issue.

Can't connect to mongoose on test environment

I have a node application running in docker with mongodb and it works fine on development environment. However, I'm creating some tests with mocha and chai and I can't connect to mongo when I run these tests.
The function I want to test is:
const Interactor = require("interactor");
const Donation = require("../models/donations");
module.exports = class CreateDonation extends Interactor {
async run(context) {
this.context = context;
this.donation = new Donation.Model({
donationId: context.id,
status: context.status,
amount: context.chargeInfo.donatedValue,
donatorEmail: context.donatorInfo.email,
source: context.source,
});
await this.donation.save();
}
rollback() {
Donation.Model.findOneAndRemove({ donationId: this.context.id });
}
};
My test:
/* eslint-disable no-unused-vars */
/* eslint-disable no-undef */
const chai = require("chai");
const chaiHttp = require("chai-http");
const CreateDonation = require("../../interactors/create-donation");
require("../../config/db");
const should = chai.should();
const { expect } = chai;
chai.use(chaiHttp);
describe("CreateDonation", () => {
it("Creates a donation when context passed is correct", async (done) => {
const context = {
id: "123123",
status: "AUTHORIZED",
chargeInfo: {
donatedValue: 25.0,
},
donatorInfo: {
email: "test#example.com",
},
source: "CREDIT_CARD",
};
const result = await CreateDonation.run(context);
console.log(result);
done();
});
});
My db config file:
const mongoose = require("mongoose");
require("dotenv/config");
mongoose
.connect("mongodb://db:27017/donations", {
useNewUrlParser: true,
useUnifiedTopology: true,
reconnectInterval: 5000,
reconnectTries: 50,
})
.then(() => {
console.log("good");
})
.catch((err) => {
console.log(err);
});
mongoose.Promise = global.Promise;
module.exports = mongoose;
The error I get from the test above is:
MongooseServerSelectionError: getaddrinfo ENOTFOUND db
What am I doing wrong? Am I missing to import something?
When you run your services inside docker with a docker compose file, they'll get an hostname based on the name you wrote for the service inside the docker-compose file.
Example:
version: "3.9"
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
In this example, the web service can reach the redis db at the redis hostname.
If you change the service name in this way:
db:
image: "redis:alpine"
The web service must connect to the db host.
So, when you run the compose file, your the db service is reached with the db hostname from you app service. But when you run your tests outside a docker compose, the db hostname isn't available and you need to use localhost because your db is running on your OS directly (or it is running inside a container with the 27017 port mapped on the main host).
If you're using a unix OS, you can solve your problem adding an alias in your /etc/hosts file:
127.0.0.1 localhost db
In this way you can run your tests keeping the db connection string.
Otherwise, and this is the suggested solution, you can use an environment variable to change the connection string at the application startup:
mongoose.connect(process.env.MONGO_URI)
And run it using
MONGO_URI=mongodb://db:27017/donations npm start
Then in the docker compose you can add a fixed environment variable using this code:
environment:
- MONGO_URI=mongodb://db:27017/donations
Just found out that when testing, I need to use "localhost" on my connection string for mongo (I was using the name from docker-compose). So with the URI as "mongodb://localhost:27017/donations" it worked. I don't know why.

How to add proxy to connect with Azure Postgresql?

I use this script to connect node.js with Azure Postgresql.
But the ssl verification of our firewall blocks the connection, so in the past I need to use a proxy. Where in the code can I add the proxy settings as like host and port?
Means when I start the code, vscode should connect through the proxy to postgresql.
const pg = require('pg');
const config = {
host: '<your-db-server-name>.postgres.database.azure.com',
// Do not hard code your username and password.
// Consider using Node environment variables.
user: '<your-db-username>',
password: '<your-password>',
database: '<name-of-database>',
port: 5432,
ssl: true
};
const client = new pg.Client(config);
client.connect(err => {
if (err) throw err;
else { queryDatabase(); }
});
function queryDatabase() {
console.log(`Running query to PostgreSQL server: ${config.host}`);
const query = 'SELECT * FROM inventory;';
client.query(query)
.then(res => {
const rows = res.rows;
rows.map(row => {
console.log(`Read: ${JSON.stringify(row)}`);
});
process.exit();
})
.catch(err => {
console.log(err);
});
}
To configure proxy for Visual Studio Code
Edit the settings.json file
Depending on your platform, the user settings file is located here:
Windows: %APPDATA%\Code\User\settings.json
macOS: $HOME/Library/Application Support/Code/User/settings.json
Linux: $HOME/.config/Code/User/settings.json
Modify and Add the below lines to configure your proxy
"http.proxy": "http://user:pass#proxy.com:portnumber",
"https.proxy": "http://user:pass#proxy.com:portnumber",
"http.proxyStrictSSL": false
If your proxy doesn't require authentication, you could simply use
"http.proxy": "http://proxy.com:portnumber",
"https.proxy": "http://proxy.com:portnumber"
"http.proxyStrictSSL": false
Restart VS Code
The documentation related to settings and schema of the settings.json file is here for reference

Automated Testing with Databases

I'm fairly new to automated testing and was wondering how I should go about writing tests for the database. The project I'm working on right now is running PostgreSQL with Sequelize as the ORM on a Node.JS environment. If it matters, I'm also using Jest as the testing library right now.
In my app I use a config module to control configuration settings for different environments. When running tests the process.env.APP_ENV is set to test, and it will set the dialect to sqlite. Note that you will not have any data or data persistence, so you will need to populate it with all the data needed for your tests.
Include sqlite3
yarn add -D sqlite3
or
npm i -D sqlite3
Config
module.exports = {
database: {
name: 'dbname',
user: 'user',
password: 'password',
host: 'host',
// Use "sqlite" for "test", the connection settings above are ignored
dialect: process.env.APP_ENV === 'test' ? 'sqlite' : 'mysql',
},
};
Database/Sequelize
// get our config
const config = require('../config');
// ... code
const instance = new Sequelize(
config.database.name,
config.database.user,
config.database.password,
{
host: config.database.host,
// set the dialect, will be "sqlite" for "test"
dialect: config.database.dialect,
}
);
Test Class (Mocha)
const TestUtils = require('./lib/test-utils');
describe('Some Tests', () => {
let app = null;
// run before the tests start
before((done) => {
// Mock up our services
TestUtils.mock();
// these are instantiated after the mocking
app = require('../server');
// Populate redis data
TestUtils.populateRedis(() => {
// Populate db data
TestUtils.syncAndPopulateDatabase('test-data', () => {
done();
});
});
});
// run code after tests have completed
after(() => {
TestUtils.unMock();
});
describe('/my/route', () => {
it('should do something', (done) => {
return done();
});
});
});
Run Tests
APP_ENV=test ./node_modules/.bin/mocha
You could use ENV variables in other ways to set the dialect and connection parameters as well - the above is just an example based on what we have done with a lot of supporting code.
If you're not doing anything particularly complicated on the DB side, take a look at pg-mem:
https://swizec.com/blog/pg-mem-and-jest-for-smooth-integration-testing/
https://github.com/oguimbal/pg-mem
It's really cool in that it tests actual PG syntax and can pick up a bunch of errors that using a different DB or mock DB won't pick up. However, it's not a perfect implementation and missing a bunch of features (e.g. triggers, decent "not exists" handling, lots of functions) some of which are easy to work around with the hooks provided and some aren't.
For me, having the test DB initialized with the same schema initialization scripts as the real DB is a big win.

Resources