ANGULAR 6 http get JSON - json

I am having trouble getting information from certain json file.
case 1 (works):
service:
private xmlToJson: string = 'https://rss2json.com/api.json?rss_url=';
getImg(Url: string) {
return this.http.get(this.xmlToJson + Url);
}
component:
private url='https://api.flickr.com/services/feeds/photos_public.gne';
public images: any = [];
this.imgDataService.getImg(this.url)
.subscribe(data => this.images = data);
HTML:
<h1>{{images.feed.title}}</h1>
case 2 (does not work):
service:
getImg(Url: string) {
return this.http.get(Url);
}
component:
private url = 'https://api.flickr.com/services/feeds/photos_public.gne?format=json&nojsoncallback=1';
public images: any = [];
this.imgDataService.getImg(this.url)
.subscribe(data => this.images = data);
HTML:
<h1>{{images.title}}</h1>
Any idea why case 2 doesn't work? I ran both JSONs here: https://jsonlint.com/ and they came out valid.

You have a CORS error.
Here is a StackBlitz showing the two calls and what is returned from the server. The call for the Flickr URL fails because the Flickr API doesn't (at least on this service) return headers for Access-Control-Allow-Origin to enable public access.
Ironically, you'll be able to call the web service from any code that is not running in a web browser.
Since you probably won't be able to convince them otherwise (others have tried), I would suggest you give up on Flickr.
A final note: You would be able to see the error if you opened your browser's developer tools and checked the console. That should be your first stop for any weird behaviour you encounter in web development.

Change the public images: any = []
to public images: any = {}
Images data isn't an array.

Instead of this.imgDataService.getImg(this.url) type this.imgDataService.getImg(this.url2)

you can try this approach if you know what kind of json response is expected then probably you can create class like
Example:
export class ImageModel{
name:string;
title:string;
src:string;
}
where name,title and src are json keys
then in you can do:
constructor(private httpService:HttpService){}
getImg(Url: string) {
return this.httpService.get<ImageModel>(
(image:ImageModel) => {return image}
}
new HttpService should automatically map your json data to the javascript class/Interface
and then you can read the image to get the json data.

Related

Flutter API throwing Exception

I was practicing this covid-19 tracker application using flutter from a tutorial on YouTube, so after writing a few code when I hit the API and run the application, it throws this exception, I don't understand why as I am a beginner and a newbie on Flutter.
import 'dart:convert';
import 'package:covid_tracker/Model/world_states_model.dart';
import 'package:http/http.dart' as http;
import 'Utilities/app_url.dart';
class StatesServices {
// async means waiting for your request
Future<WorldStatesModel> fetchWorldStatesRecords() async {
final response = await http.get(Uri.parse(AppUrl.worldStatesApi));
if (response.statusCode == 200) {
var data = jsonDecode(response.body);
return WorldStatesModel.fromJson(data);
} else {
throw Exception('Error');
}
}
}
class AppUrl {
// this is our base url
static const String baseUrl = 'https://disease.sh/v3/covid-19';
// fetch world covid states
static const String worldStatesApi = '${baseUrl}all';
static const String countriesList = '${baseUrl}countries';
}
You are getting a status code that's not 200. Therefore your application throws an error, just as you have programmed it!
The first step would be to actually figure out why you are getting a different status code from 200. Looking at your code it seems that you try to visit '${baseUrl}all'. This translates to https://disease.sh/v3/covid-19all. This URL however does not exist.
To fix your issue try adding a / after ${baseUrl}. Such that it becomes '${baseUrl}/all'. Or add the change the baseUrl variable to https://disease.sh/v3/covid-19/. After that, your error should be resolved.
I recommend printing to the console what links you are trying to load. It would probably prevent this kind of issue in the future. Or even more useful, include it in the exception you throw. :)
if stataus !=200 from API,
You are throwing exception in this line
throw Exception('Error');
it shows API is not returning the needed data.
Try to change line
static const String baseUrl = 'https://disease.sh/v3/covid-19';
to
static const String baseUrl = 'https://disease.sh/v3/covid-19/';

Angular HttpClient returns string data instead of parsed JSON

