express-validator throwing error with valid field - express-validator

Did my best to follow the docs here, but I can't get this to work.
server.js
const express = require('express');
const app = express();
app.use(express.json())
app.use('/', index);
index.js
const router = express.Router()
const { check, validationResult } = require('express-validator/check')
router.post('/register', [
check('name').exists()
], function(req, res) {
const validationErrors = validationResult(req)
if (!validationErrors.isEmpty()) {
console.log("validationErrors.array()\n", validationErrors.array())
}
})
To test this, I am entering a valid name in the client, and it shows up just fine in req.body. Might be worth noting that req.body has the following structure:
{ userRegistrationForm:
{ name: 'John Doe',
email: 'john#example.com',
password: '',
gender: '',
birthMonth: 'Month',
birthDate: 'Day',
birthYear: 'Year' } }
The docs mention check('username').isEmail(),, but I don't know where 'username' is coming from, unless the check() method is looking at req.body by default.
No matter what I do (meaning I enter a valid name), I keep getting the same validation error:
[ { location: 'body',
param: 'name',
value: undefined,
msg: 'Invalid value' } ]
How do I correctly use the check() method?
Update:
I think I figured it out. I modified my client to pass req.body.name to the server (as opposed to req.body.userRegistrationForm.name), and check('name') seems to catch the error when I omit a name. Still, I'd like to get feedback on this issue.

express-validator maintainer here.
In order to select fields that are nested within other objects, you specify its path using dot notation*:
check('userRegistrationForm.name')
* I acknowledge that if you're asking, we may need better docs to cover this! PRs welcome.

I would like to add something that helped me here: Make sure to set the Content-Type header to application/json, or the validation always fails

Related

In Loopback 4, how to avoid update of few fields

In loopback framework, is there a way to avoid updates for few fields
Below code allows updates for all fields that is passed in the API request body.
async updateById(
#param.path.number('id') id: number,
#requestBody({
content: {
'application/json': {
schema: getModelSchemaRef(Todo, {partial: true}),
},
},
})
todo: Todo,
): Promise<void> {
await this.todoRepository.updateById(id, todo);
}
As far as I understand from your question, you want to update some part of the object in the database.
this.repo.updateById(id,objectYouWantToUpdate)
This is going to work perfectly, just send the data you want to update and not the whole object.
exclude key can help
schema: getModelSchemaRef(Todo, {partial: true, exclude: ['title']})

What is wrong with my timestamp in my MWS request?

If I submit a request to MWS via the scratchpad(AmazonServices/Scratchpad),
it is successful, and I am able to view the details of the successful request. In particular, the timestamp on the request looks like this:
&Timestamp=2018-08-14T18%3A30%3A02Z
If I literally take this timestamp, as is, and try to use it in my code to make the same exact request, I get an error:
<Message>Timestamp 2018-08-14T18%3A30%3A02Z must be in ISO8601
format</Message>\n
Here is the function I am trying to place it in: (some chars changed in sensitive params)
exports.sendRequest = () => {
return agent
.post('https://mws.amazonservices.com/Products/2011-10-01')
.query({
AWSAccessKeyId: encodeURIComponent('BINAJO5TPTZ5TTRLNGQA'),
Action: encodeURIComponent('GetMatchingProductForId'),
SellerId: encodeURIComponent('H1N1R958BK8TTH'),
SignatureVersion: encodeURIComponent('2'),
Timestamp: '2018-08-14T18%3A30%3A02Z',
Version: encodeURIComponent('2011-10-01'),
Signature: encodeURIComponent(exports.generateSignature()),
SignatureMethod: encodeURIComponent('HmacSHA256'),
MarketplaceId: encodeURIComponent('ATVPDKIKX0DER'),
IdType: encodeURIComponent('UPC'),
'IdList.Id.1': encodeURIComponent('043171884536')
})
.then(res => {
console.log('here is the response');
console.log(res)
})
.catch(error => {
console.log('here is the error');
console.log(error);
})
}
What is even more strange, is that this is the path the request is being sent to:
path: '/Products/2011-10-01?
AWSAccessKeyId=BINAJO5ZPTZ5YTTPNGQA&Action=GetMatchingProductForId&SellerId=H1N1R958ET8THH&SignatureVersion=2&Timestamp=2018-08-14T18%253A30%253A02Z&Version=2011-10-01&Signature=LwZn5of9NwCAgOOB0jHAbYMeQT31M6y93QhuX0d%252BCK8%253D&SignatureMethod=HmacSHA256&MarketplaceId=ATVPDKIKX0DER&IdType=UPC&IdList.Id.1=043171884536' },
The timestamp is not the same as the one I placed in the query. Why is this happening?
Your HTTP library is already doing the url-encoding for you, so you're double-encoding things. Remove all references to encodeURIComponent() and format your timestamp normally, with : and not %3A. Observe what happens to the generated URL.
Why? URL-encoding isn't safe to do repeatedly.
: becomes %3A with one pass, but it becomes %253A with a second pass, which is wrong.

