Route params not getting sent to ExpressJS API - javascript

I'm scratching my head on this.
I'm running an expressjs site with angularjs as my front-end resource, and my problem is that I've set up my API to query my datastore with a parameterized query. When I hit the route, the parameter is not appearing in my angularjs resource query, so I end up just getting the entire data set instead of one object by id.
/api/index.js:
var _getSingleRequest = function(req, res, next)
{
models.Request
.findOne({'_id': req.body.id})
.exec(function(err, request){
if(err) return res.send(500, err);
if(!request) return res.send(404, new Error("Request not found"));
res.send(request);
});
};
...
return {
_getSingleRequest: getSingleRequest
}
/server.js
...
var api = require('./api');
app.get('/api/request/:id', api.getSingleRequest);
...
/public/js/controllers/controller.js
...
function Request($scope, $resource, $routeParams, Request)
{
$scope.request = Request.query({_id : $routeParams.id});
...
}
...
/public/js/services/services.js
services.Request = function($resource)
{
return $resource('/api/request/:id', {id:'#id'}, {'get': {method:'GET', isArray: true}});
}
console
Mongoose: requests.find({}) { fields: undefined, safe: undefined, sort: [ [ 'requestedDate', 1 ] ] }
GET /api/request?_id=51b8cc2a06859bd418000001 304 179ms
it appears that the get request is coming through properly, but in the Mongoose query there are no parameters being passed.
what simple mistake am I making, and what other information can I post to help me figure out how to get out of the infinite loop of banging my head on the wall?

