# 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. 查看資料格式,選取需要欄位 ![](https://i.imgur.com/h6ABr9c.png) 3. 依據平台給予請求網址進行請求 ![](https://i.imgur.com/UiCIHFb.png) ```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"] ), ), ); }) ); } ``` ![](https://i.imgur.com/tWnKS2H.png) ### 自己建立API 透過[openAPI(原Swagger)](https://app.swaggerhub.com/home),可依下述步驟建造API: 1. 加入會員 2. Create New API ![](https://i.imgur.com/im0NXae.png) 3. 依照需求命名、選擇模板 4. 照[官方教學文件](https://swagger.io/docs/specification/adding-examples/)進行撰寫(紅框),就可以生成UI介面 ![](https://i.imgur.com/Jx6qC7G.png) 下列為稍等使用範例: 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也可以進行測試 ![](https://i.imgur.com/zzvI3u1.png) ## 程式範例 ### 發送請求 需使用異步 ```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)}' ), ), ); }) ); } } ``` ![](https://i.imgur.com/407DPry.png) ## 常用工具 1. [json 轉 yaml](https://codebeautify.org/json-to-yaml) 2. [openAPI(原Swagger)](https://app.swaggerhub.com/home) ###### tags: `flutter`