Why is my JSON invalid when making post request? (Postgres, Knex) - javascript

I've been playing around with this for a while, and I have to say I'm rather stumped.
I have a table called "physical_sites", and created the column "history" as a "json" type in this table.
My API request function is as follows:
const response = await fetch(BASE_URL + "physical_sites", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ data: jobSite }),
});
With my incoming data as:
{
"physical_site_name": "Here",
"physical_site_loc": "test",
"created_by": "ME",
"status": "Active",
"history": [{
"action_date": "2022-07-21T01:22:44.056Z",
"action_taken": "Create Job Site",
"action_by": "me",
"action_by_id": 24,
"action_comment": "Initial Upload",
"action_key": "1jt9JPRLy7RHJUwmz3kqoy98u"
}]
}
I will continually be adding items to the 'array' in history, so there will be multiple objects here. I checked this in an online JSON validator, and it seems correct.
Lastly, my "create" function in the controller is as follows:
async function create(req, res) {
const result = req.body.data;
console.log(result);
const data = await knex("physical_sites")
.insert(result)
.returning("*")
.then((results) => results[0]); //insert body data into assets
res.status(201).json({ data });
}
Fairly simple.
However, I keep getting this error:
message: 'insert into "physical_sites" ("created_by", "history", "physical_site_loc", "physical_site_name", "status") values ($1, $2, $3, $4, $5) returning
* - invalid input syntax for type json'
Not exactly sure what is going on, can someone help me understand what I'm missing?
Thanks.

Most likely one of you column for this table has a JSON type. I believe that it is the history column.
You could parse the history property to String before sending the request.
// ...
body: JSON.stringify({
data: {
...jobSite,
history: JSON.parse(jobSite.history)
}
}),
// ...

Related

sending value of my textarea with graphql

I hope you all have a great day. I am coding my own personal website and I have a section called to contact me. The problem I have with this section is that I am trying to send my client email to my email and when I am trying to send their message to my server through Graphql I get this error
[
{
"message": "Syntax Error: Unterminated string.",
"locations": [
{
"line": 3,
"column": 123
}
]
}
]
the request I sent to my server is
'\n mutation{\n sendEmail(EmailInput: {name: "Test name", email: "Test#email.com",
subject: "this is test subject", message: "\n
this is the first line \nthis is the second line\nwhen I have multiple lines I have these problem\n
"}) {\n success\n message\n }\n }\n '
I don't know how to fix it I don't know why I get this error.
I used fetch to send my code backend :
const emailMutationQuery = `
mutation{
sendEmail(EmailInput: {name: "${senderName.value}", email: "${senderEmail.value}", subject: "${senderSubject.value}", message: "
${senderMessage.value}
"}) {
success
message
}
}
`;
const result = await fetch("http://localhost:2882/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
query: emailMutationQuery,
}),
});
const convertedResult = await result.json();
GraphQL supports variables, which can be used to supply input data separately from the query. The variables are just a separate JSON-encoded object. This avoids syntactic difficulties (and potential security risks!) from trying to embed the inputs directly in the query.
For this you'd write a fixed query, that declares and uses the variable, but doesn't depend on the per-request inputs
const emailMutationQuery = `
mutation SendEmail($emailInput: SendEmailInput!) {
sendEmail(EmailInput: $emailInput) {
success
message
}
}
`;
You'd then create a second object containing the variable(s). The top-level keys match what you declare in the GraphQL operation line, and their content matches the corresponding GraphQL input types.
const variables = {
emailInput: {
name: senderName.value,
email: senderEmail.value,
subject: senderSubject.value,
message: senderMessage.value
}
};
Note that this is an ordinary Javascript object, and we haven't quoted or escaped anything here.
Now when we make the request, we send the query and variables together
const result = await fetch("http://localhost:2882/graphql", {
...,
body: JSON.stringify({
query: emailMutationQuery,
variables: variables
})
});
Things like newlines in the message content will be escaped in the variables block, and get passed through correctly to the underlying GraphQL engine.
I actually find a solution for it but feel free to share your answers here. The solution I found for this problem was that you have to use JSON.stringify() for the textarea. you have to pass your textarea value to this function and js will take care of the rest. my code now looks like this
const emailMutationQuery = `
mutation{
sendEmail(EmailInput: {name: "${senderName.value}", email: "${senderEmail.value}", subject: "${senderSubject.value}",
message:${JSON.stringify(senderMessage.value)}}) {
success
message
}
}
`;
I hope this help you guys.

Mongo findById() only works sometimes even when passed a valid ID

