I am using Angular4 with TypeScript version 2.2.2
My web app is running fine when I call JSON with Filters but my NativeScript app fails when I call the Filter Values as an Object but works fine when I call filter values as a string.
Error Response with status: 200 for URL: null
THIS WORKS
https://domainname.com/api/v1/searchevents?token=057001a78b8a7e5f38aaf8a682c05c414de4eb20&filter=text&search=upcoming
If the filter value and search value is STRING it works whereas if they are objects as below, it does not work
THIS DOES NOT WORK
https://api.domainname.com/api/v1/searchevents?token=057001a78b8a7e5f38aaf8a682c05c414de4eb20&filter={"limit":"12","skip":"0"}&search={"search":"","latitude":"","longitude":"","categories":"","address":"","type":"upcoming"}
The Code I used is below
getData(serverUrl, type, skip_limit) {
console.log(serverUrl);
let headers = this.createRequestHeader();
let token_value = localStorage.getItem('access_token')
let url;
var filter;
filter = '{"limit":"10","skip":"0"}'
url = this.apiUrl + serverUrl + '?token=' + token_value + '&filter=' + filter
return this.http.get(url, { headers: headers })
.map(res => res.json());
}
The URL as formed above for the API is fine and works fine. Yet the error comes Error Response with status: 200 for URL: null
CAN ANYONE HELP ME SOLVE THIS?
Looks like the issue is the "filter" values are of different type and from what you mentioned as what worked, your service is expecting a string and not an object/array. So it fails to send the proper response when it gets one. With an object in the URL, you may have to rewrite the service to read it as an object (parse the two attributes and get them individually)
To make it simple, you can make these two as two different variables in the URL. like below,
https://api.domainName.in/api/v1/oauth/token?limit=10&skip=0
Be more precise in whats happening in your question,
1) Log the exact URL and post it in the question. No one can guess what goes in "text" in your first URL.
2) Your URL which you mentioned as worked have "token" as part of path, but in the code, its a variable which will have a dynamic value from "token_value".
3) Post your service code. Especially the signature and input parsing part.
Got the solution:
All you have to do is encode the Filter and Search Parameters if it is an Object or Array using Typescript encodeURI()
var filter = '{"limit":"12","skip":"0"}'
var search = '{"search":"","latitude":"","longitude":"","categories":"","address":"","type":"upcoming"}'
var encoded_filter = encodeURI(filter);
var encoded_search = encodeURI(search);
url = this.apiUrl+serverUrl+'?token='+token_value+'&filter='+encoded_filter+'&search='+encoded_search
Related
Ok I have been manipulating this string for hours! So any help is greatly appreciated
I am trying to simply make a post call and generate a password. The api is setup to take in a string a parses the json formatted string itself.
private headers = new HttpHeaders({ 'Content-Type': 'application/json' });
constructor(http: HttpClient) {
var url: string = 'https://eus-safeaccounts-test.azurewebsites.net/' + 'passwords/generate';
var body: string = '"{\"regex\":\"[a-zA-Z0-9]\",\"minLength\":8,\"maxLength\":12}"';
http.post<string>(url, body, { headers: this.headers }).subscribe(result => {
this.signUpResponseStr = result["password"];
}, error => console.error(error));
}
This call returns code 400 bad request. (I think because the text is not being seen as json?)
However, if we set body = '""'; then we get a password sent back from the api no problem. It is seen as an empty string on API side and then they give us a password. Exploring further I tried setting body = '"abc"'; because that is a string not following json format. In this case, we DO NOT get bad request 400, but the api recognizes bad json format and returns Invalid Json
My Question:
What should the body string look like for me to send this request? The API is open so anyone can reproduce and the API code shouldn't have anything to do with the 400 bad request issue, as we can see from my explorations, but the code is here https://github.com/nickpavini/SafeAccountsAPI.
Thanks for any help! :)
EDIT: I also tried sending as JSON type and I also tried JSON.stringify() with no luck
Found it. The string is a bit tricky to understand but hopefully this will help others.
body = '"{\\"regex\\":\\"[a-zA-Z0-9]\\",\\"minLength\\":8,\\"maxLength\\":12}"'
In this case it seems that the body contains a string. (the actual string that will be received by the server)
Inside that string, whenever we need the server to see a " that does not close the string, we must pass an actual backslash \\ and then a ". We do not need 3 backslashes in this case because the single quote ' at the beginning makes sure all paranthesis are included.
Note: Test this with the api in question if it seems weird to you. I think it has to do with the api implementation.
Probably body should not be double quoted, and should look instead like...
var body: string = '{"regex":"[a-zA-Z0-9]","minLength":8,"maxLength":12}'
First timer when it comes to connecting to API. I'm trying to pull data from Toggl using my API token but I can't get credentials working. I tried to replicate the method by Chris Webb (https://blog.crossjoin.co.uk/2014/03/26/working-with-web-services-in-power-query/) but I can't get it working. Here's my M code:
let
Source = Web.Contents(
"https://toggl.com/reports/api/v2/details?workspace_id=xxxxx&client=xxxxxx6&billable=yes&user_agent=xxxxxxx",
[
Query=[ #"filter"="", #"orderBy"=""],
ApiKeyName="api-token"
])
in
Source
After that I'm inputting my API Token into Web API method in Access Web content windows but I get an error that credentials could not be authenticated. Here's Toggl API specification:
https://github.com/toggl/toggl_api_docs/blob/master/reports.md
Web.Contents function receives two parameters: url + options
Inside options, you define the headers and the api_key, and other queryable properties, such as:
let
baseUrl = "https://toggl.com/",
// the token part can vary depending on the requisites of the API
accessToken = "Bearer" & "insert api token here"
options = [
Headers = [Authorization = accessToken, #"Content-Type" =
"application/Json"], RelativePath ="reports/api/v2/details", Query =
[workspace_id=xxxxx, client=xxxxxx6 , billable=yes, user_agent=xxxxxxx]
]
Source = Web.Contents(baseUrl, options)
// since Web.Contents() doesn't parse the binaries it fetches, you must use another
// function to see if the data was retreived, based on the datatype of the data
parsedData = Json.Document(Source)
in
parsedData
The baseUrl is the smallest url that works and never changes;
The RelativePath is the next part of the url before the first "?".
The Query record is where you define all the attributes to query as a record.
This is usually the format, but check the documentation of the API you're querying to see if it is similar.
POST ing json from javascript to server in Play Framework:
var myJson = {"name": "joe", "age":20};
var obj = JSON.parse(myJson);
$.ajax(jsRoutes.controllers.MyController.create(obj));
Now, I have the javascript router configured fine. If i recieve the obj as a string I can print it out to the console just fine.
routes.conf:
POST /person/add controllers.MyController.createFromAjax(ajax: String)
BUT, I want to write the json to MongoDB using an Async promise which Activator gives the compile time error:
scala.concurrent.Future[play.api.mvc.Result][error] cannot be applied to (String)
I have other routes that take no parameters that receive json using Postman and write it to MongoDB just fine
routes.conf
POST /heartrates/bulk controllers.HRController.createFromJson
If I omit the parameter on the route that receives the json from Ajax instead of using Postman I get a HTTP 400 error in the browser.
POST http://localhost:9000/person/add 400 (Bad Request)
SO, my question is, Ajax needs a parameter but String wont work. Play documentation says json is always received as a String. What am I doing wrong here?
Scala Controller Code taken from Lightbend seed Play.Reactive.MongoDB:
def createBulkFromAjax = Action.async(parse.json) { request =>
val documents = for {
heartRate <- request.body.asOpt[JsArray].toStream
maybeHeartRate <- heartRate.value
validHeartRate <- maybeHeartRate.transform(transformer).asOpt.toList
} yield validHeartRate
for {
heartRate <- hrFuture
multiResult <- heartRate.bulkInsert(documents = documents, ordered = true)
} yield {
Logger.debug(s"Successfully inserted with multiResult: $multiResult")
Created(s"Created ${multiResult.n} heartRate")
}
}
I think you're getting mixed up between the parameters you pass to your Action as part of the jsRoutes call, and parameters that get passed to endpoints (i.e. the query string, query parameters etc).
Play will return a 400 Bad Request if you've declared a non-optional parameter (like you did with ajax: String) and you don't then actually supply it in your request.
While conceptually you are passing obj to your action, it's not as a query parameter - you've declared that your endpoint expects an HTTP POST - so the JSON should be in the HTTP request body. Notice your other endpoints don't take any query parameters.
So step 1 is to fix your routes file (I've renamed your method to match your other existing working one):
POST /person/add controllers.MyController.createFromJson
If you look at the Play documentation for the Javascript reverse router, you'll see that you'll need to set the type (aka HTTP method) if you're doing something other than a GET. So, step 2, here's what your Javascript should look like to achieve a POST:
var myJson = {"name": "joe", "age":20};
var obj = JSON.stringify(myJson);
var r = controllers.MyController.createFromJson;
$.ajax({url: r.url, type: r.type, data: obj });
After those changes you should be good; your controller code looks fine. If you still get 400 Bad Request responses, check that jQuery is setting your Content-Type header correctly - you may need to use the contentType option in the jQuery $.ajax call.
Edit after still getting 400 errors:
I've just noticed that you were using JSON.parse in your Javascript - as per this answer you should be using JSON.stringify to convert an object into something jQuery can send - otherwise it may try to URLEncode the data and/or send the fields as query parameters.
The other thing to look at is whether the JSON you are sending actually agrees with what you're trying to parse it as. I'm not sure if you've provided a simplified version for this question but it looks like you're trying to parse:
{"name": "joe", "age":20}
Using:
request.body.asOpt[JsArray]
Which will always result in a None - you didn't give it an array.
The Answer to ajax javascript routes in Play Framework 2.5 for ReativeMongo:
routes.conf:
GET /javascriptRoutes controllers.HRController.javascriptRoutes
HRController:
def javascriptRoutes = Action { implicit request =>
Ok(
JavaScriptReverseRouter("jsRoutes")(
routes.javascript.HRController.createBulkFromAjax
)
).as("text/javascript")
}
routes.conf:
POST /heartrates/add controllers.HRController.createBulkFromAjax
main.scala.html:
<script type="text/javascript" src="#routes.HRController.javascriptRoutes"></script>
javascript:
var r = jsRoutes.controllers.HRController.createBulkFromAjax();
$.ajax({url: r.url, type: r.type, contentType: "application/json", data: JsonString });
HRController:
def createBulkFromAjax = Action.async(parse.json) { request =>
//Transformation silent in case of failures.
val documents = for {
heartRate <- request.body.asOpt[JsArray].toStream
maybeHeartRate <- heartRate.value
validHeartRate <- maybeHeartRate.transform(transformer).asOpt.toList
} yield validHeartRate
for {
heartRate <- hrFuture
multiResult <- heartRate.bulkInsert(documents = documents, ordered = true)
} yield {
Logger.debug(s"Successfully inserted with multiResult: $multiResult")
Created(s"Created ${multiResult.n} heartRate")
}
}
HRController.createBulkFromAjax was built from a Lightbend activator ui seed example called play.ReactiveMogno
Blizzard just shut down their old API, and made a change so you need an apikey. I changed the URL to the new api, and added the API key. I know that the URL is valid.
var toonJSON = UrlFetchApp.fetch("eu.api.battle.net/wow/character/"+toonRealm+"/"+toonName+"?fields=items,statistics,progression,talents,audit&apikey="+apiKey, {muteHttpExceptions: true})
var toon = JSON.parse(toonJSON.getContentText())
JSON.pase returns just an empty object
return toon.toSorce() // retuned ({})
I used alot of time to see if i could find the problem. have come up empty. Think it has something to do with the "responce headers".
Responce headers: http://pastebin.com/t30giRK1 (i got them from dev.battle.net (blizzards api site)
JSON: http://pastebin.com/CPam4syG
I think it is the code you're using.
I was able to Parse it by opening the raw url of your pastebin JSON http://pastebin.com/raw/CPam4syG
And using the following code
var text = document.getElementsByTagName('pre')[0].innerHTML;
var parse = JSON.parse(text);
So to conclude I think it is the UrlFetchApp.fetch that's returning {}
So i found the problems:
I needed https:// in the URL since i found after some hours that i had an SSL error
If you just use toString instead of getContentText it works. Thow why getContentText do not work, i am not sure of.
was same problem, this works for me (dont forget to paste your key)
var toonJSON = UrlFetchApp.fetch("https://eu.api.battle.net/wow/character/"+toonRealm+"/"+toonName+"?fields=items%2Cstatistics%2Cprogression%2Caudit&locale=en_GB&apikey= ... ")
I'm trying to call my ServiceNow JSON web service. I'm getting an unexpected error when I execute URLFetchApp. I'm guessing I'm passing in the authorization headers in the wrong way but both the GAS and ServiceNow documentation is beyond terrible. I've seen some of the other SO questions similar to this but none have worked. Any help would be appreciated.
function getOpenTickets(){
var headers = {
"Authorization":"Basic RgRJ5U6EsxHt00229KX5Hj0WV1z18q08==",
"Content-Type":"application/json",
"Username":"myusername",
"Password":"mypassword"
}
var url = "https://mysninstance.service-now.com/u_equipment_repair.do?JSONv2=&sysparm_view=vendor&displayvalue=true&sysparm_action=getRecords&sysparm_query=state=500^assignment_group.name=MyGroup^ORDERBYDESCnumber";
var url = encodeURIComponent(url);
var options = {
"method":"get",
"headers":headers
}
var result = UrlFetchApp.fetch(url,options);
Logger.log(result.getContentText());
}
OK so I found the solution. There were actually two problems.
The first was with the way I was passing the authorization headers. I was passing the basic authentication as an already encoded base64 string, on top of which I was still passing the username and password which was redundant. For whatever reason Google Apps Script (GAS) doesn't like this. Once I changed the headers and the options as shown below it was fine.
The second problem was the the URI encoding. The query string did need to be encoded because of the caret "^" symbols, but for whatever reason GAS's encodeURIComponent was not encoding it properly. As soon as I manually replaced the caret symbols with their URL encoded equivalents , which is "%5E", everything worked fine and I was able to retrieve my ServiceNow data via Google Apps Script.
function getOpenTickets3(){
var headers =
{
Authorization : "Basic " + Utilities.base64Encode('myusername:mypassword'),
"Content-Type":"application/json"
}
var options =
{
"method" : "get",
"headers": headers
};
var url = "https://mysninstance.service-now.com/u_equipment_repair.do?JSONv2=&sysparm_view=vendor&displayvalue=true&sysparm_action=getRecords&sysparm_query=state=500%5Eassignment_group.name=Somevendor%5EORDERBYDESCnumber";
var result = UrlFetchApp.fetch(url,options);
Logger.log(result.getContentText());
}
You are URI encoding your entire URL in this line:
var url = encodeURIComponent(url);
In your URL, the base path needs to be unescaped when passed to fetch(...):
https://mysninstance.service-now.com/u_equipment_repair.do
Each parameter following the ? is a URI component, like:
sysparm_view=vendor
In this case, the parameter name is sysparm_view and the value is vendor, you would need to URI encode the value (vendor) if it contained special characters like one of /?&.
In the static URL you provide, there's actually nothing that needs to be encoded, so removing that call to encodeURIComponent(url) should work.
If you are dealing with dynamic values for your URL parameters, then you'd want to URI encode each parameter value separately, before concatenating onto the main string.