Flutter/Dart API Call Throws Error (sometimes) - flutter

APIs:
https://www.nseindia.com/api/option-chain-indices?symbol=NIFTY
https://www.nseindia.com/api/option-chain-indices?symbol=BANKNIFTY
API Call Method:
import 'package:http/http.dart';
import '../Models/fetched_data.dart';
Future<FetchedData?> fetchIndexDetails(String index) async {
final String url =
'https://www.nseindia.com/api/option-chain-indices?symbol=$index';
try {
final response = await get(
Uri.parse(url),
);
final FetchedData? fetchedData = fetchedDataFromJson(response.body);
return fetchedData;
} catch (e) {
print('$index Error: $e');
}
return null;
}
The json file is same for both the APIs, hence the model class too.
However, the second API call works smoothly but the first API call throws an error saying:
type 'double' is not a subtype of type 'int?'
Can anybody help me decode the problem here? Much tia :)

This is a JSON parsing issue for unmatched type parsing of the API and the your Dart Model ..
How to diagnose it?
You can always catch those errors while the development by enabling the dart debugger for uncaught exceptions, which gives you exactly the broken casting

type 'double' is not a subtype of type 'int?'
The API has returned a double value where an int is expected.
In your model or where appropriate replace the expected type to use num which int and double are both subtypes of

Check your model class where you have defined different variables and match with data type you are getting in response from the json.
There must be a variable you have defined in model class as int? but u r getting double as a response so u got to convert the data type .

Seems like you are trying to map a double to int?, the response had a double and you are assigning it to int?, add a breakpoint when mapping the response to see the corresponding field. You can try casting it to int or just changing the type all together.

Related

Flutter, external DLL and Pointer<Char> vs Pointer<Utf8>