I am having a strange issue querying a Mongo DB collection. I am using findById() to get a single item that works sometimes and not others.
I have checked the id being passed to the server route and in all cases, they match perfectly with the targeted document in the collection.
Here is the basic code:
router.get("/:postId", async (req, res) => {
console.log('id : ', req.params.postId)
console.log('type: ', typeof(req.params.postId)) // id is a string
try {
const post = await Post.findById(req.params.postId).exec();
console.log('post :', post) // sometimes null
res.json(post);
} catch (err) {
res.json({ message: err });
}
});
In the above route, only certain posts will be found while others come back null. This happens regardless of whether the id passed is correct and the document exists with the exact id.
If anyone has any ideas about what could be going wrong here I'd much appreciate the help!
EDIT
I have done some more debugging and think it is something to do with the Schema for the Post model.
For example, this object will be found:
{
"tags": ["foo"],
"_id": "8394839483fhg020834903",
"title": "bar",
"content": "baz",
"isPrivate": true,
}
But this one will not because of the missing isPrivate property.
{
"tags": [],
"_id": "5e0fdc631ef5c46b285a4734",
"title": "New post",
"content": "Some content here",
}
I have tested this across multiple queries and it appears to the root of the problem.
I have tried adding
isPrivate: {
required: false
}
To the Schema but it doesn't seem to solve the issue.
Here is the full Schema
const postSchema = mongoose.Schema({
title: {
type: String,
required: true
},
content: {
type: String,
required: true
},
tags: [{ type: String }],
date: {
type: Date,
default: Date.now
},
isPrivate: {
type: Boolean
required: false
}
});
I'm not a Mongo/Mongoose expert, so any guidance would be much appreciated.
If post id match with any record it return data, otherwise it will return null. You should handle the exception
router.get("/:postId", async (req, res) => {
try {
const post = await Post.findById(req.params.postId).exec();
if(post) {
return res.json(post);
}
res.json({ message:'No Post found' });
} catch (err) {
res.json({ message: err });
}
});
You can manually check is record exists against a post id. You can use MongoDB Compass for gui browse the record
I believe the issue might be with your _id as per mongo standard _id should be a String is of 12 bytes or a string of 24 hex characters.
We can check if the _id is valid using mongoose.isValidObjectId()
I did run this check on your objects that you posted and indeed 1 is invalid while other is valid
const mongoose = require('mongoose');
console.log(`is '8394839483fhg020834903' valid - ${mongoose.isValidObjectId('8394839483fhg020834903')}`);
console.log(`is '5e0fdc631ef5c46b285a4734' valid - ${mongoose.isValidObjectId('5e0fdc631ef5c46b285a4734')}`);
It gives me
You will have to check what is modifying your ID's in the code, you can upload your schema to get a better understanding as well.

How do I query an index properly with Dynamoose