Access loopback context/request from the model overridables

How is it possible to access the loopback context (or simple Express req object) from within the model's logic?
It is critical to be able to know more about the request itself (current user identity more than anything else) inside the model's logic. When I override a built-in method (via custom script or from the model.js file) or develop a custom remote method, I would like to access the Express req object.
As loopback.getCurrentContext() is declared to be buggy, I cannot use it.
Ideas?
PS:
I find this page confusing: http://loopback.io/doc/en/lb2/Using-current-context.html
First it's said (and marked in red as important!) it is not recommended to use LoopBackContext.getCurrentContext() and then it's used it in each example!?
What's the point to give examples that do not work? Should we simply ignore the complete page? If so, what about the context? :)
Any clarification on this topic is much appreciated.
You can get access to express req object by using remote hooks
var loopback = require('loopback');
module.exports = function (MyModel) {
MyModel.beforeRemote('findOne', function (ctx, model, next) {
//access to ctx.req
console.log(ctx.req.headers)
next()
})
MyModel.beforeRemote('my-custom-remote-method', function (ctx, model, next) {
console.log(ctx.req.headers)
next()
})
}
Sure, you can use a beforeRemote hook to modify the ctx.args property. This property is the input of the remote method (that is, custom or built-in). This way, you can copy a part of the request inside this property, and it will be passed to the build-in method
Example 1 with the built-in method findOne.
MyModel.beforeRemote('findOne', function (ctx, model, next) {
ctx.args.filter.extrafield = ctx.req.headers['some-header'];
next();
});
Then override the findOne method since it's what you want to do
MyModel.on('dataSourceAttached', function(obj){
var findOne = MyModel.findOne;
MyModel.findOne = function(filter, cb) {
console.log(filter.extrafield); // Print what was in the header
return findOne.apply(this, arguments);
};
});
And finally call the method with curl
curl -H "some-header: 'hello, world!'" localhost:3000/api/MyModel/findOne
Example 2 with a custom remote printToken, to help you understand further
MyModel.beforeRemote('printToken', function (ctx, model, next) {
ctx.args.token = ctx.req.headers['some-header'];
next();
});
MyModel.printToken = function(token, cb) {
console.log(token);
cb();
}
MyModel.remoteMethod(
'printToken',
{
accepts: {arg: 'token', type: 'string', optional: true}
}
);
Then call the remote with curl, and pass the expected header
curl -H "some-header: 'hello, world!'" localhost:3000/api/MyModel/printToken
EDIT: There is a simpler solution that only works for custom remote
When defining your remote method, it is possible to tell loopback to pass elements of the http request to your remote directly as an input argument
MyModel.remoteMethod(
'printToken',
{
accepts: [
{arg: 'req', type: 'object', 'http': {source: 'req'}},
{arg: 'res', type: 'object', 'http': {source: 'res'}}
]
}
);
This way, your remote can access the req and res objects. This is documented here

handle errors from the rest adapter

