using REST's GET in classic asp - rest

First of all, I looked on SO already and found a similar question here:
Calling REST web services from a classic asp page
However, this doesn't solve my problem. I can't find a way to retrieve the correct information provided by my call
function determineLocationId(identifier)
Dim http: Set http = Server.CreateObject("WinHttp.WinHttpRequest.5.1")
Dim privateKey
privateKey = "myKey"
IdentifyUrl = "https://sandbox.uberall.com/api/locations/?identifier=" & identifier & "&private_key=" & privateKey
With http
Call .Open("GET", identifyUrl, False)
Call .Send()
End With
If Left(http.Status, 1) = 2 Then
response.write("updated")
Else
'Output error
Call Response.Write("Server returned: " & http.Status & " " & http.StatusText)
End If
response.write(identifyUrl)
response.end()
determineLocationId = identifier
end function
When I print my identifyUrl to the screen and copy & paste it into my browser, I get the correct output. A json-formatted object with the information I need.
However, if I print http.responseBody, it just yields some chinese chars like this:
佄呃偙⁅呈䱍倠䉕䥌⁃ⴢ⼯㍗⽃䐯䑔䠠䵔⁌⸴㄰吠慲獮瑩潩慮⽬䔯≎∠瑨灴⼺眯睷眮⸳牯⽧剔栯浴㑬氯潯敳搮摴㸢਍ℼⴭ䐠瑡楥慮敭›敤慦汵⹴獡⁰㉖〮‰㠰〮⸸〲㈱䠠湡⵳楗汬⁩牆楥敢杲牥ⴠ
What am I doing wrong? The link is definetly the correct one. I also tried to add:
Call .SetRequestHeader("Content-Type", "application/json")
without success

Well, as it turned out, using responseBody wasn't correct. According to the MSDN-Page for WinHttpRequest, responseBody is retrieving this:
Retrieves the response entity body as an array of unsigned bytes.
In my case, I had to switch to reponseText, which does the correct thing:
Retrieves the response entity body as text.

Related

Azure Data Factory/SQL and Deputy Payroll API Connection - Anonymous connection possible?

