Currently, I am developing a web service which going to be called post JSON. It works fine and I got my records posted without any issue.
My issue is to display the response. I used UploadData to send .. Do I need to use download data to receive? What if I need to show in the response in MessageBox.
Note that I am expecting a response in JSON format as well. Let me know at least the concept ? First I guess, I need to receive the response and I will deserialize it.
Here is my current code. Working fine but I can't show the response.
Public Function postData(ByVal JsonBody As String) As Boolean
Dim webClient As New WebClient()
Dim resByte As Byte()
Dim resString As String
Dim reqString() As Byte
Try
Dim APIusername As String = "XXXXX"
Dim APIPassword As String = "XXXXX"
webClient.Headers("content-type") = "application/json"
webClient.Credentials = New System.Net.NetworkCredential(APIusername, APIPassword)
reqString = Encoding.Default.GetBytes(JsonBody)
resByte = webClient.UploadData(Me.urlToPost, "post", reqString)
resString = Encoding.Default.GetString(resByte)
Console.WriteLine(resString)
' Here I need to show the responses
webClient.Dispose()
Return True
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
Return False
End Function
I have used http request instead of web client and it works.
Related
I don't really understand the make-up of JSON so I am struggling to adapt other answers to suit my needs. I really hope someone can help? Specifically I want to get a list or array of "elevations" from the following JSON response in VB. I have managed to get the response into a string and parsed it but that is as far as I have got.
VB.Net:
Imports Newtonsoft.Json.Linq
Dim urlstring As String = urlstring1 & coordstring & urlstring2
Dim srequest As HttpWebRequest = DirectCast(WebRequest.Create(urlstring), HttpWebRequest)
Dim responsestring As String
'Execute http enquiry
Try
Dim sresponse As New StreamReader(srequest.GetResponse().GetResponseStream())
responsestring = sresponse.ReadToEnd()
sresponse.Close()
'MessageBox.Show(responsestring)
Catch ex As Exception
MessageBox.Show("Error getting elevations, check internet connection")
GoTo X
End Try
Dim ser As JObject = JObject.Parse(responsestring)
JSON:
{
"authenticationResultCode":"ValidCredentials",
"brandLogoUri":"http:\/\/dev.virtualearth.net\/Branding\/logo_powered_by.png",
"copyright":"Copyright © 2012 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.",
"resourceSets":[
{
"estimatedTotal":1,
"resources":[
{
"__type":"ElevationData:http:\/\/schemas.microsoft.com\/search\/local\/ws\/rest\/v1",
"elevations":[1776,1775,1777,1776],
"zoomLevel":14
}
]
}
],
"statusCode":200,
"statusDescription":"OK",
"traceId":"8d57dbeb0bb94e7ca67fd25b4114f5c3"
}
Use something to help you visualize, like https://jsonformatter.curiousconcept.com/
Collapse all then as you expand write your path.
When you get to {} you type the name, when you get to [] you type number.
YourArray = ser("resourceSets")(0)("resources")(0)("elevations")
Adding CruleD's response to my code:
Imports Newtonsoft.Json.Linq
Dim urlstring As String = urlstring1 & coordstring & urlstring2
Dim srequest As HttpWebRequest = DirectCast(WebRequest.Create(urlstring), HttpWebRequest)
Dim responsestring As String
'Execute http enquiry
Try
Dim sresponse As New StreamReader(srequest.GetResponse().GetResponseStream())
responsestring = sresponse.ReadToEnd()
sresponse.Close()
Catch ex As Exception
MessageBox.Show("Error getting elevations, check internet connection")
GoTo X
End Try
Dim ser As JObject = JObject.Parse(responsestring)
For Each token As JToken In ser("resourceSets")(0)("resources")(0)("elevations")
'Do something here with each item in the list such as add to an array
'e.g. elevationarray(tokennumber) = token
'tokennumber = tokennumber + 1
Next
In a VB .net environment, I am making the following call, trying to implement the authorize step of an OAuth process to connect to an Accelo API (a time-entry and billing type of app). I'm trying to get an access token:
Dim jsonstring = "{'Content-Type':'Application/x-www-Form-urlencoded',
'authorization':'Basic MDBhM...GbG5oLlZB'}"
Dim data = Encoding.UTF8.GetBytes(jsonstring)
Dim result_post = SendRequest(New Uri("https://ourinfo.api.accelo.com/oauth2/v0/token"), data, "application/json", "POST")
with the function defined as this:
Private Function SendRequest(uri As Uri, jsonDataBytes As Byte(), contentType As String, method As String) As String
Dim req As WebRequest = WebRequest.Create(uri)
req.ContentType = contentType
req.Method = method
req.ContentLength = jsonDataBytes.Length
Dim stream = req.GetRequestStream()
stream.Write(jsonDataBytes, 0, jsonDataBytes.Length)
'stream.Close()
Dim response = req.GetResponse().GetResponseStream()
Dim reader As New StreamReader(response)
Dim res = reader.ReadToEnd()
reader.Close()
response.Close()
Return res
End Function
and I keep receiving an error on this line:
Dim response = req.GetResponse().GetResponseStream()
Saying
"System.Net.WebException: 'The remote server returned an error: (400) Bad Request.'"
It seems to me like a syntax error or something in the way my calling method is formed or the format of the parameters passed. I got the HTTP request code suggestion/format from here:
How to POST a JSON to a specific url using VB.NET?
and I'm using the Accelo API to set the content-type and authorization "basic" part where the string is encoded in Base 64. This is a service application so i'm supposed to be able to get the token in 1-step (no user confirmation is required). I already have a "token" from when I registered, but the API still indicates I should do this code. i'm following this:
https://api.accelo.com/docs/?_ga=2.218971609.1390377756.1568376911-2053161277.1565440093#service-applications
Can anyone tell me what exactly I'm doing wrong here? I'm confused and this is the first time I'm trying to implement OAuth.
There is some example code in the API documentation that looks like this:
POST /oauth2/v0/token HTTP/1.1
Host: planet-express.api.accelo.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {client_credentials}
grant_type=client_credentials
scope=read(staff)
And I'm not sure the difference between the = and : syntax purposes. I was not able to search and find any answers to whether I'm calling everything correctly. Should I be passing the scope and grant_type in the JSON string, or setting it as a property on "req" object in the "SendRequest" function? I know that the grant_type is supposedly required but how do I set it?
What's the token I received initially when I registered, if I'm supposed to get a token this way?
I got it working with the help of a colleague. Apparently I was confusing header data and the json "data,"and I was not formatting the data correctly either. I should have been looking at the WebResponse too, not only the WebRequest. I changed my code to the following, which works now:
Sub SendRequestGetAccess()
Dim req As WebRequest = WebRequest.Create(uri)
req.Method = "POST"
req.Headers.Add("Authorization", "Basic " & "MDB....")
req.ContentType = "Application/x-www-Form-urlencoded"
req.ContentLength = jsonDataBytes.Length
Dim stream = req.GetRequestStream()
stream.Write(jsonDataBytes, 0, jsonDataBytes.Length)
stream.Close()
Dim response As WebResponse = req.GetResponse()
Console.WriteLine((CType(response, HttpWebResponse)).StatusDescription)
Dim dataStream = response.GetResponseStream()
Dim reader As StreamReader = New StreamReader(dataStream)
Dim responseFromServer As String = reader.ReadToEnd()
Console.WriteLine(responseFromServer)
reader.Close()
dataStream.Close()
response.Close()
'Dim firstItem = jsonResult.Item("data").Item(0).Value(Of String)("token")
Dim j As Object = New JavaScriptSerializer().Deserialize(Of Object)(responseFromServer)
Dim _itemvalue = j("itemkey")
End Sub
And I had to use dashes instead of colons in my json data:
Dim jsonstring = "grant=creds" & "&scope=read"
Dim data = Encoding.UTF8.GetBytes(jsonstring)
SendRequestGetAccess(New Uri("https...site.com/oauth2/v0/token"), data)
I am having trouble sending JSON data to a firebase database using the rest API, the data is sent, but it does not parse. For instance if I use this curl command in command prompt in windows:
curl -X PUT -d "{\"lastName\":\"Jones\",\"firstName\":\"Bubba\"}" https://<database-name>.firebaseio.com/rest/test/.json
That results in the correct parsing of the data:
Yet, when using the following VBA code:
Sub PUSHhttpRequestTest() 'Doesn't Work!!
Dim sc As Object
Set sc = CreateObject("ScriptControl")
sc.Language = "JScript"
Dim strURL As String: strURL = "https://<database-name>.firebaseio.com/rest/.json"
Dim strRequest
strRequest = """{\""lastName\"":\""Jones\"",\""firstName\"":\""Bubba\""}"""
Dim XMLhttp: Set XMLhttp = CreateObject("msxml2.xmlhttp")
Dim response As String
Debug.Print strRequest
XMLhttp.Open "PUT", strURL, False
XMLhttp.setrequestheader "Content-Type", "application/json;charset=UTF-8"
XMLhttp.sEnd strRequest
response = XMLhttp.responseText
Debug.Print response
End Sub
This sends exactly the same stringified JSON, and it gets added to the Firebase database, however, the JSON string doesn't get parsed:
I have tried different Content Types, and variations on the JSON string, but nothing seems to work. Can anyone explain how I can get the VBA script to send data that Firebase will parse?
Thanks
I found a possible solution to sending JSON data from excel to firebase, but it doesn't answer my question about why the above VBA code sending a Stringified JSON doesn't get parsed in Firebase. I would still like a solution to that, because I already have a function the creates the stringified JSON from my data.
Using the VBA-web Library from this Stack Overflow post seems to do the trick. The example uses dictionaries for your data, however please my comment and the subsequent reply regarding the format of the JSON string to send. No escape code is required!
There is no PUT, and Other request types for json, but you can easily add these in yourself.
The equivalent code to the above, but using VBA-web library (with custom PutJson function) is:
Sub test()
Dim strURL As String: strURL = "https://<database-name>/rest/test/whatwhat/.json"
Dim strRequest As String: strRequest = "{""LastName"":""Jones"",""firstName"":""Bubba""}"
Dim Client As New WebClient
Dim Response As WebResponse
Set Response = Client.PutJson(strURL, strRequest)
ActiveSheet.Range("A1").Value = Response.Content
End Sub
And we end up with this....
Happy Days!
However, I'd still like to know why the seemingly identical curl and VBA HTTP requests result in different parsing of the data in FireBase?
So my goal is to send a HttpRequest to api, it returns a 500 internal server error.
According to them, other companies are succesfully using this Api, so it should work in theory. I send the json example string I use to test if it works, they confirmed it is correct. So what could cause the Error?
Public Function SendStringToHttpServer(dataString As String, uriString As String, credentials As NetworkCredential) As String
Dim resultInfo As String
Dim request As HttpWebRequest = CType(WebRequest.Create(uriString), HttpWebRequest)
request.Credentials = credentials
request.Timeout = 6000
request.Method = "POST"
Dim byteArray As Byte() = Encoding.UTF8.GetBytes(dataString)
request.ContentType = "application/json"
request.ContentLength = byteArray.Length
Try
Dim dataStream As Stream = request.GetRequestStream()
dataStream.Write(byteArray, 0, byteArray.Length)
dataStream.Close()
Dim response As HttpWebResponse = CType(request.GetResponse(), HttpWebResponse)
dataStream = response.GetResponseStream()
Dim reader As New StreamReader(dataStream)
Dim responseFromServer As String = reader.ReadToEnd()
reader.Close()
response.Close()
Catch ex As Exception
Debug.WriteLine(ex.Message)
End Try
Return "done"
End Function
Note: I saw there are some similiar threads, like this. But I use it exactly the same way, so it SHOULD work but doesn't -.-
(Beside the fact that i have strict on and therefore cast explicitly)
EDIT: About the authentification methods: This works definitly, since if I use wrong username or password in the credenitals I get a 403: authorized Error and not a 500.
Furthermore the read request works just fine. Read request is very similiar just a basic HttpRequest which only requires the url and credentials.
EDIT 2: So I read that it can be tied to HttpRequest automaticlly adding and "Expect:100-continue" to the header.I prevent this now
ServicePointManager.Expect100Continue = False
But it still gives a 500 Error.
I want to POST some JSON with some VBA:
Dim sURL As String, sHTML As String, sAllPosts As String
Dim oHttp As Object
Dim blWSExists As Boolean
Set oHttp = CreateObject("MSXML2.XMLHTTP")
sURL = "some webste.com"
oHttp.Open "POST", sURL, False
oHttp.setRequestHeader "Content-type", "application/json"
oHttp.setRequestHeader "Accept", "application/json"
oHttp.Send (mType = OPEN_SYSTEM_TRADE & systemOwnerId = 10)
sHTML = oHttp.ResponseText
Worksheets("Open1").Range("A1").Value = sHTML
The predefined format to be sent to the website is a description in json as follows :
{"mType":"OPEN_SYSTEM_TRADE","systemOwnerId":10,"systemId":16, etc}
My oHttp.Send line must be wrong, as soon as i add more arguments, i get a compiler error
I publish this (not working) code cause its the best i could find on the web so far (all other get me stuck on other things that i don't understand ...
I also tried to put the json code in a cell, put the cell in a string, and send the string like this : oHttp.Send (string), which results in a Error 406 Not Acceptable reply from the website.
JSON can be very sensitive to how it's formatted, so I would make sure everything is quoted properly before it is sent. I would recommend splitting Body into a separate variable and debugging the value with http://jsonformatter.curiousconcept.com/ before sending.
Dim Body As String
Body = "{""mType"":""OPEN_SYSTEM_TRADE"",""systemOwnerId"":10}"
' Set breakpoint here, get the Body value, and check with JSON validator
oHttp.Send Body
I ran into many similar issues when working with Salesforce's REST API and combined my work into a library that may be useful to you: https://github.com/VBA-tools/VBA-Web. Using this library, your example would look like:
Dim Body As New Dictionary
Body.Add "mType", "OPEN_SYSTEM_TRADE"
Body.Add "systemOwnerId", 10
Dim Client As New WebClient
Dim Response As WebResponse
Set Response = Client.PostJson("somewebsite.com", Body)
Worksheets("Open1").Range("A1").Value = Response.Content