How to know which params is missing in a query? - javascript

I'm setting up a Booking router in NodeJS, and I have many params in.
Now when I forgot params I return an error like :
500: Need more information
I wonder if it's possible to know which params are missing when I return the error code.
This is for a new API made in NodeJS
Here are the params that I want to retrieve from the front ( made in ReactJS )
let body = {
agentDutyCode: "STRING",
RatePlanCode: params.rateCode,
RoomCode: params.roomCode,
AmountAfterTax: params.amountTax,
Start: params.fromDate,
End: params.toDate,
CardCode: params.cardCode,
CardNumber: params.cardNumber,
ExpireDate: params.expireDate,
SeriesCode: params.cvv,
CardHolderName: params.nameCard,
ChainCode: params.chainCode,
HotelCode: params.hotelCode,
RoomQuantities: params.roomQuantities,
GuestQuantitie: params.numberGuest,
GuestPerRoom: params.guestPerRoom,
LastName: params.lastName,
FirstName: params.firstName,
PhoneNumber: params.phoneNumber,
email: params.email,
FVL_SUBUNIT_7: params.walletAddress
}
And this is my promise :
cdsJson.bookResource(req.body)
.then((response) => {
if (response !== null) {
res.response = {
...response
}
} if (response.hotel.length === 0) {
res.respStatus = 500
res.response = {
sendMsg: "Need more informations"
}
next('route')
}
return response
})
If the request succeeds I got a reservation ID otherwise I got :
Error 500: Need more information

Read the documentation or the source code.
Seriously. If the API response doesn't tell you in the error message, then there is no way to know what parameters it expects programmatically.

try it for a for ... in loop like this:
cdsJson.bookResource(req.body)
.then((response) => {
if (response !== null) {
res.response = {
...response
}
} if (response.hotel.length === 0) {
res.respStatus = 500
let errorStr = "Need more informations"
for(var key in req.body) { // Get all parameters that are not set
if(objects[key] == undefined)
errorStr += "\nParameter ["+key+"] is missing!"
}
res.response = {
sendMsg: errorStr
}
next('route')
}
return response
})

You're trying to do server side validation. In Node a good approach would be to define a JSON Schema for the expected parameters and then in your route handler validate the data sent in the request with a JSON Schema validator. This would help you work out whether a request was valid and help you generate error messages automatically. As a rule it's much better (i.e. simpler and more maintainable) to use tools that enable you to declaratively declare your validation (via a schema) than imperatively write code to manually validate objects.
JSON Schema spec https://json-schema.org/
A validator https://github.com/epoberezkin/ajv

Related

HubspotClient - Update contact by email id is not working

