Parse 'form-data' from incoming webhook using Google Apps Script - forms

I have a (mulitlevel?) webhook sending into a Google Script (Access:" Anyone"/"Anyone even anonymous") and trying to pull the info out of it with a doPost(). I've used ngrok to capture a sample but can't make it work. I'm trying to extract event but getting errors like
'TypeError Cannot read property 'contents' of undefined'.
I'm using this as one possible starting point to parse it.
function doPost(e) {
try{
var data = JSON.parse(e.postData.contents);
var event = data.event;
} catch(err){
var mykey = '*************************************8'
var dataURL = 'https://maker.ifttt.com/trigger/Data_Check_WHook/with/key/'+mykey+'?value1=Error:&value2=error: '+event
UrlFetchApp.fetch(dataURL);
}
Below a sample of the webhook. Do I need to access 'payload' before reading 'event'?
Content-Disposition: form-data; name="payload"
Content-Type: application/json
{"event":"media.pause","user":true,"owner":true,"Account":********************************Hours_2973","summary":"","viewOffset":1391000,"lastViewedAt":1592403577,"year":2019,"thumb":"/library/metadata/5448/thumb/1572876947","art":"/library/metadata/5448/art/1572876947","originallyAvailableAt":"2019-08-15","addedAt":1560188503,"updatedAt":1572876947,"createdAtAccuracy":"epoch","createdAtTZOffset":"3600"}}
--------------------------55b945c1eb00cab0--

Related

Redirect SendGrid Webhook Events with an F5 using Custom Headers

When sending an email through SendGrid I am sending a custom header. Is there a way to configure the webhooks to get the custom header back from SendGrid so that a F5 iRule can be easily written to redirect the traffic based on the value in this custom header. I know I can use .addCustomArgs(...) to return custom data but I would like the custom data in the header.
var client = new SendGridClient("API_KEY");
var from = new EmailAddress("test#example.com", "Example User");
var subject = "Testing with SendGrid API";
var to = new EmailAddress("joe#test.com", "Example User");
var plainTextContent = "Test Content";
var htmlContent = "<strong>Testing with HTML content</strong>";
var msg = MailHelper.CreateSingleEmail(from, to, subject, plainTextContent, htmlContent);
var identifiers = new Dictionary<String, String>();
identifiers["application"] = "APP_NAME_GOES_HERE";
identifiers["resource"] = "RESOURCE_NAME_GOES_HERE";
msg.AddHeaders(identifiers);
var response = await client.SendEmailAsync(msg);
Twilio SendGrid developer evangelist here.
I'm afraid you cannot set headers for the SendGrid event webhook to send back. Custom arguments are sent as part of the JSON body.
I've not used F5 iRules before, but it seems that you may be able to parse and use the JSON body of a request within an iRule. According to this post, you can use iRules LX to deal with the JSON using JavaScript.
Or it seems that you can combine HTTP::collect with an HTTP_REQUEST_DATA block to collect and do things with the request body.

Relay Modern BadRequestError: Missing multipart field ‘operations’

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

Add flag to UnityWebRequest

I am trying to make a POST request to webpage that expects the --data field to be filled with some data to be processed. I'm pretty much trying to recreate this curl request, but with UnityWebRequest.
curl -X POST http://localhost:8000/clic/say?text=Make+the+gene+set --data '{"geneSetMembers":["UST"],"geneSetName":"selection0"}'
The UnityWebRequest documentation mentions that GET requests don't set any flags other than the url, but it's not clear if no other custom options exist for posts. Is there some way to format a WWWform or something that will hold the data such that the server will recognize it?
var form = new WWWForm();
// some way to plug in the jsonified data to the form
webRequest = UnityWebRequest.Post(url + route + to_say, form);
webRequest.downloadHandler = new DownloadHandlerBuffer();
webRequest.SetRequestHeader("Content-Type", "application/json");
webRequest.SendWebRequest();
// etc etc
I've tried just giving the form a field named "data" a la
form.AddField("data", "{ \"geneSetMembers\":[\"UST\"],\"geneSetName\":\"selection0\"}");
but the server does not like it, saying it "got error Invalid JSON literal name: data" So clearly that's the wrong syntax for it
EDIT: put lines in the same order they were in original code. Sorry, I have commented lines between them
Maybe your server doesn't like to receive the data as a field called data.
This ofcourse depends totally on the PHP code we don't see since you didn't share that part. b
But at least I can tell you that --data or also simply -d in curl refer to the entire data section and is not a field called data.
You could try to instead use a MultiPartFormDataSection passing just the data itself without a specific field name
var data = "{\"geneSetMembers\":[\"UST\"],\"geneSetName\":\"selection0\"}";
var form = new List<IMultiFormPart>{ new MultiPartFormDataSection(data) };
webRequest = UnityWebRequest.Post(url + route + to_say, form);
yield return webRequest.SendWebRequest();
which is now sent as content-type multipart/form-data though ...
Another alternative if your server really needs to receive a content-type application/json might be to "manually" compose the request e.g. like
var data = "{\"geneSetMembers\":[\"UST\"],\"geneSetName\":\"selection0\"}";
var request = new UnityWebRequest(url + route + to_say, "POST");
var bodyRaw = Encoding.UTF8.GetBytes(data);
request.uploadHandler = (UploadHandler) new UploadHandlerRaw(bodyRaw);
request.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
yield return request.SendWebRequest();
Though of you look close now this seems actually not to be the case since if you read the man curl
(HTTP) Sends the specified data in a POST request to the HTTP server, in the same way that a browser does when a user has filled in an HTML form and presses the submit button. This will cause curl to pass the data to the server using the content-type application/x-www-form-urlencoded
which is actually exactly the default content type used by the simple string version of UnityWebRequest.Post.
So thinking about it it should actually be as simple as using the pure string version of UnityWebRequest.Post:
var data = "{\"geneSetMembers\":[\"UST\"],\"geneSetName\":\"selection0\"}";
var request = UnityWebRequest.Post(url + route + to_say, data);
yield return request.SendWebRequest();

Multipartform data not passing in all params to server-Swift 3

My requirement is to upload a recorded audio file with a file name and duration to a server using REST API
The code I have to form the multipart form data is as below
private func createRequestBody(boundary:"--BXDFG", multidata:Data, mime:"audio/mp4", filePathKey:"file", filename:"test", metas:["title":"Mytitle","duration":"30"] -> Data {
var body = Data()
body.append(Data("--\(boundary)\r\n".utf8))
body.append(Data("Content-Disposition: form-data; name=\"\(filePathKey)\"; filename=\"\(filename)\"\r\n".utf8))
body.append(Data("Content-Type: \(mime)\r\n\r\n".utf8))
body.append(multidata)
body.append(Data("\r\n".utf8))
if (metas != nil) {
for (key, value) in metas! {
body.append(Data("--\(boundary)\r\n".utf8))
body.append(Data("Content-Disposition: form-data; name=\"\(key)\"\r\n".utf8))
body.append(Data((value as! String).utf8))
body.append(Data("\r\n".utf8))
}
}
body.append(Data("--\(boundary)--\r\n".utf8))
return body
}
What I am doing is passing the audio as NSDATA and in a for loop I am adding "title" and "duration" to the multipart form request
On server side, I have below code
#api.route('/upload/<userid>', methods=['POST'])
def upload(userid):
if request.method == 'POST':
if 'title' not in request.form:
return jsonify({'error': 'Need a valid title for uploaded file', 'code': 403})
if "title" is not passed in multipart form data then the server will return an error response.
In my case, even though, "title" is added as a part of the request, the data is not passed to the server and the server returns an error. If I just pass the audio data alone, removing the validation for "title" on server side, then the audio data is uploaded successfully to the server.
I am not able to understand why "title" and "data" are not passed to server
PS: The API request works fine in POSTMAN client.
Thanks
This solved my case
Replacing line
body.append(Data("Content-Disposition: form-data; name=\"\(key)\"\r\n".utf8))
to
body.append(Data("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".utf8))
Added and additional /r/n

Azure encoding job via REST Fails

I am trying to upload a video and encode it via azure rest service.
I have now hit the step of encoding the video but I am having difficulties with the request.
The following code shows my request:
var joburl = res.RequestMessage.RequestUri + "Jobs";
client = new HttpClient();
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "Bearer " + token);
client.DefaultRequestHeaders.Add("x-ms-version", "2.8");
client.DefaultRequestHeaders.Add("DataServiceVersion", "3.0");
client.DefaultRequestHeaders.Add("MaxDataServiceVersion", "3.0");
client.DefaultRequestHeaders.Add("x-ms-date", date);
//accept
t = new NameValueHeaderValue("odata", "verbose");
type = new MediaTypeWithQualityHeaderValue("application/json");
type.Parameters.Add(t);
client.DefaultRequestHeaders.Accept.Add(type);
result = await client.PostAsync(joburl,json);
the url:https://wamsamsclus001rest-hs.cloudapp.net/api/Jobs
the json:
{"Name":"khgfiuydencodingjob","InputMediaAssets":[{"__metadata":{"Uri":"https://wamsamsclus001rest-hs.cloudapp.net/api/Assets('nb%3acid%3aUUID%3ad037b321-cd1c-43a9-9607-c4910fa7a85b')"}}],"Tasks":[{"Configuration":"H264 Adaptive Bitrate MP4 Set 720p","MediaProcessorId":"nb:mpid:UUID:1b1da727-93ae-4e46-a8a1-268828765609","TaskBody":"<?xml version=\"1.0\"encoding=\"utf-8\"?><taskBody><inputAsset>JobInputAsset(0)</inputAsset><outputAsset>JobOutputAsset(0)</outputAsset></taskBody>"}]}
The bearer token works as I use it for other request.
But I get a bad request 400 with the followin error message:
{"error":{"code":"","message":{"lang":"en-US","value":"Parsing request content failed due to: Make sure to only use property names that are defined by the type"}}}
Can anyone spot the error.
Thank you for the help
Okay I got it to work. Needed a odata=verbose in my json/string content - like this:
var jobInJson = JsonConvert.SerializeObject(job);
json = new StringContent(jobInJson, Encoding.UTF8);//,
json.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json;odata=verbose");
I tried this earlier however I got a error 500 but now it is working.