I'm using ember-data, and want to trap and display any errors returned by the rest adapter. I looked at the question here
I added the following code to my model definition:
becameInvalid: function(errors) {
alert ("here" + errors);
},
and the rest adapter returns a 422 (Unprocessable Entity) code
however, the alert doesn't show. Am I missing something, or just being a real newbie numpty?
update #1:
making some progress. The rest server returns the following Json:
{"errors":{ "lastName": ["LastName cannot be blank"] }}
the model has
becameInvalid: function(errors) { console.log(JSON.stringify(errors)); },
however, the console now has the following:
{"email":"jmls#foo,com","firstName":"Julian","id":"aa7c4b42-df64-8fb8-d213-0ad81‌​c9bc213","lastName":"","notes":"ccc"}
which seems to be the json of the record itself, not of the errors.
How can I get to the errors? I have tried
console.log(errors.get("errors.lastName")
but get undefined.
try:
becameError: function(object) {
}
I think that your are missing something, using becameInvalid worked for me.
For example:
App.Person = DS.Model.extend({
name: DS.attr('string') ,
becameInvalid: function(errors) {
alert(errors.get('errors.name').join(','));
}
});
Update
Following the suggestion of #fanta, in the commend. Maybe your problem is in the returned json, the expected is:
{
errors: {
field_a: ['error a', 'error b'],
field_b: ['error c']
}
}
Where field_a must be some field mapped on DS.attr(field_a).
Give a look in that sample http://jsfiddle.net/marciojunior/8maNq/
Try using the DS.rejectionHandler:
DS.rejectionHandler = function(reason) {
Ember.Logger.assert([reason, reason.message, reason.stack]);
throw reason;
};
This should catch all errors from the adapter.

Testing MongooseJs Validations

Does anyone know how to test Mongoose Validations?
Example, I have the following Schema (as an example):
var UserAccount = new Schema({
user_name : { type: String, required: true, lowercase: true, trim: true, index: { unique: true }, validate: [ validateEmail, "Email is not a valid email."] },
password : { type: String, required: true },
date_created : { type: Date, required: true, default: Date.now }
});
The validateEmail method is defined as such:
// Email Validator
function validateEmail (val) {
return /^[a-zA-Z0-9._-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/.test(val);
}
I want to test the validations. The end result is that I want to be able to test the validations and depending on those things happening I can then write other tests which test the interactions between those pieces of code. Example: User attempts to sign up with the same username as one that is taken (email already in use). I need a test that I can actually intercept or see that the validation is working WITHOUT hitting the DB. I do NOT want to hit Mongo during these tests. These should be UNIT tests NOT integration tests. :)
Thanks!
I had the same problem recently.
First off I would recommend testing the validators on their own. Just move them to a separate file and export the validation functions that you have.
This easily allows your models to be split into separate files because you can share these validators across different models.
Here is an example of testing the validators on their own:
// validators.js
exports.validatePresenceOf = function(value){ ... }
exports.validateEmail = function(value){ ... }
Here is a sample test for this (using mocha+should):
// validators.tests.js
var validator = require('./validators')
// Example test
describe("validateEmail", function(){
it("should return false when invalid email", function(){
validator.validateEmail("asdsa").should.equal(false)
})
})
Now for the harder part :)
To test your models being valid without accessing the database there is a validate function that can be called directly on your model.
Here is an example of how I currently do it:
describe("validating user", function(){
it("should have errors when email is invalid", function(){
var user = new User();
user.email = "bad email!!"
user.validate(function(err){
err.errors.email.type.should.equal("Email is invalid")
})
})
it("should have no errors when email is valid", function(){
var user = new User();
user.email = "test123#email.com"
user.validate(function(err){
assert.equal(err, null)
})
})
})
The validator callback gets an error object back that looks something like this:
{ message: 'Validation failed',
name: 'ValidationError',
errors:
{ email:
{ message: 'Validator "Email is invalid" failed for path email',
name: 'ValidatorError',
path: 'email',
type: 'Email is invalid'
}
}
}
I'm still new to nodeJS and mongoose but this is how I'm testing my models + validators and it seems to be working out pretty well so far.
You should use validate() method as a promise and test it with a tool that makes asserts for async stuff (ex: Chai as Promised).
First of all, require a promise library and switch out to the promise provider (for example Q):
mongoose.Promise = require('q').Promise;
Afterwards just, use asserts about promises:
it('should show errors on wrong email', function() {
user = new UserModel({
email: 'wrong email adress'
});
return expect(user.validate()).to.be.rejected;
});
it('should not show errors on valid email adress', function() {
user = new UserModel({
email: 'test#test.io'
});
return expect(user.validate()).to.be.fulfilled;
});