In NodeJS, I'm using "#hubspot/api-client": "^7.1.2".
Created hubspot client using accessToken as follows
const hubSpotClient = new hubspot.Client({ accessToken });
When I try to update the contact using email it's throwing error
Request:
const idProperty = 'email';
const response = await hubSpotClient(store).crm.contacts.basicApi.update(email, idProperty, contact);
Response:
ERROR {
"statusCode": 404,
"body": {
"status": "error",
"message": "Object not found. objectId are usually numeric.",
"correlationId": "71e911d3...",
"context": {
"id": [
"testemail#..."
]
},
"category": "OBJECT_NOT_FOUND"
}
Create contact is working fine with this client but updating by email is not working.
Anything out of place or syntax error in passing the idProperty?
The problem is in your implementation, because it seems like you are not using properly the Hubspot API.
If you check the function signature of the basicApi.update
public async update(contactId: string, simplePublicObjectInput: SimplePublicObjectInput, idProperty?: string, _options?: Configuration): Promise<RequestContext> {
Basically, you need to pass down a contactId, and then a simplePublicObjectInput that is basically an object that represents your update.
Your code should look like this:
import { Client } from "#hubspot/api-client";
const hubspotClient = new Client({ accessToken: YOUR_ACCESS_TOKEN });
const contactID = 1234;
const response = await hubspotClient.crm.contacts.basicApi.update(contactID, {
properties: { email: 'my-new-email#gmail.com' },
})
Keep in mind that Hubspot always tries to follow their same guidelines as their endpoints. If your check the endpoint specification you will see the following:
Think about the Hubspot node client as just an abstraction of some http client, but at the end does exactly the same as the endpoints described in their implementations.
For that reason, in your implementation, Hubspot is returning an appropriated error, since you are not giving the contactId in the first argument, Hubspot is telling you: "Object not found. objectId are usually numeric." Because indeed a Contact ID is numeric and you are using the value of an email --string-- instead.
If you want to "update by email"
I think that there is no direct way to do it, you might need to do a previous search of the contact by email.
You could use the searchApi.
And after getting the id just run the update.
const searchResponse = await hubspotClient.crm.contacts.searchApi.doSearch({
filterGroups: [
{
filters: [
{
value: 'email-to-search#gmail.com',
propertyName: 'email',
operator: 'EQ',
},
],
},
],
sorts: [],
properties: [],
limit: 1,
after: 0,
});
// Off course you need to improve a lot the error handling here and so on.
// This is just an example
const [contactID] = searchResponse.results;
const contactUpdateResponse = await hubspotClient.crm.contacts.basicApi.update(contactID, {
properties: { email: 'my-new-email#gmail.com' },
})
I hope this helps you!
You CAN use email as the idProperty for the hubspot/api-client get contact function, but it only works if you fill in all the other query fields before idProperty, even if they are undefined.
Here is my example of a getContactByEmail as a Google Cloud Function in Node, using the api-client, and it works great!
exports.getContactByEmail = functions.https.onCall(async (data, context) => {
const email = data.email;
const contactId = email;
const properties = ["firstname", "lastname", "company"];
const propertiesWithHistory = undefined;
const associations = undefined;
const archived = false;
const idProperty = "email";
try {
const apiResponse = await hubspotClient.crm.contacts.basicApi.getById(
contactId,
properties,
propertiesWithHistory,
associations,
archived,
idProperty
);
console.log(JSON.stringify(apiResponse.body, null, 2));
return apiResponse.properties;
} catch (error) {
error.message === "HTTP request failed"
? console.error(JSON.stringify(error.response, null, 2))
: console.error(error);
return error;
}
});

Feathers-mongoose : Get by custom attribute in feathers-mongoose

I have a very basic feathers service which stores data in mongoose using the feathers-mongoose package. The issue is with the get functionality. My model is as follows:
module.exports = function (app) {
const mongooseClient = app.get('mongooseClient');
const { Schema } = mongooseClient;
const messages = new Schema({
message: { type: String, required: true }
}, {
timestamps: true
});
return mongooseClient.model('messages', messages);
};
When the a user runs a GET command :
curl http://localhost:3030/messages/test
I have the following requirements
This essentially tries to convert test to ObjectID. What i would
like it to do is to run a query against the message attribute
{message : "test"} , i am not sure how i can achieve this. There is
not enough documentation for to understand to write or change this
in the hooks. Can some one please help
I want to return a custom error code (http) when a row is not found or does not match some of my criterias. How can i achive this?
Thanks
In a Feathers before hook you can set context.result in which case the original database call will be skipped. So the flow is
In a before get hook, try to find the message by name
If it exists set context.result to what was found
Otherwise do nothing which will return the original get by id
This is how it looks:
async context => {
const messages = context.service.find({
...context.params,
query: {
$limit: 1,
name: context.id
}
});
if (messages.total > 0) {
context.result = messages.data[0];
}
return context;
}
How to create custom errors and set the error code is documented in the Errors API.

Loopback is not responding with modified data after 'loaded' hook

I have the following code in my Model.js file.
Model.observe('loaded', (ctx, next) => {
const {
data,
options: {
user
}
} = ctx;
const owner = (user && data && user.uid === data.userId) || false;
console.log(
`${data.id}: loaded - access by ${user && user.name}, owner:${owner}`
);
if (!owner) {
delete data.testProp1;
}
console.log('returning: ', ctx.data);
next();
});
When I make a request, I see the following log output (server logs):
f3f9ffd6-14dc-42e5-94ba-503aa3426faa: loaded - access by User1, owner:false
returning:
{
testProp2: true,
id: 'f3f9ffd6-14dc-42e5-94ba-503aa3426faa',
userId: 'sfeywkKSuBTlf0DwE4ZOFd8RX5E3'
}
But then in the actual response the browser receives I actually get:
{
testProp1: true,
testProp2: true,
id: 'f3f9ffd6-14dc-42e5-94ba-503aa3426faa',
userId: 'sfeywkKSuBTlf0DwE4ZOFd8RX5E3'
}
Is there something in the documentation I am missing? Deleting the property is exactly what it shows in the Loopback docs here. Also, I actually see the modified data as the data property on the ctx object before calling next(). Anyone run into this issue or know some caveat to the docs that isn't explicitly stated?

Returning a record with a string in ember

I am trying to implement a search function where a user can return other users by passing a username through a component. I followed the ember guides and have the following code to do so in my routes file:
import Ember from 'ember';
export default Ember.Route.extend({
flashMessages: Ember.inject.service(),
actions: {
searchAccount (params) {
// let accounts = this.get('store').peekAll('account');
// let account = accounts.filterBy('user_name', params.userName);
// console.log(account);
this.get('store').peekAll('account')
.then((accounts) => {
return accounts.filterBy('user_name', params.userName);
})
.then((account) => {
console.log(account);
this.get('flashMessages')
.success('account retrieved');
})
.catch(() => {
this.get('flashMessages')
.danger('There was a problem. Please try again.');
});
}
}
});
This code, however, throws me the following error:
"You cannot pass '[object Object]' as id to the store's find method"
I think that this implementation of the .find method is no longer valid, and I need to go about returning the object in a different manner. How would I go about doing this?
You can't do .then for filterBy.
You can't do .then for peekAll. because both will not return the Promise.
Calling asynchronous code and inside the searchAccount and returning the result doesn't make much sense here. since searchAccount will return quickly before completion of async code.
this.get('store').findAll('account',{reload:true}).then((accounts) =>{
if(accounts.findBy('user_name', params.userName)){
// show exists message
} else {
//show does not exist message
}
});
the above code will contact the server, and get all the result and then do findBy for the filtering. so filtering is done in client side. instead of this you can do query,
this.store.query('account', { filter: { user_name: params.userName } }).then(accounts =>{
//you can check with length accounts.length>0
//or you accounts.get('firstObject').get('user_name') === params.userName
//show success message appropriately.
});
DS.Store#find is not a valid method in modern versions of Ember Data. If the users are already in the store, you can peek and filter them:
this.store.peekAll('account').filterBy('user_name', params.userName);
Otherwise, you'll need to use the same approach you used in your earlier question, and query them (assuming your backend supports filtering):
this.store.query('account', { filter: { user_name: params.userName } });

Meteor - How to find out if Meteor.user() can be used without raising an error?

I'm looking for a way to determine if Meteor.user() is set in a function that can be called both from the server and client side, without raising an error when it is not.
In my specific case I use Meteor server's startup function to create some dummy data if none is set. Furthermore I use the Collection2-package's autoValue -functions to create some default attributes based on the currently logged in user's profile, if they are available.
So I have this in server-only code:
Meteor.startup(function() {
if (Tags.find().fetch().length === 0) {
Tags.insert({name: "Default tag"});
}
});
And in Tags-collection's schema:
creatorName: {
type: String,
optional: true,
autoValue: function() {
if (Meteor.user() && Meteor.user().profile.name)
return Meteor.user().profile.name;
return undefined;
}
}
Now when starting the server, if no tags exist, an error is thrown: Meteor.userId can only be invoked in method calls. Use this.userId in publish functions.
So in other words calling Meteor.user() on the server startup throws an error instead of returning undefined or null or something. Is there a way to determine whether it will do so prior to calling it?
I cannot solve this simply by wrapping the call with if (Meteor.isServer) within the autoValue function, as the autoValue functions are normally called from server side even when invoked by the user, and in these cases everything in my code works fine.
Note that this is related to How to get Meteor.user() to return on the server side?, but that does not address checking if Meteor.user() is available in cases where calling it might or might not result in an error.
On the server, Meteor.users can only be invoked within the context of a method. So it makes sense that it won't work in Meteor.startup. The warning message is, unfortunately, not very helpful. You have two options:
try/catch
You can modify your autoValue to catch the error if it's called from the wrong context:
autoValue: function() {
try {
var name = Meteor.user().profile.name;
return name;
} catch (_error) {
return undefined;
}
}
I suppose this makes sense if undefined is an acceptable name in your dummy data.
Skip generating automatic values
Because you know this autoValue will always fail (and even if it didn't, it won't add a useful value), you could skip generating automatic values for those inserts. If you need a real name for the creator, you could pick a random value from your existing database (assuming you had already populated some users).
Been stuck with this for two days, this is what finally got mine working:
Solution: Use a server-side session to get the userId to prevent
"Meteor.userId can only be invoked in method calls. Use this.userId in publish functions."
error since using this.userId returns null.
lib/schemas/schema_doc.js
//automatically appended to other schemas to prevent repetition
Schemas.Doc = new SimpleSchema({
createdBy: {
type: String,
autoValue: function () {
var userId = '';
try {
userId = Meteor.userId();
} catch (error) {
if (is.existy(ServerSession.get('documentOwner'))) {
userId = ServerSession.get('documentOwner');
} else {
userId = 'undefined';
}
}
if (this.isInsert) {
return userId;
} else if (this.isUpsert) {
return {$setOnInsert: userId};
} else {
this.unset();
}
},
denyUpdate: true
},
// Force value to be current date (on server) upon insert
// and prevent updates thereafter.
createdAt: {
type: Date,
autoValue: function () {
if (this.isInsert) {
return new Date;
} else if (this.isUpsert) {
return {$setOnInsert: new Date};
} else {
this.unset();
}
},
denyUpdate: true
},
//other fields here...
});
server/methods.js
Meteor.methods({
createPlant: function () {
ServerSession.set('documentOwner', documentOwner);
var insertFieldOptions = {
'name' : name,
'type' : type
};
Plants.insert(insertFieldOptions);
},
//other methods here...
});
Note that I'm using the ff:
https://github.com/matteodem/meteor-server-session/ (for
ServerSession)
http://arasatasaygin.github.io/is.js/ (for is.existy)

Categories