I'm trying to implement a solution which automatically calls someone when a certain event occurs, based on Twilio, Azure Automation and SCOM. Furthermore, it shall be possible for someone to call a number, and the same process is triggered.
The Twilio Account/Phonenumber is set up and works fine. When I do a call to the Twilio Number I successfully receive HTTP POST on my Azure Automation Webhook and the Runbook is fired.
The only problem I'm facing right now, is that I cannot make use of the cmdlet ConvertFrom-Json to extract the WebhookBody.
This is the error I get when using the cmdlet:
ConvertFrom-JSON : Invalid JSON primitive: Called. At line:13 char:11
+ $Inputs = ConvertFrom-JSON $webhookdata.RequestBody
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [ConvertFrom-Json], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.ConvertFromJsonCommand
And this is the Input arriving on the Azure Automation Webhook from Twilio:
{"WebhookName":"Twilio
Endpoint","RequestBody":"Called=%2B41815880262&ToState=Chur&CallerCountry=CH&Direction=inbound&Timestamp=Fri%2C%2010%20Feb%202017%2009%3A07%3A35%20%2B0000&CallbackSource=call-progress-events&CallerState=&ToZip=&SequenceNumber=0&CallSid=CA7c152287d945595fe600614fe7778f8a&To=%2B41815880262&CallerZip=&ToCountry=CH&ApiVersion=2010-04-01&CalledZip=&CalledCity=&CallStatus=completed&Duration=1&From=%2BMYTELNUZMBER&CallDuration=8&AccountSid=MYSID&CalledCountry=CH&CallerCity=&Caller=%2Bmybnumber&FromCountry=CH&ToCity=&FromCity=&CalledState=Chur&FromZip=&FromState=","RequestHeader":{"Cache-Control":"max-age=259200","Connection":"close","Accept":"/","Host":"s2events.azure-automation.net","User-Agent":"TwilioProxy/1.1","X-Twilio-Signature":"pq2jYVGN3H5LmanwId0xCvp69tM=","x-ms-request-id":"bc1cf55a-33b2-4046-a343-199d1a7fac4a"}}
When I simply output the WebHook Data with this cmd, I can see that the Twilio Repsonse looks somewhat strange (Heade looks good though):
$WebhookName = $WebhookData.WebhookName
$WebhookHeaders = $WebhookData.RequestHeader
$WebhookBody = $WebhookData.RequestBody
Write-Output $WebhookHeaders
Write-Output $WebhookBody
Output:
Cache-Control : max-age=259200 Connection : close Accept
: / Host : s2events.azure-automation.net User-Agent
: TwilioProxy/1.1 X-Twilio-Signature : xmEbt23prT+W8zJrRZE5pdKullE=
x-ms-request-id : bdca412c-584e-42ba-acbb-969cdf9c1ec0
Called=%2B41815880262&ToState=Chur&CallerCountry=CH&Direction=inbound&Timestamp=Wed%2C%2008%20Feb%202017%2013%3A18%3A27%20%2B0000&CallbackSource=call-progress-events&CallerState=&ToZip=&SequenceNumber=0&CallSid=CALLSID&To=%2B41815880262&CallerZip=&ToCountry=CH&ApiVersion=2010-04-01&CalledZip=&CalledCity=&CallStatus=completed&Duration=1&From=%2BMYNUMBER&CallDuration=7&AccountSid=MYSID&CalledCountry=CH&CallerCity=&Caller=%2BMYBNUMBER&FromCountry=CH&ToCity=&FromCity=&CalledState=Chur&FromZip=&FromState=
Does anybody have an idea what I could do instead of writing my own "Converter" to get the values from the TWILIO HTTP POST? Or may I be doing something horribly wrong?
So, I think I understood your problem. You are doing it slightly wrong: $webhook data is already an object, which has everything you need:
$WebhookData.WebhookName
$WebhookData.RequestHeader
$WebhookData.RequestBody
You just need to parse RequestBody into something meaningful:
$data = #{ };
foreach ($item in $WebhookData.RequestBody.Split('&')) {
try {
$item = $item.Split('=');
$data.Add($item[0], [System.Net.WebUtility]::UrlDecode($item[1]))
}
catch {
Write-Warning -Message ('Possible null parameter value for {0}' -f $item[0]);
}
}
Twilio developer evangelist here.
When Twilio sends a webhook request to your URL it is not encoded as JSON. This is why your JSON conversion is failing.
Twilio sends the data as either URL encoded parameters in the body of a POST request or URL query parameters for GET requests. This is the same as if the request were made by the submission of a form in a browser.
I'm not familiar with Azure cmdlets but if there is one for parsing URL encoded data, then you'll want to use that instead. Alternatively, #4c74356b41 has provided a decent implementation.
Related
I am trying to invoke an HTTP triggered Azure function built on with a GET request. I setup the linked service as per the recommended steps and the function itself works with a query string through POSTMAN or internet browser, but fails when I try to invoke through Data factory.
{
"errorCode": "3608",
"message": "Call to provided Azure function '' failed with status-'NotFound' and message - 'Invoking Azure function failed with HttpStatusCode - NotFound.'.",
"failureType": "UserError",
"target": "Azure Function1",
"details": []
}
I came across another stackoverflow post https://stackoverflow.com/a/54497119/4212430 where there was a mention of a JSON response for ADF.
I have since changed my python code to provide an HTTP response as a JSON object as below
def main(req: func.HttpRequest) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
statename = req.params.get('statename')
if not statename:
try:
req_body = req.get_json()
except ValueError:
pass
else:
statename = req_body.get('statename')
if statename:
initiate_main(statename)
host.close()
function_message = {"Response":"Successfully trasnferred BOM files"}
return func.HttpResponse(
json.dumps(function_message),
mimetype="application/json",
status_code=200)
else:
function_message = {"Response":"Error in transferring files"}
return func.HttpResponse(
json.dumps(function_message),
mimetype="application/json",
status_code=400)
But that hasn't helped either.
It turns out that I was using the wrong URI with an api added at the end while I should have just been giving the plain function name
In Postman I'm able to submit a query to our Azure DevOps 2019 Server no problem:
POST https://<AZDOSERVER>/<COLLECTION>/<PROJECT>/<TEAM>/_apis/wit/wiql?api-version=5.0
{"query": "Select [System.Id] From WorkItems WHERE [System.AreaPath] UNDER '<AREANAME>'"}
But when I do it in Python it seems to run into an encoding issue with the single quotes around my AREANAME. Here's my code:
url = "https://<AZDOSERVER>/<COLLECTION>/<PROJECT>/<TEAM>/_apis/wit/wiql?api-version=5.0"
json = '{"query": "Select [System.Id] From WorkItems WHERE [System.AreaPath] UNDER '
+ "'<AREANAME>'" + '" }'
headers = {'Accept': 'application/json; api-version=5.0'}
response = request.post(url, json=json, auth=self.basicauth, headers=headers)
I get a 400 error with the following message:
b'{"count":1,"value":{"Message":"Error converting value \\"{\\"query\\":
\\"Select [System.Id] From WorkItems WHERE [System.AreaPath] UNDER \'<AREANAME>\'\\" }\\"
to type \'Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models.Wiql\'. Path \'\',
line 1, position 92.\\r\\n"}}'
How should I pass JSON properly into the python request.post() method so that it's sent wtih proper encoding? I tried capturing my outbound request via Fiddler but it doesn't see python traffic. I'm installing Wireshark too but that's going to take a while. I also stepped thru the request.post method to try and understand how it's build the body of the request. It seems to be handling the single quotes properly when it covers to a byte array.
Figured it out: request.post() takes a dictionary object for the json parameter instead of a json string.
I have a SoapUI REST (i.e. non-SOAP) mock service that returns a response for a POST request.
The request and response both contain JSON content.
At the moment, I can get it to return a static response and that works fine, but I want some of the values in the response to be dynamically sourced from the request.
So if I have this request:
{
"the_request":{
"abc":"123",
}
How can I get the value of "abc" copied in the response?
Investigation has lead me to believe I can do this via including a variable in the response, something like:
Response:
{
"the_response":{
"value_from_request":"${#MockResponse#Request#the_request#abc}",
"other":"stuff",
}
And then implementing a script to populate the variable in the response, via the Script tab.
How can I then populate this with data from the request?
Currently SoapUI just generates an empty value
"value_from_request":"",
Tried using mockRequest.requestContent in the Script tab, but have not found how to obtain the "123" value from it.
OK, worked this out. So the response message can simply reference a variable in the requestContext like so:
Response:
{
"the_response":{
"value_from_request":"${the_value}",
"other":"stuff",
}
And a groovy script can be used to parse the JSON request content and populate "the_value" or whatever you like in the requestContext:
// Parse the JSON request.
def requestBody = new groovy.json.JsonSlurper().parseText(mockRequest.getRequestContent())
// Set up "the_value" from the request message.
requestContext.the_value = requestBody.the_request.abc
// Bit of logging so can see this in the "script log" tab.
log.info "Value extracted from request: ${requestContext.the_value}"
I think the script should be like this
def requestBody = new groovy.json.JsonSlurper().parseText(mockRequest.getRequestContent())
context.setProperty("the_value",requestBody.the_request.abc)
I set up a POST ressource in API Gateway which invokes a Lamdba function, fine.
In the "integration request", for text/plain Content-type, I defined the following mapping :
#set($messageStr = $util.urlEncode($input.body))
{
"message" : "$messageStr"
}
Problem is : whenever I POST data with JSON reserved characters, the integration request mapping thows
{"message": "Could not process payload"}
Example : blablabla will be correctly passed through to lambda, not {blablabla nor a:e ...
This seems like that method urlEncode expects JSON data.
Any idea how to pass whatever body as pure text ?
Thanks
I'm trying to post a json data via Arduino.When ı'm trying to this code.ı will send a json data with QueryString.If ı try this code the server answer me with Wrong QueryString format.Which mean is ı'm connected to server and server got my data.
if (client.connect(server, 80)) {
Serial.println("connected");
// Make a HTTP request:
client.println("POST /URL?query=jsondata HTTP/1.1");
client.println("Host: **.**.**.**");
client.println("Connection: close\r\nContent-Type: application/x-www-form-urlencoded");
client.print("Content-Length: ");
client.println(PostData.length());
client.println();
client.println(PostData);
}
But My Main Plan is send my json data with querystring.If ı Try this code ;
client.println("POST /URL?query={request:{Header:{Username:kullaniciAdi,Password:123456},Item:{Serial:ABC123QWE,Data:100, DateOn:23/11/1986 15:45:24}}} HTTP/1.1");
I get a HTTP Error 400. The request is badly formed.
Anyone Has a any idea?
Yes, your URI contains spaces and may contain other characters to confuse the format of the post request. You need to encode these characters.
As far as I can tell, the Arduino standard libraries do not include any form of urlEncode method, which is common in other languages and libraries, so you will either have to create your own or look for one.
Your resulting code would be something like:
String request = "/URL?query={request:{Header:{Username:kullaniciAdi,Password:123456},Item:{Serial:ABC123QWE,Data:100, DateOn:23/11/1986 15:45:24}}}";
String encRequest = uriEncode(request); // need to write your own method for this...
String post = "POST " + encRequest + " HTTP/1.1");
client.println( post);
Some discussion on creating a uriEncode function is on the Arduino Forum and there also appears to be a working method on hardwarefun.com