I am very new to jQuery and json. I am trying to get UK Bank Holiday data from the following API/link so that I can create a function which determines if a selected date is a working day.
https://www.gov.uk/bank-holidays.json
I had an error for No Transport which I fixed by putting in:
jQuery.support.cors = true;
I am now getting Access Denied. I have no idea how to gain access to this because as I say, I am still learning all this.
function IsWorkingDay(date) {
var day = new moment(value, "DD-MM-YYYY").day();
jQuery.support.cors = true;
var bankHolidays = $.getJSON("https://www.gov.uk/bank-holidays.json").done(function(data) {
alert(data);
})
.fail(function(a, b, c) {
alert(b + ',' + c);
return day != 0 && day != 6;
}
});
My question is in two phases:
How do I get access? (Main question)
How do I move on to access the data? I have downloaded the json onto my computer to look at, just how I am going to go about translating this to javascript is what I am struggling on.
If you are blocked by CORS, and the service doesn't support JSONP, the easiest way to solve it is to create a proxy service for the actual service. So if you create a service on your server (which is the same that is serving the javascript), you can call that service, which in turn will fetch the data from the external service. On the server side, there is no CORS to worry about.
I don't know what your backend is, but the steps are as follows:
Create a service on your side that is exposed with a URL (e.g. /myapp/workingday)
Call this service instead of the real service
Your proxy service will get the JSON data and return it to the javascript
Edit
I don't know MVC4, but I suspect it's some of the same concepts as Spring MVC, so here's a Java example:
#Controller
public class HolidaysController {
#RequestMapping("/workingday")
public void isworkingDay(#RequestParam("day") Date day, HttpServletResponse response) {
// Call external service and get JSON
String json = callExternalService(day);
response.setContentType("application/json");
response.getWriter().write(json);
}
}
And in your javascript:
function IsWorkingDay(date) {
var day = new moment(value, "DD-MM-YYYY").day();
var bankHolidays = $.getJSON("/workingday").done(function(data) {
// process data
});
}
For this to work you need to use jsonp as illustrated here
BUT
running the above code throw an invalid label exception which as explained here and as #NilsH suggests is due to the server blocking it
Related
I stored values in my cache using my Controller class using the dependency IMemoryCache. I am also accessing my cache and get few values from it like so:
//IMemoryCache initailized before this variable : _cache
public void foo()
{
var token = _cache.Get<TokenModel>("Token" + HttpContext.Session.GetString("TokenGuid"));
//Do something with token
}
Question is:
How can I can access the cache from my Javascript file?
Cache is located on the server while JavaScript is executed on the client. The only way I can think of is if you create a cache controller and create a Get action on it. After that you would call this action in Ajax and asynchronously get the server cache value.
public class CacheController : Controller
{
[HttpGet("{key}")]
public IActionResult GetCacheValue(string key)
{
var cacheValue = //get your cache
return Json(cacheValue);
}
}
IMemoryCache allows you to speed up your application by storing your data "in-memory". So you can reach memory from your javascript code.
Please have a look to the documentation of the IMemoryCache here: https://learn.microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-2.1
What I would suggest you is get your cached data on backend side and put it cookie. Then later you can get cookie value from your javascript code.
I assume you have an instance of IMemoryCache which name is _cache.
You can set cache by like this.
_cache.Set(cacheKey, cacheEntry, cacheEntryOptions);
HttpCookie myCookie = new HttpCookie("yourCookieName");
myCookie["cacheData"] = cacheEntry;
myCookie.Expires = DateTime.Now.AddDays(1d);
Response.Cookies.Add(myCookie);
or you can do the same after you get your cached data. Just get the data from your memory and set it to cookie.
You can get the cookie from your Javascript by using both DOM or JQuery.
If you would like to use DOM:
var x = document.cookie;
For jquery have a look at this answer on StackOverFlow:
https://stackoverflow.com/a/1599367/1261525
I was wondering if there were any good techniques in keeping your WebAPI controller routes in sync with the client side.
For instance, you have a WebAPI controller BooksController. On the client you could invoke a method by calling the endpoint:
$.get('books/1');
Then one day you decide to rename the controller, or add a RoutePrefix. This breaks the client side code, as the endpoint has changed.
I came across the library WebApiProxy, which looks interesting. Does anyone have a good approach to solving this problem? Is there a reason to use string literals on the client that I may be overlooking?
I created a blog bost on te subject. Take a look :)
http://blog.walden.dk/post/2017/02/02/export-all-your-asp-net-webapi-endpoints-to-json
Im working on a post consuming it in javascript.. Anyway, this code exports the endpoints runtime, and will work on refactorings and route changes. It exports uri parameters as well, they can be used to be parsed in javascript and replaced with values from the client.
The simplest way to achieve waht you want, is to use the built-in ApiExplorer in ASP.NET WEBAPI. It searches for all "ApiController" implementations, and reads the route-attribute metadata.
public class EndpointManager
{
public IEnumerable<ApiMethodModel> Export()
{
//Use the build-in apiexplorer to find webapi endpoints
IApiExplorer apiExplorer = GlobalConfiguration.Configuration.Services.GetApiExplorer();
//exclude endpoints without the attribute
var apiMethods = apiExplorer.ApiDescriptions.Select(ad => new ApiMethodModel(ad)).ToList();
return apiMethods;
}
}
You can create an endpoint that returns that generated data.
[RoutePrefix("api/endpoint")]
public class EndpointApiController : ApiController {
[HttpGet]
[Route("all")]
public IEnumerable<ApiMethodModel> All()
{
var endpoints = new EndpointManager().Export();
return endpoints;
}
}
Now all the endpoints can be reached at "/api/endpoint/all"
Here is an sample I was talking about in my comment to your question:
function getUrl(uri) {
var bookRoute = /books(.*?)/i;
var otherRoute = /something(.*?)/i;
if(uri.match(bookRoute)) {
return uri.replace(bookRoute, "http://localhost/webapi/books$1")
}
if(uri.match(otherRoute)) {
return uri.replace(otherRoute, "http://mydomain/api/something$1")
}
return uri;
}
alert(getUrl("books/1"));
alert(getUrl("something/realy/different/1"));
All you need is to define the routes in the body of your function.
I have a web server returning an thrift object serialized used the JSON protocol to a client html page using the pure Javascript Thrift library (thrift.js).
The server for example:
from MyThriftFile.ttypes import ThriftClass
from thrift import TSerialization
from thrift.protocol import TJSONProtocol
thrift_obj = new ThriftClass()
result = TSerialization.serialize(
thrift_obj,
protocol_factory=TJSONProtocol.TJSONProtocolFactory())
return result
Now in the C#, Python, Java, and even the node.js Thrift libraries there is some form of this generic TSerialization or TDeserialization utlity and its more or less implemented like so:
def deserialize(base,
buf,
protocol_factory=TBinaryProtocol.TBinaryProtocolFactory()):
transport = TTransport.TMemoryBuffer(buf)
protocol = protocol_factory.getProtocol(transport)
base.read(protocol)
return base
So it gets it data, loads it up into a throw away transport (because we are not going to send this information anywhere), creates a new protocol object for encoding this data, and finally the actual thrift object reads this data to populate itself.
The pure javacript library however seems to lack this functionality. I understand why the client library only support the JSON protocol (web pages don't deal in raw binary data) but why not method for de/serialization from/to JSON?
I made my own method for doing the job but it seems hacky. Anyone have a better trick?
$(document).ready(function() {
$.get("www.mysite.com/thrift_object_i_want/", function(data, status) {
var transport = new Thrift.Transport();
var protocol = new Thrift.Protocol(transport);
// Sets the data we are going to read from.
transport.setRecvBuffer(data);
// This is basically equal to
// rawd = data
rawd = transport.readAll();
// The following is lifited from
// readMessageBegin().
// These params I am setting are private memeber
// vars that protocol needs set in order to read
// data set in setRevBuff()
obj = $.parseJSON(rawd);
protocol.rpos = []
protocol.rstack = []
protocol.rstack.push(obj)
// Now that the protocl has been hacked to function
// populate our object from it
tc = new ThriftClass();
tc.read(protocol);
// u is now a js object equal to the python object
});
});
I haven't tried your code but I assume it is working.
It seems correct and is essentially what the TSerializer et al classes do in those other languages. Granted, it could be wrapped in a more friendly way for the vanilla JS library.
The only thing that I might recommend to make it less "hacky" would be to just create a Thrift service method that returns the object(s) you need... then the serialization/deserialization logic will be automatically wrapped up nicely for you in the generated service client.
http://www.biletix.com/search/TURKIYE/en#!subcat_interval:12/12/15TO19/12/15
I want to get data from this website. When i use jsoup, it cant execute because of javascript. Despite all my efforts, still couldnot manage.
enter image description here
As you can see, i only want to get name and url. Then i can go to that url and get begin-end time and location.
I dont want to use headless browsers. Do you know any alternatives?
Sometimes javascript and json based web pages are easier to scrape than plain html ones.
If you inspect carefully the network traffic (for example, with browser developer tools) you'll realize that page is making a GET request that returns a json string with all the data you need. You'll be able to parse that json with any json library.
URL is:
http://www.biletix.com/solr/en/select/?start=0&rows=100&fq=end%3A[2015-12-12T00%3A00%3A00Z%20TO%202015-12-19T00%3A00%3A00Z%2B1DAY]&sort=vote%20desc,start%20asc&&wt=json
You can generate this URL in a similar way you are generating the URL you put in your question.
A fragment of the json you'll get is:
....
"id":"SZ683",
"venuecount":"1",
"category":"ART",
"start":"2015-12-12T18:30:00Z",
"subcategory":"tiyatro$ART",
"name":"The Last Couple to Meet Online",
"venuecode":"BT",
.....
There you can see the name and URL is easily generated using id field (SZ683), for example: http://www.biletix.com/etkinlik/SZ683/TURKIYE/en
------- EDIT -------
Get the json data is more difficult than I initially thought. Server requires a cookie in order to return correct data so we need:
To do a first GET, fetch the cookie and do a second GET for obtain the json data. This is easy using Jsoup.
Then we will parse the response using org.json.
This is a working example:
//Only as example please DON'T use in production code without error control and more robust parsing
//note the smaller change in server will break this code!!
public static void main(String[] args) throws IOException {
//We do a initial GET to retrieve the cookie
Document doc = Jsoup.connect("http://www.biletix.com/").get();
Element body = doc.head();
//needs error control
String script = body.select("script").get(0).html();
//Not the more robust way of doing it ...
Pattern p = Pattern.compile("document\\.cookie\\s*=\\s*'(\\w+)=(.*?);");
Matcher m = p.matcher(script);
m.find();
String cookieName = m.group(1);
String cookieValue = m.group(2);
//I'm supposing url is already built
//removing url last part (json.wrf=jsonp1450136314484) result will be parsed more easily
String url = "http://www.biletix.com/solr/tr/select/?start=0&rows=100&q=subcategory:tiyatro$ART&qt=standard&fq=region:%22ISTANBUL%22&fq=end%3A%5B2015-12-15T00%3A00%3A00Z%20TO%202017-12-15T00%3A00%3A00Z%2B1DAY%5D&sort=start%20asc&&wt=json";
Document document = Jsoup.connect(url)
.cookie(cookieName, cookieValue) //introducing the cookie we will get the corect results
.get();
String bodyText = document.body().text();
//We parse the json and extract the data
JSONObject jsonObject = new JSONObject(bodyText);
JSONArray jsonArray = jsonObject.getJSONObject("response").getJSONArray("docs");
for (Object object : jsonArray) {
JSONObject item = (JSONObject) object;
System.out.println("name = " + item.getString("name"));
System.out.println("link = " + "http://www.biletix.com/etkinlik/" + item.getString("id") + "/TURKIYE/en");
//similarly you can fetch more info ...
System.out.println();
}
}
I skipped the URL generation as I suppose you know how to generate it.
I hope all the explanation is clear, english isn't my first language so it is difficult for me to explain myself.
I have a AngularJS webapplication with a Jersey Backend Application.
Now everything is working fine using ngResource to access REST resource out of AngularJS. The only problem is with the DELETE option.
I have the following code to delete a course using my ngResource:
Course.deleteCourse = function(course) {
course.$remove({
courseId:course.id
});
return course;
};
In the backend (Jersey) I have the following code:
#DELETE
#Path("{id}")
public final void remove(#PathParam("id") final String id) {
System.out.println("DELETE ID = " + id);
}
If I try to delete an item the following url is called from Angular:
DELETE http://localhost:8080/manager-api/courses/5
This is fine (after me). If I call this url from CURL, i get the ssystem.out from the Backend posted to the console.
In the client-app (AngularJS) i get the following exception on the browser console:
DELETE http://localhost:8080/manager-api/courses/5 415 (Unsupported Media Type)
Anyone an idea what the problem might be? POST + GET are working fine.
I have the following consume/produce annotations:
#Consumes({ MediaType.APPLICATION_JSON })
#Produces({ MediaType.APPLICATION_JSON })
Thanks in advance for your help.
Greets
Marc
EDIT:
I have tried to replace the way of accessing the REST services out of AngularJS with $http.
Now my service looks as below:
MyApp.factory("Course", ["$http", function ($http) {
var courseBaseUrl = "/api/courses/";
return {
show: function show(courseId) {
return $http.get(courseBaseUrl + courseId);
},
list: function list() {
return $http.get(courseBaseUrl, {});
},
remove: function remove(courseId) {
return $http.delete(courseBaseUrl + courseId, {});
},
save: function save(course) {
return $http.post(courseBaseUrl, course, {});
}
};
}]);
The result is still the same. The application calls e.g
DELETE http://localhost:8080/manager-api/courses/1
and receives a
DELETE http://localhost:8080/manager-api/courses/1 415 (Unsupported Media Type)
If I call the same DELETE call on Curl, everything works fine.
Thanks for your help
Marc
I came across this as well, the problem is angular always sets the Content-Type header to xml on DELETE requests and jersey will chuck an error as you have specified that your api consumes/produces JSON with the annotations.
So to fix it (from the client side), set the content-type header, eg:
.config(function($httpProvider) {
/**
* make delete type json
*/
$httpProvider.defaults.headers["delete"] = {
'Content-Type': 'application/json;charset=utf-8'
};
})
However, for reasons I dont understand/dont know of, angular will strip away the content-type header from the request if it has no data. This would make sense if it wasn't for the fact that browsers (chrome at least) will always send a content-type... Anyway you will have to go to the trouble of finding this in the angular source:
// strip content-type if data is undefined
if (isUndefined(config.data)) {
delete reqHeaders['Content-Type'];
}
and get rid of it. I dont know of a way to do this without editing the source. Maybe someone with better JS know-how, erm, knows how.
Alternatively, from the server side, you can do as Rob has suggested and change the Jersey configuration to allow consuming MediaType.APPLICATION_XML
#Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public final void remove(#PathParam("id") final String id) {
System.out.println("DELETE ID = " + id);
}
I had same issue, Try returning new instance of Course object in your delete method.
#DELETE
#Path("{id}")
public final Course remove(#PathParam("id") final String id) {
System.out.println("DELETE ID = " + id);
return new Course();
}
Using angularjs $resource (instead of $http), without "payload" in the request, the content-type is setted as text/plain.
So IMHO it's better a server side support.
"Postel's Law states that you should be liberal in what you accept and conservative in what you send. -- source"
#DELETE
#Path("{id}")
#Consumes({ MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN })
public void remove(#PathParam("id") Long id) { ...