I cannot work out why I would get a query undefined when I know my definitions are correct. graphiQL is picking up my schemes without problems:
Auto complete works fine:
After hitting ctrl+enter all the fields are entered, see above.
Then I execute the query and I'll get:
{
"errors": [
{
"message": "Cannot read property 'query' of undefined",
"locations": [
{
"line": 1,
"column": 3
}
],
"path": [
"allAwards"
]
}
],
"data": {
"allAwards": null
}
}
npm run graphql
"graphql": "nodemon -r dotenv/config --experimental-modules --inspect=[9222] graphql_server.js",
graphql_server.js
import express from 'express'
import pg from 'pg'
import graphqlHTTP from 'express-graphql'
import PAS from 'postgraphile-apollo-server'
import AP from 'apollo-server-express'
const { makeSchemaAndPlugin } = PAS
const { ApolloServer } = AP
const env = process.env.NODE_ENV || 'development'
const dbHost = process.env.DB_HOST
const dbPort = process.env.DB_PORT
const dbName = process.env.DB_NAME
const dbUser = process.env.DB_USER
const dbPwd = process.env.DB_PWD
const dbUrl = dbPwd
? `postgres://${dbUser}:${dbPwd}#${dbHost}:${dbPort}/${dbName}`
: `postgres://${dbHost}:${dbPort}/${dbName}`
const pgPool = new pg.Pool({
connectionString: dbUrl,
})
async function main() {
const { schema, plugin } = await makeSchemaAndPlugin(
pgPool,
'public', // PostgreSQL schema to use
{
// PostGraphile options, see:
// https://www.graphile.org/postgraphile/usage-library/
}
)
const server = new ApolloServer({
schema,
plugins: [plugin],
})
const app = express()
app.use(
'/graphql',
graphqlHTTP({
schema: schema,
graphiql: true,
})
)
server.applyMiddleware({ app })
app.listen({ port: 4000 }, () => console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`))
}
main().catch(e => {
console.error(e)
process.exit(1)
})
There are 2 rows currently in psql db for awards as well
You should not utilize middleware from both express-graphql and apollo-server in your express application. Because postgraphile-apollo-server works explicitly with ApolloServer, drop express-graphql altogether. Having both middleware is likely to cause unexpected issues since they listen on the same paths.
Apollo has abandoned GraphiQL in favor of GraphQL Playground. If you want to use GraphiQL with Apollo, you can use a package like express-graphiql-middleware.
Related
So I'm in the process of learning NestJs ways. I have a small NestJs backend with only a few routes. Some of them call postgreSQL. I don't want to use any ORM and directly use pg package.
So my next step is learning how to use ConfigService. I have successfully used it to configure all env vars in the backend, but I'm struggling to use it in a small file I use to configure postgreSQL. This is the configuration file (pgconnect.ts):
import { Pool } from 'pg';
import configJson from './config/database.json';
import dotenv from 'dotenv';
dotenv.config();
const config = configJson[process.env.NODE_ENV];
const poolConfig = {
user: config.username,
host: config.host,
database: config.database,
password: config.password,
port: config.port,
max: config.maxClients
};
export const pool = new Pool(poolConfig)
database.json is a json file where I have all connect values divided by environment. Then in service classes I just:
import { Injectable } from '#nestjs/common';
import { Response } from 'express';
import { pool } from 'src/database/pgconnect';
#Injectable()
export class MyService {
getDocumentByName(res: Response, name: string) {
pool.query(
<query, error treatment, etc>
});
}
<...> more queries for insert, update, other selects, etc
}
So how could I use ConfigService inside my configuration file ? I already tried to instance class like this:
let configService = new ConfigService();
and what I would like to do is:
const config = configJson[configService.get<string>('NODE_ENV')];
but it didn't work. You have to pass .env file path to new ConfigService(). And I need to use NODE_ENV var to get it, because it depends on environment. To get NODE_ENV without using ConfigService I would have to use dotenv, but if I'm going to use dotenv I don't need ConfigService in the first place.
So then I tried to create a class:
import { Injectable, HttpException, HttpStatus } from '#nestjs/common';
import { ConfigService } from '#nestjs/config'
const { Pool } = require('pg');
import configJson from './config/database.json';
#Injectable()
export class PgPool {
constructor(private configService: ConfigService) { };
config = configJson[this.configService.get<string>('NODE_ENV')];
poolConfig = {
user: this.config.username,
host: this.config.host,
database: this.config.database,
password: this.config.password,
port: this.config.port,
max: this.config.maxClients
};
static pool = new Pool(this.poolConfig);
}
export const PgPool.pool;
But this doesn't work in several ways. If I use non-static members, I can´t export pool member which is the only thing I need. If I use static members one can't access the other or at least I'm not understanding how one access the other.
So, the questions are: How do I use ConfigService outside of a class or how can I change pgconnect.ts file to do it's job ? If it's through a class the best would be to export only pool method.
Also if you think there's a better way to configure postgreSQL I would be glad to hear.
What I would do, if you're going to be using the pg package directly, is create a PgModule that exposes the Pool you create as a provider that can be injected. Then you can also create a provider for the options specifically for ease of swapping in test. Something like this:
#Module({
imports: [ConfigModule],
providers: [
{
provide: 'PG_OPTIONS',
inject: [ConfigService],
useFactory: (config) => ({
host: config.get('DB_HOST'),
port: config.get('DB_PORT'),
...etc
}),
},
{
provide: 'PG_POOL',
inject: ['PG_OPTIONS'],
useFactory: (options) => new Pool(options),
}
],
exports: ['PG_POOL'],
})
export class PgModule {}
Now, when you need to use the Pool in another service you add PgModule to that service's module's imports and you add #Inject('PG_POOL') private readonly pg: Pool to the service's constructor.
If you want to see an overly engineered solution, you can take a look at my old implementation here
I normally have my own pg module handling the pool with either an additional config file (json) or via processing a .env file:
node-pg-sql.js:
/* INFO: Require json config file */
const fileNameConfigPGSQL = require('./config/pgconfig.json');
/* INFO: Require file operations package */
const { Pool } = require('pg');
const pool = new Pool(fileNameConfigPGSQL);
module.exports = {
query: (text, params, callback) => {
const start = Date.now()
return pool.query(text, params, (err, res) => {
const duration = Date.now() - start
// console.log('executed query', { text, duration, rows: res.rowCount })
callback(err, res)
})
},
getClient: (callback) => {
pool.connect((err, client, done) => {
const query = client.query.bind(client)
// monkey patch for the query method to track last queries
client.query = () => {
client.lastQuery = arguments
client.query.apply(client, arguments)
}
// Timeout of 5 secs,then last query is logged
const timeout = setTimeout(() => {
// console.error('A client has been checked out for more than 5 seconds!')
// console.error(`The last executed query on this client was: ${client.lastQuery}`)
}, 5000)
const release = (err) => {
// calling 'done'-method to return client to pool
done(err)
// cleat timeout
clearTimeout(timeout)
// reset query-methode before the Monkey Patch
client.query = query
}
callback(err, client, done)
})
}
}
pgconfig.json:
{
"user":"postgres",
"host":"localhost",
"database":"mydb",
"password":"mypwd",
"port":"5432",
"ssl":true
}
If you prefer processing a .env file:
NODE_ENV=develepment
NODE_PORT=45500
HOST_POSTGRESQL='localhost'
PORT_POSTGRESQL='5432'
DB_POSTGRESQL='mydb'
USER_POSTGRESQL='postgres'
PWD_POSTGRESQL='mypwd'
and process the file and export vars:
var path = require('path');
const dotenvAbsolutePath = path.join(__dirname, '.env');
/* INFO: Require dotenv package for retieving and setting env-vars at runtime via absolute path due to pkg */
const dotenv = require('dotenv').config({
path: dotenvAbsolutePath
});
if (dotenv.error) {
console.log(`ERROR WHILE READING ENV-VARS:${dotenv.error}`);
throw dotenv.error;
}
module.exports = {
nodeEnv: process.env.NODE_ENV,
nodePort: process.env.NODE_PORT,
hostPostgresql: process.env.HOST_POSTGRESQL,
portPostgresql: process.env.PORT_POSTGRESQL,
dbPostgresql: process.env.DB_POSTGRESQL,
userPostgresql: process.env.USER_POSTGRESQL,
pwdPostgresql: process.env.PWD_POSTGRESQL,
};
I have a mongodb server setup which on running the below command starts on port 3000
npm run start
I also a graphql server which on running the below command starts at port 4000
npm run start-graphql
the scripts of my package.json is as below
"scripts": {
"start": "nodemon server.js",
"start-graphql": "nodemon graphqlserver.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
server.js
require('dotenv').config();
const express = require('express');
const app = express();
const mongoose = require('mongoose');
mongoose.connect(process.env.DATABASE_URL);
const db = mongoose.connection;
db.on('error', (err) => console.log(err));
db.once('open', () => {
console.log("Backend Database connected");
});
app.use(express.json({ limit: '2mb'}));
const photosRouter = require('./routes/photos');
app.use('/images', photosRouter)
app.listen(3000, () => {
console.log('Server started at port 3000');
})
graphqlserver.js
const express = require('express');
const path = require('path');
const express_graphql = require('express-graphql').graphqlHTTP;
const { loadSchemaSync } = require('#graphql-tools/load');
const { GraphQLFileLoader } = require('#graphql-tools/graphql-file-loader');
const { addResolversToSchema } = require('#graphql-tools/schema');
const getResolvers = require('./graphql/resolvers');
// GraphQL schema
const combinedSchema = loadSchemaSync(
path.join(__dirname, './graphql/schemas/*.graphql'),
{
loaders: [new GraphQLFileLoader()],
}
);
const schema = addResolversToSchema({
schema: combinedSchema,
resolvers: Object.assign({}, getResolvers())
});
// Create an express server and a GraphQL endpoint
const app = express();
app.use('/graphql', express_graphql({
schema: schema,
graphiql: true
}));
app.listen(4000, () => console.log('Express GraphQL Server Now Running On localhost:4000/graphql'));
when I call the rest api's normally either through postman or curl it returns the response as expected.
For eg: http://localhost:3000/images returns me an array of objects
But When I want to call (using axios) the same via the graphql server (which is running on port 4000 ),
I get response as null.
I have no clue why this is happening.
Please check the below screenshot for your reference
Note: For better clarity please check the codebase link
https://github.com/yaswankar/G-photos-backend
Any help would be appreciated.
Thanks in advance
Request: Please help by giving an upvote so that it could better reach to those who could help.
Edit:
New Error screenshot
I was able to resolve the main issue by adding the query block inside photos resolver
Query: {
photo: photosContext,
},
The other error was resolved by processing the response instead of sending the raw data to the hyper class
async function getActivePhotos(parent, args, req) {
try {
const activePhotos = await photoService.getActivePhotos(req).then(resp => resp.data.map(item => item)); // Process and mapping data
return activePhotos;
} catch (error) {
// logger.error(__filename + ': Failed to get response for getActivePhotos, err=' + JSON.stringify(error));
return new GraphQLError(JSON.stringify(error));
}
}
I am trying to connect to my backend mongodb 5.0.5 with nodejs express script.
when running the app.js using nodemon it shows your mongodb is connected but on the localhost it keeps on reloading without any error stack trace.
I am using mongoose models in the models as in MVC in nodejs. Not sure why its is not getting run on localhost, it was working fine when last I used these files.
here are my files:
app.js
// imports
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const { append } = require('express/lib/response')
const zomatoRoutes = require('./Routes/zomato')
const mongoose = require('mongoose')
// create express server
var app = express()
//listen to a port
app.listen(7878, () => {
console.log('app running on port 7878');
})
app.use(bodyParser.json())
//connect mongodb
mongoose.connect('mongodb://localhost/zomato', () => {
console.log("MongoDB Connected");},
e => console.log(e)
)
// Middleware routes
app.use('/zomato', zomatoRoutes)
app.use(cors())
Model > locations.js
const mongoose = require('mongoose')
const locationSchema = new mongoose.Schema({
name: {
type: String,
required:true
},
city_id: {
type: String,
required:true
},
location_id: {
type: String,
required:true
},
country_name: {
type: String,
required:true
}
})
module.exports = mongoose.model("LocationsModel", locationSchema, "locations")
Controllers > location.js
const { status } = require('express/lib/response')
const Locations = require('../Model/location')
exports.getAllLocations = (req, res) => {
Locations.find().then(
result => {
res.status(200).json({ message: "data fetched successfully", data: result })
}
).catch(error => {
res.send(500).json({ message: "Error in Database", error: error })
})
}
and my routes
zomato.js
const express = require('express')
const Router = express.Router();
const RestaurantController = require('../Controller/Restaurant')
const LocationsController = require('../Controller/Location')
// configure routes
// Restaurants routes
Router.get('/restaurants', RestaurantController.getAllRestaurants)
Router.post('/restaurants/filter/:pageNo', RestaurantController.getRestaurantsByFilter)
// Locations routes
Router.get('/locations', LocationsController.getAllLocations)
module.exports = Router
my Json files
locations.json goes like this:
[
{
"_id": "1",
"name": "ShalimarBhagh, Delhi",
"city_id": "1",
"location_id": "1",
"country_name": "India"
},
{
"_id": "2",
"name": "Janpat, Delhi",
"city_id": "1",
"location_id": "2",
"country_name": "India"
},
{
"_id": "3",
"name": "MSP, Delhi",
"city_id": "1",
"location_id": "3",
"country_name": "India"
}
]
** Updates: I forgot to mention I recently updated to windows10 to make sure my react app works and after this issue is arising, now I created a fresh application with removing mongo and re-installing mongodb still gets me this error in postman Error: read ECONNRESET**
Update I get this stack trace
C:\Users\acer\Documents\EDUREKA\Nodejs-mongodb-
mongoose\node_modules\mongoose\lib\connection.js:797
const serverSelectionError = new ServerSelectionError();
^
MongooseServerSelectionError: connect ECONNREFUSED ::1:27017
at NativeConnection.Connection.openUri
(C:\Users\acer\Documents\EDUREKA\Nodejs-mongodb-
umongoose\node_modules\mongoose\lib\connection.js:797:32)
Try this instead:
// imports
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const { append } = require('express/lib/response')
const zomatoRoutes = require('./Routes/zomato')
const mongoose = require('mongoose')
// create express server
const app = express()
// Middleware routes
app.use(cors())
app.use(bodyParser.json())
app.use('/zomato', zomatoRoutes)
//connect mongodb
mongoose.connect('mongodb://localhost/zomato', () => {
console.log("MongoDB Connected");
const server = app.listen(7878, () => {
console.log('app running on port 7878');
})
server.setTimeout(0) // disable the default time out server mechanism
},
e => console.log(e)
)
Which is:
initialize exprress app
register middlewares
connect to mongo
if connection successful (and only then) - start the application
Also, replace your code
res.status(200).json({ data: 'whatever' })
to:
res.status(200).send({ data: 'whatever' })
There is a chance that your response is not getting back to client, hence - resulting in timeout error. This approach should fix this as well
Hope it will help you with your problem
Localhost is not resolved, though I changed my mongodb to ipv6 using mongod --ipv6 still it does not accept and in stack trace shows isIPV6 : false.
so finally I had to change the using the answer here listen to port using ipv4
//connect to mongoDB
const uri = 'mongodb://localhost:27017/zomato';
const options = {
useNewUrlParser: true,
useUnifiedTopology: true,
family:4
}
const connectWithDB = () => {
mongoose.connect(uri, options, (err, db) => {
if (err) console.error(err);
else console.log("database connection")
})
}
connectWithDB()
It is working now and fetching data but want to resolve the issue of ipv6 nodejs.
Stack => Nodejs, Express.js, Typeorm
I'm trying to use typeorm with typescript. I have created a repository to save the survivor information. But I keep getting this error:
ConnectionNotFoundError: Connection "default" was not found.
at new ConnectionNotFoundError (/Users/Wblech/codeminerTeste/backend/src/error/ConnectionNotFoundError.ts:8:9)
at ConnectionManager.get (/Users/Wblech/codeminerTeste/backend/src/connection/ConnectionManager.ts:40:19)
at Object.getRepository (/Users/Wblech/codeminerTeste/backend/src/index.ts:284:35)
at new CreateSurvivorRepository (/Users/Wblech/codeminerTeste/backend/src/repositories/typeorm/CreateSurvivorRepository.ts:10:26)
at Object.<anonymous> (/Users/Wblech/codeminerTeste/backend/src/useCases/CreateSurvivor/index.ts:6:41)
at Module._compile (internal/modules/cjs/loader.js:774:30)
at Module._compile (/Users/Wblech/codeminerTeste/backend/node_modules/source-map-support/source-map-support.js:547:25)
at Module.m._compile (/private/var/folders/fr/6x3p83cj6r73h57k1_x6nctc0000gn/T/ts-node-dev-hook-7748782675459163.js:69:33)
at Module._extensions..js (internal/modules/cjs/loader.js:785:10)
at require.extensions..jsx.require.extensions..js (/private/var/folders/fr/6x3p83cj6r73h57k1_x6nctc0000gn/T/ts-node-dev-hook-7748782675459163.js:114:20)
[ERROR] 00:28:59 ConnectionNotFoundError: Connection "default" was not found.
My ormconfig.json is this one:
{
"name": "default",
"type": "postgres",
"host": "localhost",
"port": 5432,
"username": "postgres",
"password": "teste",
"database": "codeminer_backend",
"entities": [
"src/database/models/*.ts"
],
"migrations": [
"src/database/migrations/*.ts"
],
"cli": {
"migrationsDir": "./src/database/migrations"
}
}
Those are the code that the error appoint:
at new CreateSurvivorRepository (/Users/Wblech/codeminerTeste/backend/src/repositories/typeorm/CreateSurvivorRepository.ts:10:26)
import { getRepository, Repository } from 'typeorm'
import { SurvivorOrm } from '../../database/models/SurvivorsOrm'
import { ICreateSurvivorRequestDTO } from '../../useCases/CreateSurvivor/CreateSurvivorDTO'
import { ICreateSurvivorRepository } from '../ICreateSurvivorRepository'
export class CreateSurvivorRepository implements ICreateSurvivorRepository {
private ormRepository: Repository<SurvivorOrm>
constructor () {
this.ormRepository = getRepository(SurvivorOrm)
}
public async create ({ id, name, age, gender, lastLocation, infected }: ICreateSurvivorRequestDTO): Promise<SurvivorOrm> {
const survivor = await this.ormRepository.create({ id, name, age, gender, lastLocation, infected })
await this.ormRepository.save(survivor)
return survivor
}
}
at Object.<anonymous> (/Users/Wblech/codeminerTeste/backend/src/useCases/CreateSurvivor/index.ts:6:41)
import { CreateInventoryRepository } from '../../repositories/typeorm/CreateInventoryRepository'
import { CreateSurvivorRepository } from '../../repositories/typeorm/CreateSurvivorRepository'
import { CreateSurvivorController } from './CreateSurvivorController'
import { CreateSurvivorUseCase } from './CreateSurvivorUseCase'
const createSurvivorRepositoryTypeOrm = new CreateSurvivorRepository()
const createInventoryRepositoryTypeOrm = new CreateInventoryRepository()
const createSurvivorUseCase = new CreateSurvivorUseCase(
createSurvivorRepositoryTypeOrm,
createInventoryRepositoryTypeOrm
)
const createSurvivorController = new CreateSurvivorController(
createSurvivorUseCase
)
export { createSurvivorUseCase, createSurvivorController }
My connection is in a file in the path './src/database/index.ts' and is this one:
import { createConnection } from 'typeorm'
createConnection()
And I import the connection in this file called server.ts:
import express from 'express'
import { router } from './router'
import './database'
const port = 8081
const app = express()
app.use(express.json())
app.use(router)
app.listen(port, () => console.log(`App running at ${port}`))
I'm really stuck at this
Basically - TypeORM tries to get the "default" connection option, but If not found then throws an error:
ConnectionNotFoundError: Connection "default" was not found.
We can solve this issue by doing some kind of sanity check before establishing a connection - luckily we have .has() method on getConnectionManager().
import { Connection, getConnectionManager, getConnectionOptions,
createConnection, getConnection, QueryRunner } from 'typeorm';
async init() {
let connection: Connection;
let queryRunner: QueryRunner;
if (!getConnectionManager().has('default')) {
const connectionOptions = await getConnectionOptions();
connection = await createConnection(connectionOptions);
} else {
connection = getConnection();
}
queryRunner = connection.createQueryRunner();
}
We're trying to use the latest standards and are updated our javascript files require sections. We're trying to updated this:
const {app: { port, test_var }} = require('../config/config')
const app = require('./app')
to this:
import {app: { port, test_var }} from '../config/config'
import app from './app'
But the following error is thrown:
import {app: { port, test_var }} from '../config/config'
^
SyntaxError: Unexpected token ':'
What would be the correct syntax? I can't find an example for this specific case in the documentation.
This is the content of config.js:
const env = process.env.NODE_ENV || 'development'
console.log(`Environment '${env}'`)
const development = {
app: {
port: parseInt(process.env.DEV_APP_PORT) || 3000,
test_var: parseInt(process.env.TEST_VAR),
// Generate token:
// require('crypto').randomBytes(128).toString('hex')
accessTokenKey: process.env.accessTokenKey || '5ef37718e7c74b',
refreshTokenKey: process.env.refreshTokenKey || 'j;9f0as8098fas'
},
db: {
host: process.env.DEV_DB_HOST || 'localhost',
port: parseInt(process.env.DEV_DB_PORT) || 27017,
name: process.env.DEV_DB_NAME || 'db'
}
}
const production = {
app: {
port: parseInt(process.env.PROD_APP_PORT) || 8080,
accessTokenKey: process.env.accessTokenKey,
refreshTokenKey: process.env.refreshTokenKey
},
db: {
host: process.env.PROD_DB_HOST || 'ServerProd',
port: parseInt(process.env.PROD_DB_PORT) || 27017,
name: process.env.PROD_DB_NAME || 'NodeDB'
}
}
const config = {
development,
production
}
module.exports = config[env]
You can't use module.exports then, because that's old way that works with require.
Please look at
Export ECMA
===========================================
Edit my answer because first is not clear.
Import clause in import ES6 isn't the same as destructuring. There is a syntactic similarity if you read doc. about import, but there are no constructors for that.
Use another statement for destructuring after the import