I'm following along with a tutorial to create a movie review app on the MERN stack.
When calling my API using Insomnia, I'm getting the error "ReviewsDAO.addReview is not a function"
reviewsDAO.js:
import mongodb from "mongodb"
const ObjectId = mongodb.ObjectId
let reviews
export default class ReviewsDAO{
static async injectDB(conn){
if(reviews){
return
}
try { reviews = await conn.db(process.env.MOVIEREVIEWS_NS).collection('reviews')}
catch(e){
console.error(`unable to establish connection handle in reviewDAO: ${e}`)
}
}
static async addReview(movieId, user, review, date){
try{
const reviewDoc = {
name: user.name,
user_id: user._id,
date: date,
review: review,
movie_id: ObjectId(movieId)
}
return await reviews.insertOne(reviewDoc)
}
catch(e) {
console.error(`unable to post review ${e}`)
return {error: e}
}
}
reviews.controller.js:
import ReviewsDAO from '../dao/reviewsDAO.js'
export default class ReviewsController{
static async apiPostReview(req,res,next) {
const reviewsDAO = new ReviewsDAO()
try{
const movieId = req.body.movie_id
const review = req.body.review
const userInfo = {
name: req.body.name,
_id: req.body.user_id
}
const date = new Date()
const ReviewResponse = await reviewsDAO.addReview(
movieId,
userInfo,
review,
date
)
res.json({status: "success"})
}
catch(e) {
res.status(500).json({error: e.message})
}
}
The reviews collection is also not being created in MongoDB. But maybe that isn't supposed to happen until we create our first review.
Why isn't my function being called appropriately?
You need to instantiate a ReviewsDAO object in order to call its methods.
const reviewsDAO = new ReviewsDAO()
Then you will be able to access the addReview() method
You are calling the class method without initializing the object.
For example:
class Animal{
function sayhello(){
console.log("Hello")
}
}
// I can call the sayhello method by creating an object.
var dog=new Animal()
dog.sayhello() //prints "Hello"
But in your case, you are calling the method without creating the object.
Animal.sayhello()
// It will create an error
So initialise the object and call the method
const reviewsDAO = new ReviewsDAO()
reviewDAO.addreviews()
The static keyword defines static methods for classes.
Static methods are called directly on the class (Car from the example above) - without creating an instance/object (mycar) of the class
So
const Reviewsdao= new ReviewsDAO()
ReviewsDAO().addreviews()
Call the method with the class name after initialising it.
Related
Let's say we have a bookshop and an author entity, to show the author their earnings stat, we want to check if the authenticated user is indeed the author themselves. So we have:
#UseGuards(GqlAuthGuard)
#ResolveField(() => [Eearning], { name: 'earnings' })
async getEarnings(
#Parent() author: Author,
#GqlUser() user: User,
) {
if (user.id !== author.id)
throw new UnauthorizedException(
'Each author can only view their own data',
);
// rest of the function implementation
}
We could query this:
query {
author(id: "2bd79-6d7f-76a332b06b") {
earnings {
sells
}
}
}
Now imagine we want to use a custom Guard instead of that if statement. Something like below:
#Injectable()
export class AutherGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const ctx = GqlExecutionContext.create(context);
// const artistId = ?
}
}
How can I access the id argument given to the author query when AutherGuard is used for the getEarnings handler?
Not sure how documented is that but the parent object can be accessed through the getRoot method:
const gqlContext = GqlExecutionContext.create(context);
const root = gqlContext.getRoot();
const authorId = root.id;
In fact, we have a helper function that we use like this:
export function getArgs(context: ExecutionContext): any {
if (context.getType<GqlContextType>() === "graphql") {
const gqlContext = GqlExecutionContext.create(context);
return { ...gqlContext.getArgs(), $parent: gqlContext.getRoot() };
} else if (context.getType() === "http") {
return context.switchToHttp().getRequest().params;
}
}
...
const args = getArgs(context);
const authorId = _.get(args, "$parent.id");
I'm trying to build an API with express and pg. Whenever I try to access an endpoint that is related to a query to the database I get the error above.
My handler function is as follows:
import { Request, Response, Router, NextFunction } from 'express';
import { Orders } from '../models/order';
const orders = new Orders;
const index = async (_req: Request, res: Response, next: NextFunction) => {
try {
const ordersList = await orders.index();
res.json(ordersList);
} catch (err) {
next(err)
}
}
const ordersRoute = Router();
ordersRoute.get('/', index);
This handler refers to the following model:
import { Pool } from 'pg';
client = new Pool({
host: POSTGRES_HOST,
database: POSTGRES_DB,
user: POSTGRES_USER,
password: POSTGRES_PASSWORD,
port: parseInt(POSTGRES_PORT as string, 10)
export class Orders {
async index(): Promise<Order[]> {
try {
const conn = await client.connect();
const sql = 'SELECT * FROM orders';
const result = await conn.query(sql);
conn.release();
return result.rows;
} catch (err) {
throw new Error(`Cannot get orders: ${err}`);
}
}
}
anytime I try to access the endpoint I get
Error: Cannot get orders: TypeError: Cannot read properties of
undefined (reading 'connect')
in the console.
any idea how to fix ?
So how things work in your case.
All modules are read by nodejs starting from your index one by one from top to bottom.
In your script, you declare client and then export a class. In that case, your client is setup, then you export a class, and that file is completed, meaning that the only thing that remains is the exported thing. So when you try to use the exported class, you'll not have the same context as in your module.
You need to export the client too and import it where you need that class or to include client definition inside the class
the title problem ! I don't know why I can't use a method from another class in NodeJS. This is my first time using classes in Node.
Let see some code:
'use strict'
api_client.js:
class ApiClient {
constructor(userQuery) {
this.userQuery = userQuery;
}
getResponse() {
try {
const response = {"my query": this.userQuery}"this is an example to simplify";
} catch(error) {
throw new Error(error.message);
}
}
}
module.exports = ApiClient;
api_service.js:
'use strict';
const apiClient = require('../clients/api_client');
class ApiService {
static async getResponse(userQuery) {
try {
const instance = await new ApiClient(userQuery);
const response = instance.getResponse(); //I think here is the problem. WebStorme tell me that I can't acces to getResponse method.
const responseJson = response.json();
return responseJson;
} catch (error) {
throw new Error(error.message);
}
}
So I can't use the "getResponse" method from ApiClient class in ApiService. Something wrong !?
thanks!
code in app/src/emails/account.js
const mailgun = require("mailgun-js");
const DOMAIN = "sxxxxxxxxxxxxxxxxxxxxxxxxxxx.mailgun.org";
const mg = mailgun({apiKey: process.env.MAILGUN_API_KEY, domain: DOMAIN});
const sendWelcomeEmail = async (email, name) => {
const dataForMail = {
to: email,
from: 'zzz#xxx.com',
subject: 'Testing!',
text: `Welcome to the app, ${name}, let me know how you get along with the app.`,
}
mg.messages().send(dataForMail)
}
code in app/test/__mocks__/mailgun-js:
module.exports = {
messages() {
},
send() {
},
mailgun() {
}
}
Whenever I run jest, it says 'mailgun is not a function'. How can I create a manual mock for this constructor?
My mock is an object, not a function. Test doubles need to match the interface of the thing they're replacing; in this case, it needs to be a function that returns an object with a messages method (which returns an object with the send method). My mock doesn't match that structure at all. (Big thanks to #jonrsharpe for informing this)
mailgun-js.js needs to be edited the same way.
module.exports = function(apiKey, domain) {
const object2 = {
send() {
}
}
const object1 = {
messages () {
return object2
}
}
return object1
}
I am getting this error when running the sample application for AngularJS from Breeze's website.
This is the code for the controller breezectl.js:
'use strict';
angular.module('mean').controller('breezeController', ['$scope', 'Global', 'dataservice',
function($scope, Global, dataservice) {
$scope.global = Global;
$scope.breeze = {
name: 'Breeze Sample'
};
//$scope.results = dataservice;
function getProducts() {
function success(data) {
$scope.results = data;
}
function failed(error) {
$scope.results = error.message;
}
dataservice.getAllProducts()
.then(success)
.catch(failed);
}
getProducts();
}
]);
dataservice.getAllProducts() enters the catch(failed) branch with this error message: "A MergeStrategy of 'Disallowed' does not allow you to attach an entity when an entity with the same key is already attached"
This is the code for dataservice.js:
'use strict';
angular.module('mean').factory('dataservice', ['breeze', 'entityManagerFactory',
function(breeze, entityManagerFactory) {
var manager = entityManagerFactory.newManager();
function getAllProducts(){
function success(data) {
return data.results;
}
return breeze.EntityQuery.from('Products')
.using(manager).execute()
.then(success);
}
var service = {
getAllProducts: getAllProducts
};
return service;
}
]);
Note: A direct call to Products from the Restful API (localhost:3000/breeze/northwind/Products) works properly and returns a set of Json objects representing all of the products in the collection.
Steve Schmitt are right. My metadata.json had the "defaultResourceName" property with a different name that the database collection.
I changed "Products" to "products" and this works.
Many thanks to all of you.