In your Request function, you're passing _id:
Request.query({_id : $routeParams.id});
^^^
But in your service, you're expecting id:
$resource('/api/request/:id', {id:'#id'}
^^^
That will generate requests looking like this (which is also what your log says):
/api/request/?_id=XXX
But your backend is expecting this:
/api/request/XXX

req.body.id is for the request body, not route parameters, which come from the request URI. You want req.params.id

Related

Multiple parameters are not being send properly in get method using Angular 5 and Node js backend

I am trying to create a API using nodejs and access it using GET method by sending parameters using Angular 5 GET method. When I am testing my API using Postman, it works fine, but sending the GET request from Angular is not giving me the result. My node js router for receiving multiple parameters code is as follow:
router.get('/:min&:max',(req,res,next)=> {
Image.find({hue: {$gt:req.params.min,$lt:req.params.max}})
.select('name url hue')
.exec()
.then(docs => {
const response={
images: docs.map(doc=> {
return {
name: doc.name,
url: doc.url,
hue: doc.hue,
_id: doc._id,
}
})
}
res.status(200).json(docs);
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
})
My angular GET method goes like this :
getSearchedImages(min, max) {
let params = {
'min': String(min),
'max': String(max)
}
this.http.get('http://localhost:3000/', { params: params})
.subscribe(val=> console.log(val))
}
Is there any problem in Angular part or is my code in Node is to be adjusted
Use POST if you want to pass parameters in request body. Otherwise, if you like GET, pass parameters in URL.
HTTP itself doesnt restrict this, but some front-end implementations do

Express/Mongoose is only saving partial request data to database

I think this is related to how I've defined my schemas, but I can't seem to find where the bug is... I have an almost identical file set up that's working perfectly and I've unfortunately not been able to find a duplicate of this issue anywhere.
When sending an API request to my local Express instance via Postman, only the 'title' request body value is stored in the database. I am sending the following simple request to my route as Application/Json (thought the same happens when using x-www-form-urlencoded):
{
"postTitle": "title goes here",
"postContent": "body goes here",
"isPublished": true
}
This is clearly being registered in express, as if I log the object I can see this data (plus timestamps and an _id):
{ _id: 5b07d9c0b8124e0599079c04,
postTitle: 'title goes here',
postContent: 'body goes here',
isPublished: true,
createdAt: 2018-05-25T09:39:12.869Z,
updatedAt: 2018-05-25T09:39:12.869Z,
__v: 0 }
However, when I send a get request to my route on this object using its ID, I receive the following in response:
{ "_id": "5b07d9c0b8124e0599079c04" }
Likewise, if I send a request to list all objects, I receive the following response:
{
"posts": [
{
"_id": "5b07d9c0b8124e0599079c04"
},
{
"_id": "5b07d9c0b8124e0599079c03"
},
{
"_id": "5b07d9914f10ce058f137eba"
}
]
}
Weirdly, sometimes the post title sent as part of the response is included in the response, and sometimes it isn't.
My schema is as follows:
var postSchema = new Schema({
postTitle: String,
postContent: String,
isPublished: Boolean
},
{
timestamps: true
});
My post API route for POST requests is as follows:
router.post('/posts', (req, res, next) => {
var postTitle = req.body.postTitle;
var postContent = req.body.postContent;
var isPublished = req.body.isPublished;
var newPost = new Post({
postTitle: postTitle,
postContent: postContent,
isPublished: isPublished
});
newPost.save(function (error) {
if (error) {
console.log(error)
}
res.send({
success: true,
message: 'Post saved successfully!'
})
})
});
(If you're not using Router, you'll have 'app.post' instead of 'router.post') Again, this is a bit longwinded but everything works fine.
My GET route is as follows:
router.get('/posts', (req, res) => {
Post.find({}, 'title content published', function (error, posts) {
if (error) { console.error(error); }
res.send({
posts: posts
})
}).sort({_id:-1})
});
OK - so, by going through my code in detail I've figured out where I was going wrong and fixed the issue, however, in my searching I found very little in the way of results. I'm pretty new to Express, so I'm going to outline the cause of the issue and how I resolved it in order to potentially save someone else a bunch of time if they make the same stupid mistake.
Now, the issue I'm having results from the way I was retrieving the data and serving that in response to get requests. As an example, here's my GET route to list all of the objects.
I was entirely focusing on the post request and assuming it was a problem with the database. It turns out what I'd actually done, is in order to make my schemas and routes less confusing, I'd changed the names of the relevant variables. What I'd forgotten to do, however, is update this line in my GET route to reflect the change:
Post.find({}, 'postTitle postContent isPublished', function (error, posts) {
Which I'd left as:
Post.find({}, 'title content published', function (error, posts) {
The reason the title sometimes displayed is that I tried undoing changes back and forth to spot the issue.
I know this is a super basic query but I got stuck on this for the best part of a day, and the only other relevant discussion on this ended with OP saying that it magically fixed itself.

Request params do not contain proper values

I'm using Mongoose to build a REST API using NodeJs and am running into issues with the params of req.
The code I'm using (model) is as follows:
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var RequestSchema = new Schema({
query: {
type: String,
default: ''
},
number: {
type: String,
default: ''
},
subject: {
type: String,
default: ''
}
});
module.exports = mongoose.model('Cel', RequestSchema)
However, when I use the following code from my controller (answerQuery is used for a POST request) and print out the values I find unexpected values :
exports.answerQuery = function(req, res) {
console.log('query is : ' + req.params.query); // this is undefined
console.log('query is : ' + req.body.query); // this is the value of query
console.log('query is: ' + req.params.number); // this is the value of number
console.log('subject is : ' + req.params.subject); // this is undefined
};
I understand why req.body.query works but am confused as to why req.params.query and req.params.subject don't work (return undefined) but req.params.number does. I haven't used Javascript a lot and think that I might be missing something here.
Edit 0: I'm using a POST request for this
Edit 1: This is my route file:
'use strict';
module.exports = function(app) {
var celRequest = require('../controllers/celSearchController');
// Routes
app.route('/celsearch/:number')
.post(celRequest.answerQuery);
};
Your route is this:
POST /celsearch/:number
This defines one parameter, number. Parameters are accessed through req.params, which is why req.params.number works.
You are trying to access req.params.subject, referring to a parameter called subject, which doesn't exist. Therefore, it's undefined. Same goes for req.params.query.
Because it's a POST route, and it's most common to pass data to POST routes using the request body, that data ends up in req.body. Since the client is passing a parameter called "query" in the request body, req.body.query works.
So:
req.params is used for route parameters, the :NAME placeholders in the route declaration;
req.body is used for parameters passed in the request body, commonly used for POST requests;
req.query is used for parameters passed in the URL as a query string: /foo/bar?query=somevalue. This is generally used for GET requests.

Cannot return id specific mongo documents in Angular controller

Trying to return a list of articles specific to a sectionId in angular controller. I can get back the entire list of articles using articles.query but the passed sectionId query param gets completely ignored. I tried a to abstract it to an articles service but I'm not sure how to build services correctly yet so it threw more errors. Any help / examples of how I might achieve this, preferable as a service, would be great. I am using mean.js. Thanks in advance!
Sections controller
angular.module('sections').controller('SectionsController', ['$scope', '$stateParams', '$location', 'Authentication', 'Sections', 'SectionArticlesList', 'Articles',
function($scope, $stateParams, $location, Authentication, Sections, SectionArticlesList, Articles) {
..........
// Find existing Section
$scope.findOne = function() {
$scope.section = Sections.get({
sectionId: $stateParams.sectionId // sections return fine
});
// problem starts here
$scope.articles = Articles.query({
section:$stateParams.sectionId // this param is ignored
});
$scope.articles.$promise.then(function(data) {
// all articles in collection returned instead of section specific
console.log('Articles: '+ JSON.stringify(data));
$scope.articles = data;
});
Articles Model
var ArticleSchema = new Schema({
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true,
required: 'Title cannot be blank'
},
content: {
type: String,
default: '',
trim: true
},
section: {
type: Schema.ObjectId,
ref: 'Section'
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
UPDATE:
Following up on the advice of Kevin B and Brad Barber below, I tried adding a factory and node server route, passing the $stateParams.sectionId to the specific factory instance. I created a new route in the articles.routes.server to make sure not to have a conflict with the standard ‘/articles/:articleId’ route. Unfortunately, anything I try still either throws errors or everything in the articles collection which is the opposite of what I want to do.
section.client.controller
// Find existing Section
$scope.findOne = function() {
$scope.section = Sections.get({
sectionId: $stateParams.sectionId
});
// fails no matter what is passed to query
$scope.articles = SectionArticlesList.query($stateParams.sectionId);
//$scope.SectionArticlesList.query($stateParams.sectionId);
//$scope.articles = SectionArticlesList.query({sectionId});
$scope.articles.$promise.then(function(data) {
// still only ever returns full list of articles
console.log('Length of articles: '+ JSON.stringify(data.length));
$scope.articles = data;
});
….
articles.client.services
angular.module('articles').factory('SectionArticlesList', ['$resource',
function($resource) {
return $resource('articles/:articleSectionId', {
articleSectionId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
]);
articles.server.routes
// Custom route
app.route('/articles/:articleSectionId')
.get(articles.listBySectionID);
// Custom binding
app.param('articleSectionId', articles.listBySectionID);
articles.server.controller
The server side controller function never appears to get called because neither of the console.logs show up.
exports.listBySectionID = function(req, res, id) {
console.log('listBySection Called....'); // this is never printed
// have tried passing - id, sectionId and {section:id}
Article.find( {section:id} ).sort('-created').populate('user', 'displayName').exec(function(err, articles) {
if (err) {
console.log('listBySection err triggered...'); // this neither
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(articles);
}
});
};
I think I have tried everything I can think of to pass the sectionId correctly but nothing has worked yet. The latest error in the console is the 404 below.Interestingly the sectionId IS getting through but as if it is looking for one single resource such as a single blog post.
GET /sectionArticles?sectionId=555bfaf29a005c30cbfe6931 404
I don't quite understand how the default mean.js /articles route and it's corresponding list function works but duplicating a similar structure and passing an id as a param to the query to retrieve only specific results doesn't.
Would really like to understand how this should be wired up. If anyone can point out what I am doing wrong I’d appreciate it!

AngularJS app isn't passing data correctly to Node?

I'm not even exactly sure what the problem is here, I've been trying to figure it out for a couple days. I'm somewhat new to the MEAN stack, so I'm probably missing something obvious. I basically copied the boilerplate code for the mean.io back-end controllers, models, and routes and Angular controllers, views, and services. I'm now getting this error when I create a new Client via the browser:
CastError: Cast to ObjectId failed for value "undefined" at path "_id"
at ObjectId.cast (/Users/d/Web/personal/mean-app/node_modules/mongoose/lib/schema/objectid.js:116:13)
at ObjectId.castForQuery (/Users/d/Web/personal/mean-app/node_modules/mongoose/lib/schema/objectid.js:165:17)
at Query.cast (/Users/d/Web/personal/mean-app/node_modules/mongoose/lib/query.js:2270:32)
at Query.findOne (/Users/d/Web/personal/mean-app/node_modules/mongoose/lib/query.js:1117:10)
at Query.exec (/Users/d/Web/personal/mean-app/node_modules/mongoose/node_modules/mquery/lib/mquery.js:2181:16)
at Query.exec (/Users/d/Web/personal/mean-app/node_modules/mongoose/lib/query.js:1748:19)
at Function.ClientSchema.statics.load (/Users/d/Web/personal/mean-app/app/models/client.js:80:48)
at exports.client (/Users/d/Web/personal/mean-app/app/controllers/clients.js:15:12)
at paramCallback (/Users/d/Web/personal/mean-app/node_modules/express/lib/router/index.js:151:7)
at param (/Users/d/Web/personal/mean-app/node_modules/express/lib/router/index.js:133:11)
controllers/clients.js:
exports.client = function(req, res, next, id) {
Client.load(id, function(err, client) {
if (err) return next(err);
if (!client) return next(new Error('Failed to load client ' + id));
req.client = client;
next();
});
};
models/client.js:
ClientSchema.statics.load = function(id, cb) {
this.findOne({ _id: id }).populate('user').exec(cb);
};
When I insert a client via the mongo shell manually (db.clients.save({ name: "Bob" })), it saves and appears in Node, but when I go to edit it via the Angular view, it can't save, giving me a similar error:
TypeError: Cannot read property 'id' of undefined
I'm thinking that perhaps this means that my back-end code is find and it's the front-end code that isn't communicating all the necessary data to the back-end. For reference:
public/js/controllers/clients.js
angular.module('mean.clients').controller('ClientsController', ['$scope', '$routeParams', '$location', 'Global', 'Clients', function ($scope, $routeParams, $location, Global, Clients) {
$scope.global = Global;
$scope.create = function() {
var client = new Clients({
name: this.name,
contactName: this.contactName
});
client.$save(function(response) {
$location.path('clients/' + response._id);
});
this.name = '';
this.contactName = '';
};
// etc.
}]);
public/js/services/clients.js
angular.module('mean.clients').factory('Clients', ['$resource', function($resource) {
return $resource('clients/:clientId', {
clientId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}]);
You will need to include the _id in your client object.

Categories