Lấy dữ liệu từ API và trả về Json trong Flutter
📅 — 👀 1209 — 👦Đây là đoạn code đơn giản lấy dữ liệu từ api và trả về dạng json trong Flutter. Các bạn có thể tham khảo cách làm bên dưới.
Chú ý: Nếu bạn debug App trên trình duyệt Chrome hay Edge thì sẽ gặp lỗi XMLHttpRequest error (đây là cơ chế chặn CORS - Cross-origin resource sharing của trình duyệt). Chúng ta bỏ qua lỗi này như sau :
- Vào thư mục flutter\bin\cache và xóa file có tên flutter_tools.stamp
- Vào thư mục flutter\packages\flutter_tools\lib\src\web và mở file chrome.dart
- Tìm '--disable-extensions'
- Thêm '--disable-web-security'
Link lấy dữ liệu API :
https://thichcode.net/api/users.php
Dữ liệu trả về có dạng sau:
[
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere@april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
},
{
"id": 2,
"name": "Ervin Howell",
"username": "Antonette",
"email": "Shanna@melissa.tv",
"address": {
"street": "Victor Plains",
"suite": "Suite 879",
"city": "Wisokyburgh",
"zipcode": "90566-7771",
"geo": {
"lat": "-43.9509",
"lng": "-34.4618"
}
},
"phone": "010-692-6593 x09125",
"website": "anastasia.net",
"company": {
"name": "Deckow-Crist",
"catchPhrase": "Proactive didactic contingency",
"bs": "synergize scalable supply-chains"
}
},
{
"id": 3,
"name": "Clementine Bauch",
"username": "Samantha",
"email": "Nathan@yesenia.net",
"address": {
"street": "Douglas Extension",
"suite": "Suite 847",
"city": "McKenziehaven",
"zipcode": "59590-4157",
"geo": {
"lat": "-68.6102",
"lng": "-47.0653"
}
},
"phone": "1-463-123-4447",
"website": "ramiro.info",
"company": {
"name": "Romaguera-Jacobson",
"catchPhrase": "Face to face bifurcated interface",
"bs": "e-enable strategic applications"
}
},
{
"id": 4,
"name": "Patricia Lebsack",
"username": "Karianne",
"email": "Julianne.OConner@kory.org",
"address": {
"street": "Hoeger Mall",
"suite": "Apt. 692",
"city": "South Elvis",
"zipcode": "53919-4257",
"geo": {
"lat": "29.4572",
"lng": "-164.2990"
}
},
"phone": "493-170-9623 x156",
"website": "kale.biz",
"company": {
"name": "Robel-Corkery",
"catchPhrase": "Multi-tiered zero tolerance productivity",
"bs": "transition cutting-edge web services"
}
},
{
"id": 5,
"name": "Chelsey Dietrich",
"username": "Kamren",
"email": "Lucio_Hettinger@annie.ca",
"address": {
"street": "Skiles Walks",
"suite": "Suite 351",
"city": "Roscoeview",
"zipcode": "33263",
"geo": {
"lat": "-31.8129",
"lng": "62.5342"
}
},
"phone": "(254)954-1289",
"website": "demarco.info",
"company": {
"name": "Keebler LLC",
"catchPhrase": "User-centric fault-tolerant solution",
"bs": "revolutionize end-to-end systems"
}
},
{
"id": 6,
"name": "Mrs. Dennis Schulist",
"username": "Leopoldo_Corkery",
"email": "Karley_Dach@jasper.info",
"address": {
"street": "Norberto Crossing",
"suite": "Apt. 950",
"city": "South Christy",
"zipcode": "23505-1337",
"geo": {
"lat": "-71.4197",
"lng": "71.7478"
}
},
"phone": "1-477-935-8478 x6430",
"website": "ola.org",
"company": {
"name": "Considine-Lockman",
"catchPhrase": "Synchronised bottom-line interface",
"bs": "e-enable innovative applications"
}
},
{
"id": 7,
"name": "Kurtis Weissnat",
"username": "Elwyn.Skiles",
"email": "Telly.Hoeger@billy.biz",
"address": {
"street": "Rex Trail",
"suite": "Suite 280",
"city": "Howemouth",
"zipcode": "58804-1099",
"geo": {
"lat": "24.8918",
"lng": "21.8984"
}
},
"phone": "210.067.6132",
"website": "elvis.io",
"company": {
"name": "Johns Group",
"catchPhrase": "Configurable multimedia task-force",
"bs": "generate enterprise e-tailers"
}
},
{
"id": 8,
"name": "Nicholas Runolfsdottir V",
"username": "Maxime_Nienow",
"email": "Sherwood@rosamond.me",
"address": {
"street": "Ellsworth Summit",
"suite": "Suite 729",
"city": "Aliyaview",
"zipcode": "45169",
"geo": {
"lat": "-14.3990",
"lng": "-120.7677"
}
},
"phone": "586.493.6943 x140",
"website": "jacynthe.com",
"company": {
"name": "Abernathy Group",
"catchPhrase": "Implemented secondary concept",
"bs": "e-enable extensible e-tailers"
}
},
{
"id": 9,
"name": "Glenna Reichert",
"username": "Delphine",
"email": "Chaim_McDermott@dana.io",
"address": {
"street": "Dayna Park",
"suite": "Suite 449",
"city": "Bartholomebury",
"zipcode": "76495-3109",
"geo": {
"lat": "24.6463",
"lng": "-168.8889"
}
},
"phone": "(775)976-6794 x41206",
"website": "conrad.com",
"company": {
"name": "Yost and Sons",
"catchPhrase": "Switchable contextually-based project",
"bs": "aggregate real-time technologies"
}
},
{
"id": 10,
"name": "Clementina DuBuque",
"username": "Moriah.Stanton",
"email": "Rey.Padberg@karina.biz",
"address": {
"street": "Kattie Turnpike",
"suite": "Suite 198",
"city": "Lebsackbury",
"zipcode": "31428-2261",
"geo": {
"lat": "-38.2386",
"lng": "57.2232"
}
},
"phone": "024-648-3804",
"website": "ambrose.net",
"company": {
"name": "Hoeger LLC",
"catchPhrase": "Centralized empowering task-force",
"bs": "target end-to-end models"
}
}
]
Tạo file models.dart
import 'dart:convert';
import 'package:flutter/foundation.dart';
class CategoryProvider with ChangeNotifier {
UserInfo _selectedItem = UserInfo(
id: 0,
name: '',
username: '',
email: '',
address: Address(
street: 'street',
suite: 'suite',
city: 'city',
zipcode: 'zipcode',
geo: Geo(lat: 'lat', lng: 'lng')),
phone: '',
website: '',
company: Company(name: 'name', catchPhrase: 'catchPhrase', bs: 'bs'));
UserInfo get selected => _selectedItem;
void setSelectedItem(UserInfo s) {
_selectedItem = s;
notifyListeners();
}
}
List usersFromJson(String str) =>
List.from(json.decode(str).map((x) => UserInfo.fromJson(x)));
String usersToJson(List data) =>
json.encode(List.from(data.map((x) => x.toJson())));
class UserInfo {
int id;
String name;
String username;
String email;
Address address;
String phone;
String website;
Company company;
UserInfo({
required this.id,
required this.name,
required this.username,
required this.email,
required this.address,
required this.phone,
required this.website,
required this.company,
});
factory UserInfo.fromJson(Map json) => UserInfo(
id: json["id"],
name: json["name"],
username: json["username"],
email: json["email"],
address: Address.fromJson(json["address"]),
phone: json["phone"],
website: json["website"],
company: Company.fromJson(json["company"]),
);
Map toJson() => {
"id": id.toString(),
"name": name,
"username": username,
"email": email,
"address": address.toString(),
"phone": phone,
"website": website,
"company": company.toJson(),
};
}
class Company {
String name;
String catchPhrase;
String bs;
Company({
required this.name,
required this.catchPhrase,
required this.bs,
});
factory Company.fromJson(Map json) => Company(
name: json["name"],
catchPhrase: json["catchPhrase"],
bs: json["bs"],
);
Map toJson() => {
"name": name,
"catchPhrase": catchPhrase,
"bs": bs,
};
}
class Geo {
String lat;
String lng;
Geo({
required this.lat,
required this.lng,
});
factory Geo.fromJson(Map json) => Geo(
lat: json["lat"],
lng: json["lng"],
);
Map toJson() => {
"lat": lat,
"lng": lng,
};
}
class Address {
String street;
String suite;
String city;
String zipcode;
Geo geo;
Address({
required this.street,
required this.suite,
required this.city,
required this.zipcode,
required this.geo,
});
factory Address.fromJson(Map json) => Address(
street: json["street"],
suite: json["suite"],
city: json["city"],
zipcode: json["zipcode"],
geo: Geo.fromJson(json["geo"]),
);
Map toJson() => {
"street": street,
"suite": suite,
"city": city,
"zipcode": zipcode,
"geo": geo,
};
}
Tạo file main.dart
import 'package:flutter/material.dart';
import 'package:pretty_json/pretty_json.dart';
import 'package:provider/provider.dart';
import 'package:http/http.dart' as http;
import 'models.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '[ThichCode.NET] Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ChangeNotifierProvider(
create: (_) => CategoryProvider(),
builder: (context, snapshot) {
return const JsonApiDropdown();
}),
);
}
}
class JsonApiDropdown extends StatefulWidget {
const JsonApiDropdown({Key? key}) : super(key: key);
@override
JsonApiDropdownState createState() {
return JsonApiDropdownState();
}
}
class JsonApiDropdownState extends State {
Future? _listFuture;
Future _fetchUsers() async {
final jsonString =
await http.get(Uri.parse('https://thichcode.net/api/users.php'), headers: {
"Accept": "application/json",
"Access-Control_Allow_Origin": "*",
"Content-Type": "application/json",
});
if (jsonString.statusCode == 404) {
// ignore: avoid_print
print('Not connect');
return [];
} else {
final users = usersFromJson(jsonString.body);
if (users.isNotEmpty) {
context.read().setSelectedItem(users[0]);
}
return users;
}
}
@override
void initState() {
super.initState();
_listFuture = _fetchUsers();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Fetching data from JSON - ThichCode.NET'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
FutureBuilder(
future: _listFuture,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return const CircularProgressIndicator();
}
var arrItems = snapshot.data!
.map(
(u) => DropdownMenuItem(
child: Text(u.name),
value: u,
),
)
.toList();
return Consumer(builder: (context, provider, _) {
return DropdownButton(
items: arrItems,
onChanged: (UserInfo? _value) => {
context.read().setSelectedItem(_value!),
},
isExpanded: false,
value: Provider.of(context).selected,
hint: const Text('Select User'),
);
});
},
),
Padding(
padding: const EdgeInsets.all(30.0),
child: Text(
prettyJson(Provider.of(context).selected, indent: 5),
),
),
],
),
);
}
}
Chúc các bạn thành công !
📁 Flutter