I'm working on posting data from a React Form to a Ruby on Rails API, about the React part, if just send the first item from an array using this code:
const submitOrderHandler = async (userData) => {
setIsSubmitting(true);
await fetch("http://localhost:3000/ordertemps", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(cartCtx.items[0]),//please include user: userData
});
setIsSubmitting(false);
setDidSubmit(true);
cartCtx.clearCart();
};
The Ruby on Rails API manage it and store it in the table, this is the output:
However, I need to store all the data selected by the user, so, to accomplish this task I updated my code like this:
const submitOrderHandler = async (userData) => {
const dataSelected = JSON.stringify(cartCtx.items);
console.log(dataSelected);
setIsSubmitting(true);
await fetch("http://localhost:3000/ordertemps", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(cartCtx.items),//please include user: userData
});
setIsSubmitting(false);
setDidSubmit(true);
cartCtx.clearCart();
};
The problem is I'm getting a 400 Status, so this is how the data looks from the FrontEnd:
This is the output from the Ruby on Rails Endpoint:
the source code of the Controller in charge to manage and store the data is this:
#POST /ordertemps
def create
#ordertemp = Ordertemp.new(ordertemp_params)
if #ordertemp.save
render json: #ordertemp
else
render error: { error: 'Unable to create an order'}, status: 400
end
end
private
def ordertemp_params
#params.require(:ordertemp).permit( :clientName, :clientId, :amount, :mealid, :name, :price)
params.require(:ordertemp).permit(:name, :amount, :price)
end
So, I'm assuming these facts:
the data is properly formatted from the FrontEnd.
For some reason my Ruby on Rails'Controller can't manage more than one element sent by the front end.
My question is: what am I missing in my controller to store all the data sent by the FrontEnd?
Thanks a lot for your comments
Update your controller code as below:
#POST /ordertemps
def create
begin
params['_json'].each do |ordertemp_params|
#ordertemp = Ordertemp.new(ordertemp_params)
#ordertemp.save
end
head :no_content
rescue => e
render json: { error: unable to create orders }, status: 400
end
end
Hope this will help you.
Related
So I have been trying to upload a excel file from the frontend using a post request to a Django backend, however whatever I do the request[FILES] python dictionary is empty.
Does anyone have an idea of why this would happen?
This is my POST view from the Django views.py file
#api_view(["POST"])
#csrf_exempt
def processFile(request, *args, **kwargs):
data = request.data
print(data.items())
print(str(data.get('file0')))
if len(request.FILES) == 0 :
print("empty files")
print(request.FILES)
return Response("ok")
And now the way I am making the POST request in the frontend.
const fileList = async (actualFiles) => {
var dataForm = new FormData();
console.log(actualFiles)
for(let i=0;i<actualFiles.length;i++) {
const id = 'file' + i;
console.log("appending file" + i)
dataForm.append(id, actualFiles[i])
}
const res = await fetch(`http://localhost:8000/process-file/`,
{
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data; boundary=----somefixedboundary'
},
body : dataForm,
})
const data = await res.json()
console.log("Data:" + data)
}
Worth mentioning: I have been trying for a while thinking the problem is in the request, however in the network tab on the browser I can see that it is all alright.
I am adding the content type and boundary because according to Django documentation if you do not add those the server will not be able to process the data.
Any ideas? Thank you in advance!
I am trying to send the contents of a flashcard to a backend route http://127.0.0.1:5000/post onClick and it works when I send the data to webhook.site but when I change it to http://127.0.0.1:5000/post I get the error " question = data['question' TypeError: 'NoneType' object is not subscriptable ". Here is the code for the fetch request: async function postData() {
try {
let result = await fetch('http://127.0.0.1:5000/post', {
method: 'POST',
mode: 'no-cors',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
key: `${Date.now()}`,
question: flashcard.question,
answer: flashcard.answer,
options: flashcard.options
})
});
} catch(e) {
console.log(e)
}
}
and here is the code for the backend route in flask:
#app.route('/post', methods=['GET', 'POST'])
def post():
data = request.get_json()
question = data['question']
answer = data['answer']
options = data['options']
key = data['key']
return jsonify({'question' : question, 'answer' : answer, 'options' : options, 'key' : key})
if __name__ == "__main__":
app.run(debug=True)
I get that the error is stating that "data" has no value which I assume means it's not recieving the JSON objects that I'm posting. It's weird because it works perfectly when I use a webhook.site url. can anyone help? thanks for your time!
I am trying to send the contents of a flashcard to a backend route http://127.0.0.1:5000/post onClick and it works when I send the data to webhook.site but when I change it to http://127.0.0.1:5000/post I get the error " question = data['question' TypeError: 'NoneType' object is not subscriptable ". Here is the code for the fetch request:
async function postData() {
try {
let result = await fetch('http://127.0.0.1:5000/post', {
method: 'POST',
mode: 'no-cors',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
key: `${Date.now()}`,
question: flashcard.question,
answer: flashcard.answer,
options: flashcard.options
})
});
} catch(e) {
console.log(e)
}
}
and here is the code for the backend route in flask:
#app.route('/post', methods=['GET', 'POST'])
def post():
#save data to db
data = request.get_json()
question = data['question']
answer = data['answer']
options = data['options']
key = data['key']
return jsonify({'question' : question, 'answer' : answer, 'options' : options, 'key' : key})
if __name__ == "__main__":
app.run(debug=True)
I get that the error is stating that "data" has no value which I assume means it's not recieving the JSON objects that I'm posting. It's weird because it works perfectly when I use a webhook.site url. can anyone help? thanks for your time!
Seems like your content is not a valid json request. If that is the case then content will be equal to None(not subscriptable).
Try to debug how data looks in flask and based on that you will know if its valid json.
I'm using Slim v4 for my REST API for testing purposes.
I want to fetch a JSON Data string to my REST API for saving some events.
public async callSaveEvent(event: EventList) {
let url: string = config.basePath + "eventList/saveEventList";
console.table(JSON.stringify(event));
await fetch(url, {
method: 'POST',
mode: 'no-cors',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ event })
}).then(response => {
if (!response.ok) {
throw new Error("Something is bad");
}
}).catch(error => {
console.error("Das ist passiert!: ", error);
});
}
This is my current Code. If I use the fetch.options.mode == "cors", I recieve in Slim that this Method is not allowed. Method is OPTIONS instead of POST. Because of this I using mode == "no-cors".
$param = $req->getParsedBody();
$param_ = $param;
$resp->getBody()->write($param);
return $resp;
}
This is my Backend Code. When I try to read the parsedBody, its just empty.
If I send a request with PostMan its accept the data and I get the data in the $param variable.
Can someone find some errors? I can't find them.
I have a Lambda function that handles reading data from a file(stored inside S3 bucket) as well as inserting data to a Dynamodb table. This Lambda function is exposed as a REST endpoint using API gateway. The function accepts GET request as well as POST request. I'm making GET/POST requests from my REACT project using axios and aws4(for signing) libraries. GET request is to read data from a file stored inside S3 and it works just fine. And POST request is for inserting data into Dynamodb table. However, it doesn't work and AWS returns InvalidSignatureException error as a respond. This is an excerpt of my code :
createAWSSignedRequest(postData) {
let request = {};
if (postData) {
request = {
host: process.env.AWS_HOST,
method: 'POST',
url: process.env.AWS_URL,
path: process.env.AWS_PATH,
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(postData)
}
} else {
request = {
host: process.env.AWS_HOST,
method: 'GET',
url: process.env.AWS_URL,
path: process.env.AWS_PATH
}
}
let signedRequest = aws4.sign(request, {
secretAccessKey: process.env.AWS_SECRET_KEY,
accessKeyId: process.env.AWS_ACCESS_KEY
});
return signedRequest;
}
This is how GET request is made :
let signedRequest = this.createAWSSignedRequest('GET');
axios(signedRequest)
.then(response => {
})
.catch((error) => {
console.log("error",error);
});
This is how POST request is made :
const data = {
uuid: "916b7d90-0137-11e8-94e6-116965754e23", //just a mock value
date : "22/jan/2018",
user_response: [
{
question:"this is quesiton1",
choice:"user selected A"
},
{
question:"this is quesiton2",
choice: "user selected b"
},
{
question:"this is quesiton3",
choice: "user selected C"
}
]
};
let signedRequest = this.createAWSSignedRequest(data);
axios(signedRequest)
.then(response => {
......
})
.catch((error) => {
console.log("error",error);
});
As you can see, the code for both GET and POST requests are exactly the same (except payload and method type). I'm singing with the same secret access key and access key id for both requests. I'm not sure why one request results in "InvalidSignatureException" when the other doesn't. Can anyone shed a light on this issue for me.
Thanks
After having discussion with AWS4 lib developer, I figured out what I did wrong. AWS4 uses "body" as a payload attribute to compute signature. However, Axios uses "data" attribute as payload. My mistake was only setting either one of them. So when I set just "data" attribute, the payload was present in the request and content-length is computed correctly. However, the signature was incorrect since the payload was not taken into consideration when computing signature. When I set just "body", payload was not present in the request because Axios does not use "body" attribute for payload. The solution is to set both attributes with payload. I hope this helps to anyone who are having the same issue I have.
If you use the AWS Amplify library it has a module called API which should fit your use cases, and it will perform Sigv4 signing for you either with authenticated or unauthenticated roles. The Auth category uses Cognito as the default implementation. For instance:
npm install aws-amplify --save
Then import and configure the lib:
import Amplify, { API } from 'aws-amplify';
Amplify.configure({
Auth: {
identityPoolId: 'XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab',
region: 'XX-XXXX-X'
},
API: {
endpoints: [
{
name: "APIName",
endpoint: "https://invokeURI.amazonaws.com"
}
]
}
});
Then for your API Gateway endpoint calling a Lambda:
let apiName = 'MyApiName';
let path = '/path';
let options = {
headers: {...} // OPTIONAL
}
API.get(apiName, path, options).then(response => {
// Add your code here
});
More info here: https://github.com/aws/aws-amplify