I'm using Dynamoose to simplify my interactions with DynamoDB in a node.js application. I'm trying to write a query using Dynamoose's Model.query function that will search a table using an index, but it seems like Dynamoose is not including all of the info required to process the query and I'm not sure what I'm doing wrong.
Here's what the schema looks like:
const UserSchema = new dynamoose.Schema({
"user_id": {
"hashKey": true,
"type": String
},
"email": {
"type": String,
"index": {
"global": true,
"name": "email-index"
}
},
"first_name": {
"type": String,
"index": {
"global": true,
"name": "first_name-index"
}
},
"last_name": {
"type": String,
"index": {
"global": true,
"name": "last_name-index"
}
}
)
module.exports = dynamoose.model(config.usersTable, UserSchema)
I'd like to be able to search for users by their email address, so I'm writing a query that looks like this:
Users.query("email").contains(query.email)
.using("email-index")
.all()
.exec()
.then( results => {
res.status(200).json(results)
}).catch( err => {
res.status(500).send("Error searching for users: " + err)
})
I have a global secondary index defined for the email field:
When I try to execute this query, I'm getting the following error:
Error searching for users: ValidationException: Either the KeyConditions or KeyConditionExpression parameter must be specified in the request.
Using the Dynamoose debugging output, I can see that the query winds up looking like this:
aws:dynamodb:query:request - {
"FilterExpression": "contains (#a0, :v0)",
"ExpressionAttributeNames": {
"#a0": "email"
},
"ExpressionAttributeValues": {
":v0": {
"S": "mel"
}
},
"TableName": "user_qa",
"IndexName": "email-index"
}
I note that the actual query sent to DynamoDB does not contain KeyConditions or KeyConditionExpression, as the error message indicates. What am I doing wrong that prevents this query from being written correctly such that it executes the query against the global secondary index I've added for this table?
As it turns out, calls like .contains(text) are used as filters, not query parameters. DynamoDB can't figure out if the text in the index contains the text I'm searching for without looking at every single record, which is a scan, not a query. So it doesn't make sense to try to use .contains(text) in this context, even though it's possible to call it in a chain like the one I constructed. What I ultimately needed to do to make this work is turn my call into a table scan with the .contains(text) filter:
Users.scan({ email: { contains: query.email }}).all().exec().then( ... )
I am not familiar with Dynamoose too much but the following code below will do an update on a record using node.JS and DynamoDB. See the key parameter I have below; by the error message you got it seems you are missing this.
To my knowledge, you must specify a key for an UPDATE request. You can checks the AWS DynamoDB docs to confirm.
var params = {
TableName: table,
Key: {
"id": customerID,
},
UpdateExpression: "set customer_name= :s, customer_address= :p, customer_phone= :u, end_date = :u",
ExpressionAttributeValues: {
":s": customer_name,
":p": customer_address,
":u": customer_phone
},
ReturnValues: "UPDATED_NEW"
};
await docClient.update(params).promise();

Cypress request : empty array in body

I'm finding myself in some troubles while testing my API with Cypress. (I'm using version 2.1.0)
I am sending a request to my endpoint, and want to verify how it is reacting when I am sending an empty array as a parameter. The problem is that somehow, Cypress must be parsing the body I am giving him, and removing the empty array.
My code is the following :
cy.request({
method: 'PUT',
url,
form: true,
body: {
name: 'Name',
subjects: []
}
})
.then((response) => {
expect(response.body).to.have.property('subjects');
const { subjects } = response.body;
expect(subjects.length).to.eq(0);
});
// API receives only the parameter name, and no subjects
When I am sending an empty array of subjects, the endpoint will delete all the associated subjects, and return the object with an empty array of subjects. It is working as it should, and my software in use is working as it should.
When Cypress is sending this request, the endpoint does not receive the parameter subjects. Which is for me a very different thing : I should not touch the subjects in this case.
Is there a way to avoid this "rewriting" by Cypress and send the body as I write it ?
The test works when setting form: false.
it.only('PUTs a request', () => {
const url = 'http://localhost:3000/mythings/2'
cy.request({
method: 'PUT',
url: url,
form: false,
body: {
name: 'Name',
subjects: []
}
})
.then((response) => {
expect(response.body).to.have.property('subjects');
const {
subjects
} = response.body;
expect(subjects.length).to.eq(0);
});
})
I set up a local rest server with json-server to check out the behavior.
If I try to PUT a non-empty array with form: true
cy.request({
method: 'PUT',
url: url,
form: true,
body: {
name: 'Name',
subjects: ['x']
}
})
looking at db.json after the test has run, I see the item index migrating into the key,
"mythings": [
{
"name": "Name",
"subjects[0]": "x",
"id": 2
}
],
so perhaps form means simple properties only.
Changing to form: false gives a proper array
{
"mythings": [
{
"name": "Name",
"subjects": ['x'],
"id": 2
}
],
}
which can then be emptied out by posting an empty array.

ExtJS - SyntaxError: missing ) in parenthetical

I am writing some code to educate myself in the ways of ExtJS. I am also new to JSON so hopefully this question will be easy for you to answer. I am trying to retrieve some data from a basic web service that I have written which should be returning its results as JSON (seeing as I am new to JSON - it could be that that is broken).
The error I am getting is
SyntaxError: missing ) in
parenthetical
The JSON that I am returning from my web service is
{
"rows": [
{
"id": "100000",
"genre_name": "Action",
"sort_order": "100000"
}, {
"id": "100002",
"genre_name": "Comedy",
"sort_order": "100002"
}, {
"id": "100001",
"genre_name": "Drama",
"sort_order": "100001"
}]
}
My ExtJS code is as below. The loadexception callback is where I have retrieved the JSON and error above from
var genres = new Ext.data.Store({
proxy: new Ext.data.HttpProxy({
method: 'POST',
url: 'http://localhost/extjs_training/Demo_WebService/Utility.asmx/GetGenres',
failure: function(response, options){
Ext.get('my_id').dom.innerHTML = 'Load failed: ' + response.status;
}
}),
reader: new Ext.data.JsonReader({
fields: ['id', 'genre_name'],
root: 'rows'
}),
listeners: {
loadexception: function (proxy, options, response, e) {
var result = response.responseText;
Ext.MessageBox.alert('Load failure', e + " ..... " + result);
}
}
});
var loadSuccess = genres.load({
callback: function(r, options, success){
Ext.get('my_id').dom.innerHTML = 'Load status: success=' + success;
}
});
Is the JSON you included above what is actually being returned from the call, or what you are anticipating it should look like? The string you included looks clean, but it looks like you formatted it as well. I'm not sure if the space after "id": is allowed, either. It might not be a big deal, though.
The missing parenthetical typically indicates that something in the JSON is wrong. It could be an extra character before/after the string. Use Firebug to examine what you are getting back, and make sure it is clear of any extra characters.
http://www.sencha.com/forum/showthread.php?10117-Solved-missing-%29-in-parenthetical.
Echoeing two statements was the reason in my case. So check your echoes again.

Categories