First question - is it possible to access Deputy Payroll API with only the permanent/anonymous token? If not, probably don't need to read the rest.
I have been tasked with moving data from a Deputy Payroll API to an Azure SQL DW.
I am trying to accomplish this without OAuth2.0 or Azure/Deputy Integration
According to Deputy's documentation you can connect via Permanent Token.
I have used permanent tokens before and REST but I am getting different behaviour.
When I ping the Subdomain for the base deputy URL (https://business.na.deputy.com/) it returns an object with 2 points that look like the following;
"Noshido__LK":"Ad8f......yd78y="
(128/256 key?)
When I ping the payroll api (https://business.na.deputy.com/api/v1/resource/TimesheetPayReturn) using the token it, Data Factory tells me that I 'need to use Login, OAuth2.0, or Bearer'.
I am not familiar with these type of connections, and am hoping to work within the parameters.
Thank You!
The short answer is yes. Permanent tokens is the easier way to access the data. The instructions on how to generate the permanent token is found in the GIF animation here:
https://www.deputy.com/api-doc/API/Authentication/
This is the code I use in Excel VBA to read the data
Sub Get_Data()
Dim request As New WinHttpRequest
Dim url As String, parameters As String
Dim permanentAccessToken As String
'Demo credentials
permanentAccessToken = "892******************b3e05f0df0"
url = "https://business.na.deputy.com/"
url = url & "api/v1/resource/TimesheetPayReturn"
request.Open "GET", url
request.SetRequestHeader "Authorization", "OAuth " + permanentAccessToken
request.Send
' Check the result is valid
If request.Status <> 200 Then
MsgBox "Error: " & request.ResponseText
Exit Sub
End If
End Sub
The permanent token is added to the header and that should work.

SoapUI 5.7.0 mockRequest.requestContent is empty for POST request

I am using SOAP UI 5.7.0 to mock a REST service and it is working fine. Only, when I want to access the body of a POST request with mockRequest.requestContent, the correct content is returned only in the first call, but from then on, it always returns the empty string.
I tried the call in OnRequestScript and in the POST requests own Dispatch script but the behavior is the same in both cases. I have the suspicion, that the Stream of the request is already read somewhere else and so does not return any more content. But I don't know what to do about it.
I wonder what is the correct way to read the content of a POST request.
Thank you
Appears to be a known issue, see posts in the community forum here and here.
this seems to be an old bug of PUT operation in REST mocks.
Unfortunately, this is a bug. There is an internal defect of SOAP-2344 for this issue. This applies for the PUT and DELETE methods for a REST mock service.
I have the same issue with a PATCH request.
Use the following trick to get the body of the PUT and DELETE requests:
mockRequest.with {
if (method.toString() == 'PUT' || method.toString() == 'DELETE') {
InputStreamReader isr = new InputStreamReader(request.getInputStream(), "UTF-8")
BufferedReader br = new BufferedReader(isr)
StringBuilder sb = new StringBuilder()
while ((s=br.readLine())!=null) {
sb.append(s)
}
def requestBody = new groovy.json.JsonSlurper().parseText(sb.toString())
log.info "requestBody: " + requestBody
}
}
I use it on the project but I don't really remember how where I got the snippet from. I had to change some parts to make it work as far as I remember. Give it a try.

PATCH / Post with curl in Classic ASP

I was thrown into a pretty old project, which is made in classic ASP. For our needs, I need to make a simple curl-request, to update some data.
I'm pretty new to ASP, so I looked for similar problems. I stumbled upon this
question here:
How can I post data using cURL in asp classic?
I tried to adapt as much as possible, but it seems like I'm missing an important thing and here I need your help:
functions.asp
public function makeCurlRequest(strMethod)
Dim http: Set http = Server.CreateObject("WinHttp.WinHttpRequest.5.1")
Dim privateKey
privateKey = "abc def"
Dim url: url = "https://sandbox.uberall.com/api/locations/322427?private_key=" & privateKey
Dim data: data = "{""location"":{""openingHours"":[{""dayOfWeek"":1,""from1"":""07:01"",""to1"":""07:02""}]}}"
'method needs to be PATCH
With http
Call .Open(strMethod, url, False)
Call .SetRequestHeader("Content-Type", "application/json")
Call .Send(data)
End With
If Left(http.Status, 1) = 2 Then
response.write("updated")
response.end()
Else
'Output error
Call Response.Write("Server returned: " & http.Status & " " & http.StatusText)
End If
end function
In my file, I simply call makeCurlRequest("PATCH").
Now it does indeed print "updated", so I guess I'm retrieving a 200, but the fields aren't updated.
Regarding to the uberall API, they require a location-object, which should be this, what is currently in my data-variable. (Checked it via a JSON-validator).
For a better readability, I'll provide the indented code as well, maybe here is an error:
{
"location":{
"openingHours":[
{
"dayOfWeek":1,
"from1":"07:01",
"to1":"07:02"
}
]
}
}
The ID's are correct, I double-checked that already. Maybe the payload is wrong? What might be the problem? Maybe data needs to be provided otherwise instead of this approach?
Looking at the examples on Uberall Tutorials Page
It looks as though the encapsulation of the location object is not necessary, instead structure the body like
{
"openingHours":[
{
"dayOfWeek":1,
"from1":"07:01",
"to1":"07:02"
}
]
}
In the code, change the data variable to be;
Dim data: data = "{""openingHours"":[{""dayOfWeek"":1,""from1"":""07:01"",""to1"":""07:02""}]}"
Must admit I had to dig around in the documentation to find an example that showed how they expected the body of the request to be structured, which isn't great for an API. Also if the payload was wrong you should be getting back an error so you know there was a problem with the payload, something along the lines of HTTP 400 Bad Request would make sense.
It's also possibly that the API uses HTTP 200 OK for everything, in which case any errors might get missed, so while testing you could just do something like this;
Dim http: Set http = Server.CreateObject("WinHttp.WinHttpRequest.5.1")
Dim privateKey
privateKey = "abc def"
Dim url: url = "https://sandbox.uberall.com/api/locations/322427?private_key=" & privateKey
'Purposefully passing the wrong structure to see what is returned.
Dim data: data = "{""location"":{""openingHours"":[{""dayOfWeek"":1,""from1"":""07:01"",""to1"":""07:02""}]}}"
'method needs to be PATCH
With http
Call .Open(strMethod, url, False)
Call .SetRequestHeader("Content-Type", "application/json")
Call .Send(data)
End With
'Not bothered about the status for now, just give me the response.
Call Response.Write("Server returned: " & http.Status & " " & http.StatusText)
Call Response.Write("Body: " & http.ResponseText)

Invalid_request_parameter (create and sending envelopes)

I'm trying to use a service of DocuSign API in an abap project. I want to send a document to a specific email so it can be signed. But im getting the following error:
"errorCode": "INVALID_REQUEST_PARAMETER",## "message": "The request contained at least one invalid parameter. Query parameter 'from_date' must be set to a valid DateTime, or 'envelope_ids' or 'transaction_ids' must be specified.
I tried the following:
CALL METHOD cl_http_client=>create_by_url
EXPORTING
url = l_url (https://demo.docusign.net/restapi/v2/accounts/XXXXXX')
proxy_host = co_proxy_host
proxy_service = co_proxy_service
IMPORTING
client = lo_http_client
lo_http_client->request->set_method( method = 'POST').
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'Accept'
value = 'application/json'.
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'X-DocuSign-Authentication'
value = get_auth_header( ). (json auth header)
CALL METHOD lo_http_client->request->set_cdata
EXPORTING
data = create_body( ).
This is my body:
CONCATENATE
`{`
`"emailSubject": "DocuSign REST API Quickstart Sample",`
`"emailBlurb": "Shows how to create and send an envelope from a document.",`
`"recipients": {`
`"signers": [{`
`"email": "test#email",`
`"name": "test",`
`"recipientId": "1",`
`"routingOrder": "1"`
`}]`
`},`
`"documents": [{`
`"documentId": "1",`
`"name": "test.pdf",`
`"documentBase64":` `"` l_encoded_doc `"`
`}],`
`"status": "sent"`
`}` INTO re_data.
The api request to get the Baseurl is working fine. (I know the error is quite specific what the problem is, but i cant find any sources on the docusign api documentation that one of the mentioned parameters should be added to the request)
Thank you in regards
The error message seems to indicate that you're Posting to an endpoint that requires certain query string parameters -- but you're not specifying them as expected in the query string. I'd suggest you check the DocuSign API documentation for the operation you are using, to determine what query string parameters it requires, and then ensure that you're including those parameters in your request URL.
If you can't figure this out using the documentation, then I'd suggest that you update your post to clarify exactly what URL (endpoint) you are using for the request, including any querystring parameters you're specifying in the URL. You can put fake values for things like Account ID, of course -- we just need to see the endpoint you are calling, and what qs params you're sending.
To create an envelope, use
https://demo.docusign.net/restapi/v2/accounts/XXXXXX/envelopes
instead of
https://demo.docusign.net/restapi/v2/accounts/XXXXXX
Thank you for all the answers, i found the mistake. Creating the request wasn´t the problem. I was using the wrong "sending"-method -_-.
now its working :)
lo_rest_client->post( EXPORTING io_entity = lo_request_entity ).

Upload to Azure Blob using SAS and REST

I'm having trouble writing to an Azure Block Blob from C++ using a SAS (Shared Access Signature). I'm using the Blob REST API and Poco. The HTTP request returns error 404 (resource does not exist), but I can't figure out what I'm doing wrong.
I generate the SAS on the server in C# like this (seems to work fine):
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference("my-blob");
container.CreateIfNotExists();
SharedAccessBlobPolicy sasConstraints = new SharedAccessBlobPolicy();
sasConstraints.SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(40);
sasConstraints.Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.List;
string sasContainerToken = container.GetSharedAccessSignature(sasConstraints);
return Request.CreateResponse(HttpStatusCode.OK, container.Uri + sasContainerToken);
In the Azure portal I can indeed see the Blob container being created as expected. I receive this SAS in C++ using an HTTP request. What I get looks like this (some names and signature replaced for security reasons):
https://myname.blob.core.windows.net/my-blob?sv=2012-02-12&se=2016-06-07T11%3A13%3A19Z&sr=c&sp=wl&sig=%%%%%%%%%%%%%%%%%%%%%%%
Then I try to create the file using Poco and the Blob REST API. That looks like this:
std::string cloudUrl = sasURI + "&restype=container";
std::string fileName = "fname.ext";
Poco::URI* uri = new Poco::URI(cloudUrl.c_str());
std::string* path = new std::string(uri->getPathAndQuery());
Poco::Net::HTTPSClientSession* session = new Poco::Net::HTTPSClientSession(uri->getHost(), uri->getPort());
std::string method = Poco::Net::HTTPRequest::HTTP_PUT;
Poco::Net::HTTPRequest* request = new Poco::Net::HTTPRequest(method, *path, Poco::Net::HTTPMessage::HTTP_1_1);
request->add("x-ms-blob-content-disposition", "attachment; filename=\"" + fileName + "\"");
request->add("x-ms-blob-type", "BlockBlob");
request->add("x-ms-meta-m1", "v1");
request->add("x-ms-meta-m2", "v2");
Poco::Net::HTTPResponse* httpResponse = new Poco::Net::HTTPResponse();
int fileContent = 42;
request->setContentLength(sizeof(int));
request->setKeepAlive(true);
std::ostream& outputStream = session->sendRequest(*request);
outputStream << fileContent;
std::istream &is = session->receiveResponse(*httpResponse);
Poco::Net::HTTPResponse::HTTPStatus status = httpResponse->getStatus();
std::ostringstream outString;
Poco::StreamCopier::copyStream(is, outString);
if (status != Poco::Net::HTTPResponse::HTTP_OK)
{
Logger::log("Connection failed\nstatus:", status, "\nreason:", httpResponse->getReason(), "\nreasonForStatus:", httpResponse->getReasonForStatus(status), "\nresponseContent:", outString.str());
}
I've looked up here how the REST API works. I found here that when using a SAS I don't need to do regular authentication.
What am I doing wrong here? Why am I getting error 404?
I believe most of your code is correct, all you need to do is insert the file name in your SAS URL.
Now that I have seen this question more carefully, this is what is happening:
You're creating a SAS on a blob container (my-blob) and using this SAS to upload a file (let's call it fname.ext). However you're not including the file name in the SAS URL so Azure Storage Service is assuming that you're trying to upload a file called my-blob in a $root container so on the service side when Azure Blob Service tries to validate the SAS, it validates it against $root container. Because you created the SAS for my-blob container and Azure Service is using $root container, the SAS does not match and that's why you're getting 403 error.
What you need to do is insert the file name in your SAS URL. So your SAS URL (or Request URL) would be something like (notice that I added fname.ext there):
https://myname.blob.core.windows.net/my-blob/fname.ext?sv=2012-02-12&se=2016-06-07T11%3A13%3A19Z&sr=c&sp=wl&sig=%%%%%%%%%%%%%%%%%%%%%%%
Also, you don't need the following two lines of code:
request->add("x-ms-version", "2015-02-21");
request->add("x-ms-date", "2016-06-07");
As these are not really needed when using SAS.
I've finally figured out what was going wrong here. :)
There were two problems in the above code. The first is that the filename needed to be inserted into the URL, as Gaurav Mantri explained. This does the trick:
int indexOfQuestionMark = cloudUrl.find('?');
cloudUrl = cloudUrl.substr(0, indexOfQuestionMark) + "/" + fileName + cloudUrl.substr(indexOfQuestionMark);
The other problem is that I wasn't uploading enough bytes. sizeof(int) is 4 bytes while pushing 42 into a stream turns it into characters, making it only 2 bytes. The server then keeps waiting for the remaining 2 bytes. That makes this the correct line in the example code above:
request->setContentLength(2);
Also, it works without these three lines so I suppose they're not needed:
request->add("x-ms-blob-content-disposition", "attachment; filename=\"" + fileName + "\"");
request->add("x-ms-meta-m1", "v1");
request->add("x-ms-meta-m2", "v2");
Similarly, adding this doesn't seem needed: "&restype=container".
Finally, for writing the SharedAccessBlobPermissions.List rights aren't needed so those can be left out in SAS generation on the server side.
One possible reason for your error could be the request date being too old. You're setting the request date as Midnight UTC tonight. Azure Storage allows about 15 minutes of clock skewness. Request date/time being "too old" is one of the major reasons for this 403 error (apart from incorrect account key and expired token in case of a SAS).
This is how you're setting x-ms-date request header.
request->add("x-ms-date", "2016-06-07");
This header's value should be formatted in the following format:
request->add("x-ms-date", "Sun, 11 Oct 2009 21:49:13 GMT");
Usually in C# world, we would do a DateTime.UtcNow.ToString("R") to get the date/time in correct format.
Please change your code accordingly and see if that solves the problem.