I basically have everything functioning following this tutorial on how to implement a API in flutter: https://docs.flutter.dev/cookbook/networking/fetch-data. I followed the tutorial but i get an error message "Failed to load Album". My understanding of this is that the server didn't respond with a 200 ok repsonse, but im not sure. I don't know how what the problem is and how i can get it to display the information. The API im using is a car registry, where you can type in a numberplate and get all the details for a vehicle.
Future<Album> fetchAlbum() async {
final response = await http
.get(Uri.parse('http://api.nrpla.de/Cz33849?api_token=JjCYzJA0B5FQPPjlWeyUqN3KSuaErwMyrryuQCmX7R6epHagtINaMjxfwaTGGyrl'),
headers: {
});
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
class Album {
final String registration;
final String type;
final String brand;
final String model;
final String version;
final String fuel_type;
final String registration_status;
final int engine_power;
final String doors;
final String leasing_period_start;
final String leasing_period_end;
final String color;
final String body_type;
Album({
required this.registration,
required this.type,
required this.brand,
required this.model,
required this.version,
required this.fuel_type,
required this.registration_status,
required this.engine_power,
required this.doors,
required this.leasing_period_start,
required this.leasing_period_end,
required this.color,
required this.body_type,
});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
registration: json['registration'],
type: json['type'],
brand: json['brand'],
model: json['model'],
version: json['version'],
fuel_type: json['fuel_type'],
registration_status: json['registration_status'],
engine_power: json['engine_power'],
doors: json['doors'],
leasing_period_start: json['leasing_period_start'],
leasing_period_end: json['leasing_period_end'],
color: json['color'],
body_type: json['body_type'],
);
}
}
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<Album> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.registration);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
),
),
),
);
}
}
You have consumed your monthly limit that's why you are not getting data from the API status code is 429
Related
I am trying to create an app that shows the current data in my web server using the Flutter plugin. I want to access the details of my web server using HTTP GET.
I followed this guide (https://docs.flutter.dev/cookbook/networking/fetch-data) and used the code as well but I can't make it work on my HTTP GET link since it has nested parameters.
Here is the code from the guide:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Album> fetchAlbum() async {
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
class Album {
final int userId;
final int id;
final String title;
const Album({
required this.userId,
required this.id,
required this.title,
});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({super.key});
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<Album> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
),
),
),
);
}
}
Here is my link by the way: https://api.thingspeak.com/channels/1864145/fields/1.json?results=1
and this is the array it contains
{
"channel":{
"id":1864145,
"name":"channel name",
"description":"description",
"latitude":"0.0",
"longitude":"0.0",
"field1":"first field",
"field2":"second field",
"field3":"third field",
"field4":"fourth field",
"created_at":"2022-09-18T11:53:33Z",
"updated_at":"2022-09-18T12:26:54Z",
"last_entry_id":10742
},
"feeds":[
{"created_at":"2022-12-27T05:34:12Z",
"entry_id":10741,
"field1":"111",
"field2":"4",
"field3":"28",
"field4":"61"
}
]
}
///edit
For those confused, I don't have a code yet since I have no idea how to do it but I tried to replace the variables based on our own parameters and it did not work so I thought there is a different way/code for the nested array parameters.
I used exactly same code from Flutter Documentation to fetch data from internet.
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Album> fetchAlbum() async {
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
class Album {
final int userId;
final int id;
final String title;
const Album({
required this.userId,
required this.id,
required this.title,
});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({super.key});
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<Album> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
),
),
),
);
}
}
It should display data with text widget after getting data, but http.get is not returning and it just keeps showing CircularProgressIndicator like:
I'm using Windows 10, Flutter 3.7.0 stable channel, Dart 2.19.0, http 0.13.5 version. How to fix this?
This could be because you haven't added the interne permissions in you android manifest
<manifest...
...
<uses-permission android:name="android.permission.INTERNET"/>
....
/manifest>
I am new in using bloc library with freezed package. I have a scenario where a list of objects is coming from API is displayed. Now the list tile has a Marked as Fav button and clicking upon it a event is trigged and fav bool is toggled and state is emitted.
The Issue :
The value of the object is changed but the UI is not updated accordingly.
Main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_bloc_update/bloc/fakeapi_bloc.dart';
void main() {
runApp(
BlocProvider(
create: (context) => FakeapiBloc(),
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const Scaffold(
body: SafeArea(child: MyHomePage()),
),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
context.read<FakeapiBloc>().add(const FakeapiEvent.loadData());
super.initState();
}
#override
Widget build(BuildContext context) {
return BlocBuilder<FakeapiBloc, FakeapiState>(
builder: (context, state) {
return state.map(
inital: (_) => const Center(
child: CircularProgressIndicator(),
),
loading: (_) => const Center(
child: CircularProgressIndicator(),
),
loaded: (state) {
return ListView.builder(itemBuilder: (ctx, pos) {
return ListTile(
title: Text(state.posts[pos].title),
trailing: IconButton(
onPressed: () {
context
.read<FakeapiBloc>()
.add(FakeapiEvent.markedFav(pos: pos));
},
icon: Icon(state.posts[pos].isFav
? Icons.favorite
: Icons.favorite_border_outlined),
),
);
});
},
error: (_) => const Center(
child: CircularProgressIndicator(),
),
);
},
);
}
}
Post.dart
import 'dart:convert';
List<Post> postFromJson(String str) =>
List<Post>.from(json.decode(str).map((x) => Post.fromJson(x)));
String postToJson(List<Post> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Post {
Post({
required this.userId,
required this.id,
required this.title,
required this.body,
});
final int userId;
final int id;
final String title;
final String body;
bool isFav = false;
factory Post.fromJson(Map<String, dynamic> json) => Post(
userId: json["userId"],
id: json["id"],
title: json["title"],
body: json["body"],
);
Map<String, dynamic> toJson() => {
"userId": userId,
"id": id,
"title": title,
"body": body,
};
}
bloc.dart
import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:freezed_bloc_update/post.dart';
import 'package:http/http.dart' as http;
part 'fakeapi_event.dart';
part 'fakeapi_state.dart';
part 'fakeapi_bloc.freezed.dart';
class FakeapiBloc extends Bloc<FakeapiEvent, FakeapiState> {
FakeapiBloc() : super(const FakeapiState.inital()) {
on<LoadData>(
(event, emit) async {
try {
emit(const FakeapiState.loading());
Uri uri = Uri.parse('https://jsonplaceholder.typicode.com/posts');
final response = await http.get(uri);
if (response.statusCode == 200) {
emit(FakeapiState.loaded(posts: postFromJson(response.body)));
} else {
emit(const FakeapiState.error(errorMessage: 'Api Call Failed'));
}
} catch (err) {
emit(const FakeapiState.error(errorMessage: 'Api Call Failed'));
}
},
);
on<MarkedFav>((event, emit) {
final previousState = state as Loaded;
previousState.posts[event.pos].isFav =
!previousState.posts[event.pos].isFav;
emit(FakeapiState.loaded(posts: [...previousState.posts]));
});
}
}
events.dart
part of 'fakeapi_bloc.dart';
#freezed
class FakeapiEvent with _$FakeapiEvent {
const factory FakeapiEvent.loadData() = LoadData;
const factory FakeapiEvent.markedFav({required int pos}) = MarkedFav;
}
states.dart
part of 'fakeapi_bloc.dart';
#freezed
class FakeapiState with _$FakeapiState {
const factory FakeapiState.inital() = Initial;
const factory FakeapiState.loading() = Loading;
const factory FakeapiState.loaded({required List<Post> posts}) = Loaded;
const factory FakeapiState.error({required String errorMessage}) = Error;
}
One solution which I did was keeping a bool variable(outside of model class) in state itself and clicking upon the fav toggling the bool value. Which is retriggering the UI update.
your Post class should be converted to a freezed class
I'm new to flutter and im trying to design an application that pulls information via a car numberplate. I have followed this tutorial regarding the API: https://docs.flutter.dev/cookbook/networking/fetch-data. For the API i need to specify the numberplate which i have used this tutorial where its saved text from the textfield: https://docs.flutter.dev/cookbook/forms/retrieve-input. I can't seem to figure out how to get text from the textfield and then make the API call.
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
void main() => runApp(const MyApp());
Future<Album> fetchAlbum() async {
final response = await http
.get(Uri.parse('https://v1.motorapi.dk/vehicles/'),
headers: {"X-AUTH-TOKEN": "rfrzsucnc7eo3m5hcmq6ljdzda1lz793"});
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
//headers: {"X-AUTH-TOKEN": "rfrzsucnc7eo3m5hcmq6ljdzda1lz793"}
class Album {
final String registration_number;
final String status;
final String type;
final String use;
final String first_registration;
final String vin;
final int doors;
final String make;
final String model;
final String variant;
final String model_type;
final String color;
final String chasis_type;
final String engine_power;
final String fuel_type;
final String RegistreringssynToldsyn;
final String date;
final String result;
Album({
required this.registration_number,
required this.status,
required this.type,
required this.use,
required this.first_registration,
required this.vin,
required this.doors,
required this.make,
required this.model,
required this.variant,
required this.model_type,
required this.color,
required this.chasis_type,
required this.engine_power,
required this.fuel_type,
required this.RegistreringssynToldsyn,
required this.date,
required this.result,
});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
registration_number: json['registration_number'],
status: json['status'],
type: json['type'],
use: json['use'],
first_registration: json['first_registration'],
vin: json['vin'],
doors: json['doors'],
make: json['make'],
model: json['model'],
variant: json['variant'],
model_type: json['model_type'],
color: json['color'],
chasis_type: json['chasis_type'],
engine_power: json['engine_power'],
fuel_type: json['fuel_type'],
RegistreringssynToldsyn: json['RegistreringssynToldsyn'],
date: json['date'],
result: json['result'],
);
}
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Retrieve Text Input',
home: MyCustomForm(),
);
}
}
// Define a custom Form widget.
class MyCustomForm extends StatefulWidget {
const MyCustomForm({Key? key}) : super(key: key);
#override
_MyCustomFormState createState() => _MyCustomFormState();
}
// Define a corresponding State class.
// This class holds the data related to the Form.
class _MyCustomFormState extends State<MyCustomForm> {
// Create a text controller and use it to retrieve the current value
// of the TextField.
final myController = TextEditingController();
#override
void dispose() {
// Clean up the controller when the widget is disposed.
myController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Retrieve Text Input'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
controller: myController,
),
),
floatingActionButton: FloatingActionButton(
// When the user presses the button, show an alert dialog containing
// the text that the user has entered into the text field.
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
// Retrieve the text the that user has entered by using the
// TextEditingController.
content: Text(myController.text),
);
},
);
},
tooltip: 'Show me the value!',
child: const Icon(Icons.text_fields),
),
);
}
}
change your code for this
// Define a corresponding State class.
// This class holds the data related to the Form.
class _MyCustomFormState extends State<MyCustomForm> {
// Create a text controller and use it to retrieve the current value
// of the TextField.
TextEditingController myController ;
#override
void dispose() {
// Clean up the controller when the widget is disposed.
myController.dispose();
super.dispose();
}
#override
void initState() {
super.initState();
myController=TextEditingController();
futureAlbum = fetchAlbum();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Retrieve Text Input'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
controller: myController,
),
),
floatingActionButton: FloatingActionButton(
// When the user presses the button, show an alert dialog containing
// the text that the user has entered into the text field.
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
// Retrieve the text the that user has entered by using the
// TextEditingController.
content: Text(myController.text),
);
},
);
},
tooltip: 'Show me the value!',
child: const Icon(Icons.text_fields),
),
);
}
You miss this method
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
I want to pass some parameters in flutter url
here is example:
parameters are source , destination , type, fare.
url is http://localhost:9000/api/bmrc/fare/source/destination/fare/type
url need to send http://localhost:9000/api/bmrc/fare/1/17/2/SJT
(workinng in postman/thunderclient)
I tried after passing these parameters in body but its not worked for me
They are Path Parameters, not body JSON.
You can call your API like this:
callAPI(int source,int destination,int fare,String type){
String _url= "http://localhost:9000/api/bmrc/fare/${source}/${destination}/${fare}/${type}";
... //call your API with _url
}
You can change the param types as you like
its a POST Call:
To get data from from your url, try this.
Here is the sample Example:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Future<Post> post;
#override
void initState() {
super.initState();
post = fetchPost();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter REST API Example',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: Scaffold(
appBar: AppBar(
title: Text('Flutter REST API Example'),
),
body: Center(
child: FutureBuilder<Post>(
future: post,
builder: (context, abc) {
if (abc.hasData) {
return Text(abc.data.title);
} else if (abc.hasError) {
return Text("${abc.error}");
}
// By default, it show a loading spinner.
return CircularProgressIndicator();
},
),
),
),
);
}
}
Future<Post> fetchPost() async {
final response = await http.get('Give your JSON file web link.');
if (response.statusCode == 200) {
// If the call to the server was successful (returns OK), parse the JSON.
return Post.fromJson(json.decode(response.body));
} else {
// If that call was not successful (response was unexpected), it throw an error.
throw Exception('Failed to load post');
}
}
class Post {
final int userId;
final int id;
final String title;
final String description;
Post({this.userId, this.id, this.title, this. description});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
userId: json['userId'],
id: json['id'],
title: json['title'],
description: json[' description'],
);
}
}