I've been in the process of migrating a code base from Angular 4.x to 5.x, and I'm running into a strange issue. I have a service function, that is intended to return a list of objects to the front end, which I then massage into a specific data format. I know I'll need to keep the mapping, but I'm a little miffed that it's returning just plain string data.
The original function is this: (using Http from #angular/http just renamed to HttpClient)
public GetVendors(showAll = true, screenArea: number = 0): Observable<Array<SelectModel>> {
let link = AppSettings.API_COMMON_VENDORS;
let params: URLSearchParams = new URLSearchParams();
params.set('showAll', showAll.toString());
params.set('screenArea', screenArea.toString());
let requestOptions = new RequestOptions();
requestOptions.search = params;
return this.httpClient.get(link, requestOptions).map(response => {
let result = JSON.parse(response.json());
let list = new Array<SelectModel>();
let vendors: Array<any> = result;
vendors.forEach(vendor => {
list.push(this.CreateSelectModel(vendor));
});
return list;
});
}
and after ripping out ALL of the Http code, here's the function again using HttpClient from #angular/common/http
public GetVendors(showAll = true, screenArea: number = 0): Observable<Array<SelectModel>> {
let link = AppSettings.API_COMMON_VENDORS;
let params: HttpParams = new HttpParams()
.set('showAll', showAll.toString())
.set('screenArea', screenArea.toString());
return this.httpClient.get<Array<any>>(link, {params}).map(response => {
let list = new Array<SelectModel>();
response.forEach(vendor => {
list.push(this.CreateSelectModel(vendor));
});
return list;
});
}
The issue with this is it kind of defeats the purpose of the new client parsing json for me. The response object is a string representing the JSON of the data I requested, but it's still in a string form, and not the type defined in the get<>() call.
What am I doing wrong here? shouldn't it be parsed already?
Sample Response Data A'la Network Tools in Chrome Dev Tools:
Sample Response Body:
Dev Tools Screenshot with Value of response
The backend (C#) responds with this:
[HttpGet]
public JsonResult Vendors(bool showAll = false, int screenArea = 0)
{
var vendors = _commonBL.GetVendorsSlimForUser(UserModel, UserModel.CustomerId, showAll, screenArea);
return GetJson(vendors);
}
this is how it worked before the Http => HttpClient migration, and it worked with ONE JSON.parse() The data in the return line is simply a standard List<T>
This is what the raw response for your data should look like:
[{"Id":1234,"Name":"Chris Rutherford"}]
But this is what it actually looks like:
"[{\"Id\":1234,\"Name\":\"Chris Rutherford\"}]"
So somewhere in your server code, you have applied JSON encoding twice. Once you correct that, HttpClient will do the right thing.
I'd quote an answer from this thread. Hope it will shed some light on how things work, read it thoroughly it enlightened me tough its not easy to find.
TypeScript only verifies the object interface at compile time. Any object that the code fetches at runtime cannot be verified by
TypeScript.
If this is the case, then things like HttpClient.Get should not
return Observable of type T. It should return Observable of type Object because
that's what is actually returned. Trying to state that it returns T
when it returns Object is misleading.
In the documentation the client's return section says this:
#return an Observable of the body as
type T.
In reality, the documentation should say:
#return an Observable of the body which
might be T. You do not get T back. If you got T back, it would
actually be T, but it's not.

Angular 6 HttpClient.get Observable does not assign value

I suppose that the answer will be very obvious, but still it evades me. I'm new on working with observables, and now I'm facing issues assigning a value from one. I had success if I define it (this._apps) as an Observable and asking from the view to the service using subscribe (But for my taste is was way convoluted (three levels inside a map just to return another observable with the array and then another function to subscribe the previous to assign the variable and another subscription in the view to finally show the information), inefficient and on top of that I could not get it "right" again). The task is very simple. Given the class Application
export class Application {
name: string;
baseUrl: string;
deprecated: boolean;
}
And the service (just the relevant code)
private _apps: Application[] = [];
constructor(private _http: HttpClient) {
this.getAllApplications().subscribe(apps => {
console.log('Apps subscriber');
this._apps = apps;
console.log('Apps subscriber Ends ' + apps);
},
err => {
console.log(err.status); // 401
console.log(err.error.error); // undefined
console.log(JSON.parse(err.error).error); // unauthorized
});
}
private getAllApplications() {
return this._http.get<Application[]>('http://development:4300/api/v1/apps');
}
From the constructor the function which gets the information from WebAPI is triggered, and the remote call is successful, but the variable this._apps is an empty array if I try to call it from anywhere in the code. I could not determine the type of the parameter "apps" in the subscribe function, but for some reason it cannot be assigned and the best answer given is that it is a function (See my first update) in one of my tries. Currently it returns in the console "[object Object]", but apps[0] gives undefined, so it is an empty Array.
This is the console output, just starting the application:
Angular is running in the development mode. Call enableProdMode() to enable the production mode.
Refreshing apps cache calling http://development:4300/api/v1/atbc-apps
Apps subscriber
Apps subscriber Ends [object Object]
I was trying this solution among many others that I forget (to use the more modern HttpClient instead the Http I used before), so what I'm doing wrong?
Update 1
I changed the constructor to this:
constructor(private _http: HttpClient) {
this.getAllApplications().subscribe(apps => {
console.log('apps length ' + apps.length);
this._apps = apps; // Remember private _apps: Application[] = [];
console.log('Apps subscriber Ends ' + apps.toString);
},
err => {
console.log(err.status); // 401
console.log(err.error.error); // undefined
console.log(JSON.parse(err.error).error); // unauthorized
});
}
and the declaration of the function called into this:
private getAllApplications(): Observable<Application[]> {
// the exactly the same as before
}
And now I got from the console this:
apps length undefined
Apps subscriber Ends
function () {
if (this instanceof Promise) {
return PROMISE_OBJECT_TO_STRING;
}
return originalObjectToString.apply(this, arguments);
}
That is the function I was talking about. Any ideas about why even though there is no errors (nor at compile time, neither at runtime), the returning object is not a real Application array?
Change this line:
private _apps: Application[] = [];
to:
_apps: Application[] = [];
Which will default to making it public. Then this line will see it:
this._apps = apps;
At the end I suppose is a mindset to work with Observables, and I tried to build a kind of cache, so the only way I could do it (let me know if there is a better way) was using the view to fill-out the cache. I could not do it from the service itself because the calling the function from the view is synchronous and to fill out the array is async. So I had to create a public setApplicationCache procedure which is filled out after calling the service from the view, it call the setApplicationCache( Application[] ) function and the rest works because it takes just the cache to do filtering and other operations or use it from other pages w/o calling the database again and again.
This is the code from the first view called (main page)
ngOnInit() {
this._myService.getAllApplications().subscribe(arrObjApps => {
this._myService.setApplicationsCache(arrObjApps)
this.listApps = this._myService.getApplications(true);
});
And the service has this functions:
private _apps: Application[] = [];
getAllApplications(): Observable<Application[]> {
return this._http.get('http://development:4300/api/v1/atbc-apps').pipe(
map( (response: Response) => {
let results = response.json().data.map( app => {
return new Application(app.name, app.baseUrl, app.deprecated);
});
return results;
})
);
}
getApplication(appName: string): Application {
return this._apps.find(app => app.name == appName);
}
getApplications(onlyActives: boolean): Application[] {
if (onlyActives) {
return this._apps.filter(app => app.deprecated == false);
} else {
return this._apps;
}
}
And as I stated the solution should be obvious. Just again the async mindset required to work with observables.

Angular 2 sees my Json object as an function

I have a webapp that gets via Json stuff put it in objects to display them.
I already did it two times with services and classes.
But now i copy and paste the old code make some slight changes to make sure it redirect to the good classes but now i get an array with functions instead an array with objects.
Here is my constructor that calls upon the the service classes and send things to the console
constructor(private featureService : FeatureService, private scenarioservice : ScenarioService, private failuresService : FailuresService){
//hier worden de features en failures opgehaald
this.featureService.getFeatures().subscribe(res => {
this.featureArray = res.getFeatureArray();
console.log(res.getFeatureArray());
});
this.failuresService.getFailures().subscribe(res => {
this.failureArray = res.getFailureArray();
console.log(res.failures[0].method);
console.log(this.failureArray);
});
}
}
Here is failuresService.getFailures:
import { Injectable } from "#angular/core";
import {Http, Response} from "#angular/http";
import {Failure} from "./Failure";
import {Failures} from "./failures";
#Injectable()
export class FailuresService {
constructor(protected http: Http) {}
getFailures() {
return this.http.get('http://localhost:8080/testresultaten')
.map((response: Response) => response.json())
.map(({failures = [Failure]}) => new Failures(failures));// deze error is bullshit
}
}
This is the Json that I get and want to get in an class:
{
"failures:": [
{
"method": "canRollOneGame",
"object": "BowlingGame.GameTest"
},
{
"method": "canCountNighteeneight",
"object": "FizzBuzz.FizzBuzzTest"
}
]
}
Here are the Failure and Failures classes:
import {Failure} from "./Failure";
export class Failures {
constructor(public failures : Failure[]){}
public getFailureArray(): Failure[]{
return this.failures;
}
}
export class Failure{
constructor(public method : String , public object : String ){ }
}
I could be wrong but this doesn't look right:
getFailures() {
return this.http.get('http://localhost:8080/testresultaten')
.map((response: Response) => response.json())
.map(({failures = [Failure]}) => new Failures(failures));// deze error is bullshit
}
That last mapping, I'm not sure what it is supposed to do. I've never seen that syntax (doesn't mean it's wrong). I get that you have an incoming array. But what this syntax does {failures = [Failure]} is what I think your problem is. I don't think that will do what you think.
Try this and see what happens:
.map(failures => { console.log ( failures ); new Failures(failures) } );// deze error is bullshit
If you try that with your old mapping, and then this new one, it'd be interesting to see what that console.log traces out. I think doing it your way, you won't see what you expect.
If that sorts you out, then you can try typing the incoming payload (though I'm not sure it'll work; it should be receiving JSON from the previous mapping).
.map( (failures: Array<Failure>) => { console.log ( failures ); new Failures(failures) } );
So if I read it correctly: Your goal is to create an array of Failure objects with the values coming from a JSON array where each of this has a method you'd like to execute somewhere in the code.
If thats the case then I understand what went wrong. As Tim Consolazion mentioned in the comments you only get the values for the Failure object not the Failure object itself (See custom created method error: "is not a function"). So in order to execute the commands from Failure you have to create for each object in your JSON array a Failure object. Something like this:
return this.http.get('http://localhost:8080/testresultaten')
.map((response: Response) => {
let content = response.json();
let failureList: Failure[] = [];
content.forEach(failure => {
failureList.push(new Failure(failure.method, failure.object))
});
return failureList || {};
}
What I wonder is where you found {failures = [Failure]}? I've never seen this before and I've no idea what this is for.
EDIT: I edited the question so it fits your class Failure. The failure in content.forEach(failure => { in an object from your JSON array. You can access the values of it like it is a normal object. In your case with failure.method and failure.object.
I found my problem in the Json the name was function: but in my code it was function so all that was necessary was to make sure it sends function instead of function:

ASP .Net MVC 5 JsonResult caching

can someone explain me how to implement caching of JsonResult actions in MVC 5 application?
I want to use caching of some ajax-called actions using [OutputCache()] attribute. Some of these actions return ActionResult with html-content, some JsonResult with serialized lists of {Id, Title} pairs which I'm going to use to construct dropdown lists.
My goal is to reduce amount of DB-queries (while building ViewModels) and server requests (when using ajax-calls for it).
So, my code looks like snippets below:
[OutputCache(Duration=60*60*24)]
public async Task<ActionResult> SearchCaseOrgDialog(){
//extract data return html page
return View();
}
[OutputCache(Duration=60*60*24)]
public async Task<JsonResult> AjaxOrgDepartments(){
//query database, serialize data, return json
var result = await ctx.OrgDepartments
.Select(d => new {
Id = d.Id,
Title = d.Title }
)
.ToListAsync();
return Json(result, JsonRequestBehavior.AllowGet);
}
When I look at FireFox tools-panel I see next picture for Html-content:
Here Firefox uses client-side cached version of ajax-requested page.
But situation differs with json-content:
It doesn't cache content, and seems to transfer data from server (server-side cache).
In both cases response headers look the same:
Cache-Control:"public, max-age=86400, s-maxage=0"
Content is requested using similar ajax-calls like
$.get(url, null, function(data){
//do something with data
});
So, how do I cache json-content? what is the right way to do it, and why default approach does not work?
If you want to avoid DB queries, you should consider caching the data at server side. You can use MemoryCache class to do that.
Quick sample
public class MyLookupDataCache
{
const string categoryCacheKey = "CATEGORYLIST";
public List<string> GetCategories()
{
var cache = MemoryCache.Default;
var items = cache.Get(categoryCacheKey);
if (items != null)
{
CacheItemPolicy policy = new CacheItemPolicy();
policy.AbsoluteExpiration = DateTime.Now.AddDays(7); //7 days
//Now query from db
List<string> newItems = repository.GetCategories();
cache.Set(categoryCacheKey, newItems, policy);
return newItems;
}
else
{
return (List<string>) items;
}
}
}
You can change the method signature to return the type you want. For simplicity, i am using List<String>