I try to call the tesseract C api within flutter. So far without success. The function "TessBaseAPIInit3" requires the 2nd and 3rd parameter to be of type Pointer<Char>. The following is what dart run ffigen generated out of tesseract's capi.h:
import 'dart:ffi' as ffi;
...
int TessBaseAPIInit3(
ffi.Pointer<TessBaseAPI> handle,
ffi.Pointer<ffi.Char> datapath,
ffi.Pointer<ffi.Char> language,
) {
return _TessBaseAPIInit3(
handle,
datapath,
language,
);
}
late final _TessBaseAPIInit3Ptr = _lookup<
ffi.NativeFunction<
ffi.Int Function(ffi.Pointer<TessBaseAPI>, ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>)>>('TessBaseAPIInit3');
late final _TessBaseAPIInit3 = _TessBaseAPIInit3Ptr.asFunction<
int Function(ffi.Pointer<TessBaseAPI>, ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>)>();
The following is my code which calls TessBaseAPIInit3 which requires 3 parameters of type Pointer<TessBaseAPI>, Pointer<Char>, Pointer<Char>. The string literals i create with toNativeUtf8 have type Pointer<Utf8> which i cast to Pointer<Char> in the hope that they are equivalent. But the cast from Pointer<Utf8> to Pointer<Char> gives an error.
import 'dart:ffi';
...
final DynamicLibrary tesseractDLL = DynamicLibrary.open(Platform.script.resolve("build/windows/runner/Debug/libtesseract-5.dll").toFilePath());
NativeLibrary tesseractLib = NativeLibrary(tesseractDLL);
final handle = tesseractLib.TessBaseAPICreate();
final Pointer<Char> dataPath = ''.toNativeUtf8() as Pointer<Char>;
final Pointer<Char> language = 'eng'.toNativeUtf8() as Pointer<Char>;
if (tesseractLib.TessBaseAPIInit3(handle, dataPath, language) != 0)
print("Error initializing tesseract\n");
The error message is: [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'Pointer<Utf8>' is not a subtype of type 'Pointer<Char>' in type cast
Any ideas what goes wrong? I have no idea how to create a string literal of type Pointer<Char>. The function 'toNativeUtf8' generates Pointer<Utf8>.
Is this "the right way" to call tesseract functions? Is it possible to use the c++ api anyhow? I don't want to use any wrapper, i would like to interact with the tesseract api directly.
Following did the trick. The native utf8 string needed to be cast to Char.
final dataPath = ''.toNativeUtf8().cast<Char>();
final language = 'eng'.toNativeUtf8().cast<Char>();

NoSuchMethodError: Class 'List<dynamic>' has no instance method 'cast' with matching arguments

I am trying to fetch Articles from my API servers,but i get NoSuchMethodError: Class 'List<dynamic>' has no instance method 'cast' with matching arguments error. Does anybody know how can i solve it?
List<Article> posts;
final response = await http.get(Uri.parse("$SERVER_IP/api/articles/?format=json"),
headers: <String, String>{"Authorization" : "Token ${globaltoken}"},);
final parsed = jsonDecode(utf8.decode(response.bodyBytes)).cast<String,dynamic>();
posts = parsed.map<Article>((json) => Article.fromJSON(json)).toList();
return posts;
You should not use cast() in the first place, because a nearby operation (in this case the parsed.map) already uses cast() for you and thus casts your desired type (Article). Omitting cast<String,dynamic>() should solve your error.
Please also refer to the dart documentation:
https://dart.dev/guides/language/effective-dart/usage#dont-use-cast-when-a-nearby-operation-will-do
https://dart.dev/guides/language/effective-dart/usage#avoid-using-cast

The argument type 'String?' can't be assigned to the parameter type 'String'

when I upgrade my flutter to 2.0.1, shows this error:
The argument type 'String?' can't be assigned to the parameter type 'String'.
this is my code:
enum SubStatus {
SUB,
UNSUB,
}
extension ResponseStatusExtension on SubStatus{
static const statusCodes = {
SubStatus.SUB: "sub",
SubStatus.UNSUB: "unsub",
};
String? get statusCode => statusCodes[this];
}
This is how to use it:
String url = "/post/sub/source/" + subStatus.statusCode + "/" + channelId;
this is the error UI:
what should I do to fix it? I tried to return String but in the enum code tell me should return String?:
what should I do?
Change the return type of statusCode to String and provide a default value.
String get statusCode => statusCodes[this] ?? '';
When accessing a map, there is a chance that you will get a null return value if the key does not exist in the map. Simply providing a default value will allow this code to compile. That default value should never be used unless you add something to the enum without adding a value to the map as well.
Edit:
After the comment from #Christopher Moore, I realized my mistake. So, I am going to directly use his solution over here as it is the correct one.
This is because of the new null-safety feature of Dart.
You will need to make the following change in the code and it will work:
String get statusCode => statusCodes[this] ?? '';
With new null-safety rules, the following data-type? x, the data type is followed by a question mark, means that the value x can be null. However, without the '?', it means that data-type x, it cannot be null.
So, basically String and String? are two different data types. That is why you get the error.
You can learn more here.
restart analysis server
add !
like this
subStatus.statusCode!

Flutter: http response based on model strict type

I want to implement a strict type http request/response. I'm new in flutter but have some experience in typescript. I don't know if I'm doing it right. Sorry I dont have enough reputation to post the screenshot of my code.
Actual screenshot of code
My first issue is on line 21: "type 'String' is not a subtype of type 'Api' in type cast". I want to convert the response.body to the same expected response of the login func
Then next is line 31, my concern here is the error variable is a dynamic type that cannot be 'Api' response. Can I make it possible to have to expected response type? or any workaround to this?
I hope someone could help me with this one. Thank you in advance.
The body is a json, you need to parse it first and create the Api model from it.
import 'dart:convert';
...
var responseData = jsonDecode(restResponse.data); //
if(responseData is Map){
Data.fromJson(responseData); //you can read the map entries and create a Data entry.
}
You can write a base class as response, and have a success class and an error class, and you can check those from the caller side. I'd suggest to return the parsed json without any model mapping and map the json to model from the caller side.
abstract class ResponseBase {}
class ResponseSuccess extends ResponseBase {
final dynamic data;
ResponseSuccess(this.data);
}
class ResponseError extends ResponseBase {
final int statusCode;
ResponseError(this.statusCode);
}
Future<ResponseBase> login(...
And from the caller:
whenLoginClicked() async{
var response = await repository.login(data, devideId);
if(response is ResponseSuccess){
// parse the response.data
} else if(response is ResponseError){
// handle error
}
}

Cannot access map object with []. operator [] is not defined

I am working on a mobile application using Flutter 1.7.8.
I collected data from the server in a form of a nested json object, e.g.
class Obj {
final String obj_to_access;
const Obj({this.obj_to_access});
factory Obj.fromJson(Map<String, dynamic> json) {
return Obj(
obj_to_access: json['item']
);
}
some_obj =
{
"id": some_id,
"nested_obj": Obj.fromJson(json["obj_to_access"])
}
However, I can't seem to access the nested Obj with '[]' and it always give me this error: The operator '[]' isn't defined for the class 'Obj'. Try defining the operator.
I saw that I should try defining the '[]' but I am not sure how. Please help thanks
The reason for the error is that you're passing a dynamic value to Obj.fromJson() instead of a Map - which it expects. To solve this issue, you can add cast as <Map<String, dynamic>> to the value to let the compiler know that it's a Map.