Relay Modern BadRequestError: Missing multipart field ‘operations’ - graphql-js

I am trying to upload file to my server. using Altair i can do it without any error but when i use Relay.js for uploading it server throws following error.
BadRequestError: Missing multipart field ‘operations’ (https://github.com/jaydenseric/graphql-multipart-request-spec).
at Busboy.<anonymous> (/home/dotsinspace/Documents/dev/truck.pe__server/node_modules/.pnpm/graphql-upload#9.0.0_graphql#15.3.0/node_modules/graphql-upload/processRequest.js:362:11)
at Object.onceWrapper (events.js:420:28)
at Busboy.emit (events.js:326:22)
at Busboy.EventEmitter.emit (domain.js:486:12)
at Busboy.emit (/home/dotsinspace/Documents/dev/truck.pe__server/node_modules/.pnpm/busboy#0.3.1/node_modules/busboy/lib/main.js:37:33)
at /home/dotsinspace/Documents/dev/truck.pe__server/node_modules/.pnpm/busboy#0.3.1/node_modules/busboy/lib/types/multipart.js:52:13
at processTicksAndRejections (internal/process/task_queues.js:75:11)
Following are my graphql code and mutation which i am trying to commit.
#Graphql
graphql`
mutation AccountUploadMutation($profilePicture: Image!) {
AccountUpload(profilePicture: $profilePicture) {
message,
status
}
}
`
#Mutation
commitMutation(Environment, {
'mutation': AccountUploadMutation,
'variables': { 'profilePicture': v },
'uploadables': { 'file': v },
'onCompleted': (response, error) => Response({}, { response, error })
})
and I am totally confused about uploading part to..in uploadables you have to provide file..but my server looks for variable with profilePicture as image how can i deal with it.

It looks like you have an issue the multipart parsing configuration in your backend.
My guess is that the Relay Network is sending your GraphQL query in the mutlipart field "operation", but your backend is looking for the field "operations" (plural). To fix the error, confirm that your Network is sending the query in the operations field, or change your backend to read whatever field it's actually being sent on.
Another possibility is you're not sending your query in the multipart format at all. If you followed the Network documentation's example for sending your request, then you are just sending a JSON object, not a multipart form:
// Example from Relay docs. Sends a JSON object, not a multipart
// form as expected by your backend
function fetchQuery(
operation,
variables,
cacheConfig,
uploadables,
) {
return fetch('/graphql', {
method: 'POST',
headers: {
// Add authentication and other headers here
'content-type': 'application/json'
},
body: JSON.stringify({
query: operation.text, // GraphQL text from input
variables,
}),
}).then(response => {
return response.json();
});
}
// Create a network layer from the fetch function
const network = Network.create(fetchQuery);
If this is the case, write your fetchQuery function to fetch data using a multipart form. See this example: fetch post with multipart form data

Related

How to pass json data to aws lambda through API Gateway?

I am trying to send the JSON to AWS lambda to trigger lambda handler. I am using Flutter web for this project and my API end point is as below. Below is my code to hit AWS lambda endpoint.
Future<String> getResponse(jsonData) async {
var response =
await http.post(Uri.parse("https://7jua06h1r4.execute-api.ap-south-1.amazonaws.com/stage1/calc"), headers: header, body: jsonData);
if (response.statusCode == 200) {
print("Success");
} else {
print("Error");
}
}
When I try to hit and get response using postman, everything works fine and i get 200 status with response as well. But when i test it using my browser, it display the body is empty. Can you help me out please? How can i pass JSON data through API Gateway to lambda?
{"statusCode": 200, "body": {}}
When i try using Postman, it works as expected. you can see in the image below:
[1]: https://i.stack.imgur.com/Tczfw.png
My Lambda function:
import json
import boto3
def lambda_handler(event, context):
print(event['body'])
# TODO implement
return {
'statusCode': 200,
'body': event['body']
}
Here, i am not able to get the body i.e. JSON Data from my app.
I think that in your code need to replace it:
print(event['body'])
by
print(event.body.body)
Event is not the call body, body is inside of that object and you have an attribute called body.
When you tested it using your browser, did you pass body to the url? Assuming that you just typed your url
https://7jua06h1r4.execute-api.ap-south-1.amazonaws.com/stage1/calc
into the browser, you would have gotten an empty body in response, which is the correct behaviour.

Fetch Post request not working in Custom functions Office Addin [TypeError: Network request failed]

I having been facing this error in custom functions excel Add-in, where I'm trying to call an external service inside a custom function. It works fine for a GET request such as this:
function stockPrice(ticker) {
var url = "https://api.iextrading.com/1.0/stock/" + ticker + "/price";
return fetch(url)
.then(function(response) {
return response.text();
})
.then(function(text) {
return parseFloat(text);
});
}
CustomFunctionMappings.STOCKPRICE = stockPrice;
Taken from https://learn.microsoft.com/en-us/office/dev/add-ins/excel/excel-tutorial-custom-functions#create-a-custom-function-that-requests-data-from-the-web
But gives an exception for a POST request like this:
function stockPrice(ticker) {
var url = "https://westcentralus.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment";
return fetch(url, {
method: 'POST',
headers: {
'Ocp-Apim-Subscription-Key': key,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(body))
.then(function(response) {
return response.json();
})
.then(function(response) {
return response.somevalue;
})
.catch(e => {
console.error("Caught exception");
return JSON.stringify(e);
});
}
The above is just a sample to have an idea, of how I'm calling my service. I have tried it with 2-3 different services, and I figured out that after running fetch, the code goes to catch block, and the error value that is returned in the excel is an empty object '{}'. Since there are no ways to debug custom functions on windows, and since there is no specific error description, I'm unable to figure out the issue. I have also added my service domain to App Domain list in manifest file but still no effect.
I am not sure that particular API accepts POST requests, so you maybe running into that.
Debugging in Windows is still being worked on but you can use Excel online and F12tools to debug.
If you are on Windows, you can console.log statements in conjunction with the Runtime logging:
https://learn.microsoft.com/en-us/office/dev/add-ins/excel/custom-functions-best-practices#troubleshooting
Hope that helps and we will update this when debugging is ready on for custom functions on windows desktop.

PUT request returning a 400 Bad Request Error

I am doing a PUT request to RESTfull service which changes password of a user. For the time being I have just hardcoded values of new and old password in my AJAX test my service. However it is giving me a 400 error.
AJAX call
$.ajax({
type: "PUT",
url: "api/teachers/"+user,
data: {"old":"123","new":"qwe"},
contentType: "application/json",
success: function(data,status)
{
datax = data;
alert(data+status);
ko.applyBindings(new AddMarkSheetKo(data));
},
error: function(XMLHttpRequest, textStatus, errorThrown)
{
alert(XMLHttpRequest+textStatus+ errorThrown);
// error handler here
}
});
Restful function:
#PUT
#Path("/{name}")
#Consumes(MediaType.APPLICATION_JSON)
public Response changePwd(#PathParam ("name")String name,#QueryParam ("old") String old, #QueryParam("new") String nw){
System.out.println("entered function"+old+nw);
Teacher t = DataAccessUtil.getByName(Teacher.class, name);
if(t.getPassword().equals(old)){
t.setPassword(nw);
DataAccessUtil.update(t);
return Response.ok().build();
}
else{
return Response.status(Status.BAD_REQUEST).entity("Wrong password !!!").build();
}
//return reposnse;
}
This information might be useful that on the console it prints
entered functionnullnull
So it the restfull function is called however it is not receiving the query parameters.
Any help would be really appreciated!
First, you could replace the #QueryParam annotations with #FormParam ones to retrieve the 'new' and 'old' parameters of the PUT request. Then, you should remove the #Consumes("application/json") annotation and contentType:application/json from your server and browser side code, and finally replace the submitted data in JSON format into something like 'new=qwe&old=123'.
If you want to stay with a content in JSON format, you should probably map the incoming body with an entity (ie, a Java class annotated with JAXB annotations), so that the JAX-RS implementation you use could unmarshall the incoming JSON content into a Java object.
HTH.

how to get specific value from server response for uploaded file ajax

i have tried to send uploaded file to server by using ajax like this
formData.append('foldername',fname);
formData.append('file', file)
$.ajax({
url: 'imageupload',
data: formData,
processData: false,
contentType: false,
type: 'POST',
success:function(response)
{
alert(response);
alert(response.imagename);
}
});
it is send data to server successfully but i have sent response from server like this
res.writeHead(200,{'Content-Type':'text/html', 'Access-Control-Allow-Orgin':'*'});
res.write(JSON.stringify({"imagename":"1.jpeg","imageid":"xxxxxxxxxxxxxxxxxxx"}));
res.end();
i have written two alert in success function . in first alert i got like this
{"imagename":"1.jpeg","imageid":"xxxxxxxxxxxx"}
i have written second alert for to get imagename but i got undefine
so i could not get specific key value. how to resolve this?
change
res.writeHead(200,{'Content-Type':'text/html', 'Access-Control-Allow-Orgin':'*'});
to
res.writeHead(200,{'Content-Type':'application/json', 'Access-Control-Allow-Orgin':'*'});
jquery don't convert a JSON string to Javascript Object if the content type is 'Content-Type':'text/html'. So, 'Content-Type':'application/json' or 'Content-Type':'text/json' will do the magic. You will get the response as Javascript object in the client. So, you can do
alert(response.imagename);//alerts image name

How to get the REST response message in ExtJs 4?

I'm building upon RESTFul Store example of ExtJs 4. I'd like my script to display errors provided by the REST server, when either Add or Delete request fails. I've managed to obtain the success status of a request (see the code below), but how do I reach the message provided with the response?
Store:
var store = Ext.create('Ext.data.Store', {
model: 'Users',
autoLoad: true,
autoSync: true,
proxy: {
type: 'rest',
url: 'test.php',
reader: {
type: 'json',
root: 'data',
model: 'Users'
},
writer: {
type: 'json'
},
afterRequest: function(request, success) {
console.log(success); // either true or false
},
listeners: {
exception: function(proxy, response, options) {
// response contains responseText, which has the message
// but in unparsed Json (see below) - so I think
// there should be a better way to reach it than
// parse it myself
console.log(proxy, response, options);
}
}
}
});
Typical REST response:
"{"success":false,"data":"","message":"VERBOSE ERROR"}"
Perhaps I'm doing it all wrong, so any advice is appreciated.
I assume that your service follows the REST principle and uses HTTP status codes other than 2xx for unsuccessful operations.
However, Ext will not parse the response body for responses that do not return status OK 2xx.
What the exception/response object (that is passed to 'exception' event listeners) does provide in such cases is only the HTTP status message in response.statusText.
Therefore you will have to parse the responseText to JSON yourself. Which is not really a problem since it can be accomplished with a single line.
var data = Ext.decode(response.responseText);
Depending on your coding style you might also want to add some error handling and/or distinguish between 'expected' and 'unexpected' HTTP error status codes. (This is from Ext.data.reader.Json)
getResponseData: function(response) {
try {
var data = Ext.decode(response.responseText);
}
catch (ex) {
Ext.Error.raise({
response: response,
json: response.responseText,
parseError: ex,
msg: 'Unable to parse the JSON returned by the server: ' + ex.toString()
});
}
return data;
},
The reason for this behavior is probably because of the REST proxy class not being a first class member in the data package. It is derived from a common base class that also defines the behavior for the standard AJAX (or JsonP) proxy which use HTTP status codes only for communication channel errors. Hence they don't expect any parsable message from the server in such cases.
Server responses indicating application errors are instead expected to be returned with HTTP status OK, and a JSON response as posted in your question (with success:"false" and message:"[your error message]").
Interestingly, a REST server could return a response with a non-2xx status and a response body with a valid JSON response (in Ext terms) and the success property set to 'true'. The exception event would still be fired and the response body not parsed.
This setup doesn't make a lot of sense - I just want to point out the difference between 'success' in terms of HTTP status code compared to the success property in the body (with the first having precedence over the latter).
Update
For a more transparent solution you could extend (or override) Ext.data.proxy.Rest: this will change the success value from false to true and then call the standard processResponse implementation. This will emulate 'standard' Ext behavior and parse the responseText. Of course this will expect a standard JSON response as outlined in your original post with success:"false" (or otherwise fail).
This is untested though, and the if expression should probably be smarter.
Ext.define('Ext.ux.data.proxy.Rest', {
extend: 'Ext.data.proxy.Rest',
processResponse: function(success, operation, request, response, callback, scope){
if(!success && typeof response.responseText === 'string') { // we could do a regex match here
var args = Array.prototype.slice.call(arguments);
args[0] = true;
this.callParent(args);
} else {
this.callParent(arguments);
}
}
})