# Flutter API 相關介紹
## 相關套件
* [好用package - http 介紹](https://hackmd.io/@BzWzq-x9Rb2G4WG03gcyKg/SJSr27_9q)
* [好用package - json_annotation/json_serializable/build_runner 介紹](https://hackmd.io/@BzWzq-x9Rb2G4WG03gcyKg/ByPIRXd95)
## 建立API
### 透過網路上現成API(基本上就是自己看官方文件)
* [英文食譜](https://www.edamam.com/)
* [政府資料開放平台](https://data.gov.tw/)
#### 簡單範例
資料來源: [國際重要疫情資訊](https://data.gov.tw/dataset/10568)
1. 安裝 http 套件
```
flutter pub add http
```
2. 查看資料格式,選取需要欄位

3. 依據平台給予請求網址進行請求

```dart
const String apiUrl = 'https://www.cdc.gov.tw/TravelEpidemic/ExportJSON';
Future getData(String url) async {
debugPrint('Calling url: $url');
Map<String, String> headers = {"Content-type": "application/json"};
final response = await get(Uri.parse(url), headers: headers);
if (response.statusCode == 200) {
//資料含中文
return utf8.decode(response.bodyBytes);
} else {
debugPrint('Request failed with status: ${response.statusCode}.');
}
}
class TravelEpidemicService {
Future<dynamic> getTestData() async {
final testData = await getData(apiUrl);
return testData;
}
}
```
4. 將收到的資料轉成json
```dart
//將收到的請求轉成json
Future<List<dynamic>> getTestData() async {
final recipeJson = await TravelEpidemicService().getTestData();
final recipeMap = json.decode(recipeJson);
return recipeMap;
}
```
5. 將資料顯示在頁面
```dart
Widget _buildList(List<dynamic> travelEpidemics) {
return Flexible(
child:ListView.builder(
itemCount: travelEpidemics.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: ListTile(
title: Text(travelEpidemics[index]["headline"]),
subtitle: Text(
travelEpidemics[index]["description"]
),
),
);
})
);
}
```

### 自己建立API
透過[openAPI(原Swagger)](https://app.swaggerhub.com/home),可依下述步驟建造API:
1. 加入會員
2. Create New API

3. 依照需求命名、選擇模板
4. 照[官方教學文件](https://swagger.io/docs/specification/adding-examples/)進行撰寫(紅框),就可以生成UI介面

下列為稍等使用範例:
Response body:
```json
{
"users": [
{
"name": "Jessica Smith",
"age": 9,
"height": 139
},
{
"name": "Ron Stewart",
"age": 19,
"height": 159
},
{
"name": "Yen",
"age": 26
}
]
}
```
紅框處(path以後進行取代):
```yaml
paths:
/profile:
get:
tags:
- test
summary: searches inventory
operationId: getUserInfo
description: |
By passing in the appropriate options, you can search user info
responses:
'200':
description: search results matching criteria
content:
application/json:
schema:
properties:
users:
$ref: '#/components/schemas/ArrayOfUsers'
'400':
description: bad input parameter
components:
schemas:
ArrayOfUsers:
required:
- name
properties:
name:
type: string
age:
type: integer
height:
type: integer
example:
- name: Jessica Smith
age: 9
height: 139
- name: Ron Stewart
age: 19
height: 159
- name: Yen
age: 26
```
5. 操作UI也可以進行測試

## 程式範例
### 發送請求
需使用異步
```dart
Widget _buildLoader(BuildContext context) {
return FutureBuilder<Users>(
//請求api,有資料回應response.body
future: getTestData(),
//收到response進行處理
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString(),
textAlign: TextAlign.center, textScaleFactor: 1.3),
);
}
final query = snapshot.data;
//建立收到資料後希望顯示的樣式
return _buildList(query!.users);
} else {
return const Center(child: CircularProgressIndicator());
}
},
);
}
```
### 請求api,有資料回應response.body
需使用異步
network/test_service.dart
```dart
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart';
const String apiUrl = '你的請求網址';
Future getData(String url) async {
//使用get從apiUrl取得response.body
final response = await get(Uri.parse(url));
if (response.statusCode == 200) {
return response.body;
} else {
debugPrint('Request failed with status: ${response.statusCode}.');
}
}
class TestService {
Future<dynamic> getTestData() async {
final testData = await getData(apiUrl);
return testData;
}
}
```
### 將收到的收到response.body轉成json
需使用異步,詳細方式可以看[好用package - json_annotation/json_serializable/build_runner 介紹](https://hackmd.io/@BzWzq-x9Rb2G4WG03gcyKg/ByPIRXd95)
```dart
//將收到的請求轉成json
Future<Users> getTestData() async {
final recipeJson = await TestService().getTestData();
final recipeMap = json.decode(recipeJson);
return Users.fromJson(recipeMap);
}
```
### 完整程式碼
network/test_service.dart
```dart
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart';
const String apiUrl = '你的請求網址';
Future getData(String url) async {
//使用get從apiUrl取得response.body
final response = await get(Uri.parse(url));
if (response.statusCode == 200) {
return response.body;
} else {
debugPrint('Request failed with status: ${response.statusCode}.');
}
}
class TestService {
Future<dynamic> getTestData() async {
final testData = await getData(apiUrl);
return testData;
}
}
```
test_list.dart
```dart
class TestList extends StatefulWidget {
const TestList({Key? key}) : super(key: key);
@override
_TestListState createState() => _TestListState();
}
class _TestListState extends State<TestList> {
@override
void initState() {
super.initState();
}
//將收到的請求轉成json
Future<Users> getTestData() async {
final recipeJson = await TestService().getTestData();
final recipeMap = json.decode(recipeJson);
return Users.fromJson(recipeMap);
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
_buildLoader(context),
],
),
),
);
}
Widget _buildLoader(BuildContext context) {
return FutureBuilder<Users>(
future: getTestData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString(),
textAlign: TextAlign.center, textScaleFactor: 1.3),
);
}
final query = snapshot.data;
return _buildList(query!.users);
} else {
return const Center(child: CircularProgressIndicator());
}
},
);
}
Widget _buildList(List<User> users) {
return Flexible(
child:ListView.builder(
itemCount: users.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: ListTile(
leading: const Icon(Icons.face),
title: Text(users[index].name),
subtitle: Text(
'年齡: ${getAge(users[index].age)} 身高: ${getHeight(users[index].height)}'
),
),
);
})
);
}
}
```

## 常用工具
1. [json 轉 yaml](https://codebeautify.org/json-to-yaml)
2. [openAPI(原Swagger)](https://app.swaggerhub.com/home)
###### tags: `flutter`