Flutter API throwing Exception - json

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/';

Related

Wp api for flutter

I am trying to use the wordpress api, but it throws me an error when entering the url.
Error: The argument type "String" can't be assigned to the parameter type Uri
Could someone explain the error to me and tell me how the code should look? Thanks
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<List> blog() async {
final response = await http.get(('https://bauk.blog/wp-json/wp/v2/posts?_embed': {"Accept": "application/json"}));
var convertirajson = jsonDecode(response.body);
return convertirajson;
}
You need to parse the url before passing it to http.get()
For that declare your url variable like this:
var url = Uri.parse('https://bauk.blog/wp-json/wp/v2/posts?_embed');
And then pass it to http.get() like this
http.get((url: {...} ));

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.

Get json Data from Rapid API in Flutter (Dart)

I managed to load the data from a Json File which is local on my Flutter Project. I also was able to fetch Data from the Internet, if the API Url was like:
https://[API-Server][parameter1:xy][parameter2:abc][API-KEY:lasgoewrijeowfjsdfdfiia]
I archieved that with this code sample:
Future<String> _loadStringFixtures() async {
return await rootBundle.loadString('assets/fixtures.json');
}
Future loadFixtures() async {
String jsonString = await _loadStringFixtures();
final jsonResponse = json.decode(jsonString);
FixturesAPI value = new FixturesAPI.fromJson(jsonResponse);
return value;
}
So far so good...
But now I am facing a problem with the API Provider RapidAPI
You can find the documentation etc. here:
https://rapidapi.com/api-sports/api/api-football/endpoints
As you can see they give some code snippets to connect to their API.
There are some for C, C#, Java, Python etc. You can look into all of them with the link above.
Sadly there is no example for Flutter.
And I do not see a way to adapt these examples.
Normally you can paste your API Key directly into the URL, but this seems not possible here? Or maybe it is?
Does Flutter also have other possibilities to receive data from an API besides the one I did?
Thank you so much in advance for your help!
It's possible to with http package and very easy. You can see in this example below...
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
class APIService {
// API key
static const _api_key = <YOU-API-KEY-HERE>;
// Base API url
static const String _baseUrl = "api-football-beta.p.rapidapi.com";
// Base headers for Response url
static const Map<String, String> _headers = {
"content-type": "application/json",
"x-rapidapi-host": "api-football-beta.p.rapidapi.com",
"x-rapidapi-key": _api_key,
};
// Base API request to get response
Future<dynamic> get({
#required String endpoint,
#required Map<String, String> query,
}) async {
Uri uri = Uri.https(_baseUrl, endpoint, query);
final response = await http.get(uri, headers: _headers);
if (response.statusCode == 200) {
// If server returns an OK response, parse the JSON.
return json.decode(response.body);
} else {
// If that response was not OK, throw an error.
throw Exception('Failed to load json data');
}
}
}
Then get you request:
//....
APIService apiService = APIService();
// You future
Future future;
//in the initState() or use it how you want...
future = apiService.get(endpoint:'/fixtures', query:{"live": "all"});
//....
Yes it possible in flutter. Use the Dio Package in flutter which is a powerful Http client. Using dio you can set interceptors to add api key to url so you don't have to append it in every request. Setting interceptors will help you.

ANGULAR 6 http get 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.

Flutter - using an API key

I'm making an app that grabs cryptocurrency JSON data from the public v1 Api but support for this will soon be dropped, meaning that I'll have to migrate the the more powerful professional v1 Api.
The only issue is, I don't know how to implement the use of the new Api key thats required as I parse the JSON data.
I'm using a heavily modified version of this git repo to program the app, but all basic functionality is based here.
All I need is guidance on what I need to add to this file to display the new professional v1 Api, any comments or ideas are appreciated. Thanks
This the the crypto_data_prod.dart file where I would have to change my code for use with the key.
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:fluttercrypto/data/crypto_data.dart';
class ProdCryptoRepository implements CryptoRepository {
String cryptoUrl = "https://api.coinmarketcap.com/v1/ticker/?limit=50";
#override
Future<List<Crypto>> fetchCurrencies() async {
// TODO: implement fetchCurrencies
http.Response response = await http.get(cryptoUrl);
final List responseBody = JSON.decode(response.body);
final statusCode = response.statusCode;
if (statusCode != 200 || responseBody == null) {
throw new FetchDataException(
"An error ocurred : [Status Code : $statusCode]");
}
return responseBody.map((c) => new Crypto.fromMap(c)).toList();
}
}
Try to change http.Response response = await http.get(cryptoUrl); to
http.Response response = await http.get(cryptoUrl,
headers: {"X-CMC_PRO_API_KEY": "cab79c7b-52e9-4e4b-94fc-b0f32da14799"});
For more info check this link.