iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 18
0
Mobile Development

用 Flutter 開發一個 Android App 吧系列 第 20

用 Flutter 開發一個 Android App 吧 - Day 20. 自己建造 GitHub Trending API 輪子與測試

  • 分享至 

  • xImage
  •  

本系列同步發表在 個人部落格,歡迎大家關注~

GitHub Trending API

唷西(よし),昨天花了很大的力氣將 JSON 序列化的物件模板建立完成了。

那麼下一步就是要整合 API 拉~

  1. lib/services/ 底下新增 github_trending_api.dart
  2. github_trending_api.dart 內會實現 class GitHubTrendingApiClient,其目的方便頁面直接創建 client 物件並透過方法調用 API。

接下來,先了解程式碼架構。

lib/services/github_trending_api.dart

import 'dart:convert';

import 'package:gitme_reborn/services/models/developer.dart';
import 'package:http/http.dart' as http;
import 'package:gitme_reborn/services/models/project.dart';

class GitHubTrendingApiError extends Error {
  final String message;

  GitHubTrendingApiError(this.message);

  @override
  String toString() {
    return "GitHubTrendingApiError(message: $message)";
  }
}

class GitHubTrendingApiClient {
  http.Client _client;
  String baseDomain = "github-trending-api.now.sh";

  GitHubTrendingApiClient({client}) {
    this._client = client != null ? client : http.Client();
  }
  
  Uri get baseUrl => Uri.https(baseDomain, "");

  Future<List<Project>> listProjects(...) async {...}

  Future<List<Developer>> listDevelopers(...) async {...}
}

從上可以觀察到

  1. GitHubTrendingApiError 用來 handle 調用 API 時發生錯誤。
  2. GitHubTrendingApiClient 包含以下這些部份
    • 屬性: _clientbaseDomain
    • 建構子: GitHubTrendingApiClient({client})
    • Getter/Setter: baseUrl
    • 方法: listProjects(...)listDevelopers(...)

小提醒:

  • 類別或物件中的變數通常稱作「屬性」(property),而函數通常稱作「方法」(method)
  • _clienthttp.Client 類別,可以直接用 get(...) 來傳送 GET 請求; post(...) 傳送 POST 請求。
  • http 是 Dart 語言中傳送 HTTP(s) 請求的核心函數庫,很多功能它都包好了,非常簡單易用。

實際調用 API 的方法

前一節,listProjects(...)listDevelopers(...) 這兩個方法被我省略了。

這一節仔細展開實做吧!

  Future<List<Project>> listProjects({String language, String since}) async {
    var requestUrl = Uri.https(baseDomain, "/repositories", {
      if (language != null) "language": language,
      if (since != null) "since": since,
    });
    final resp = await _client.get(requestUrl);

    if (resp.statusCode != 200) {
      throw GitHubTrendingApiError(resp.body);
    }

    return jsonDecode(resp.body)
        .map<Project>((project) => Project.fromJson(project))
        .toList();
  }

  Future<List<Developer>> listDevelopers({String language, String since}) async {
    var requestUrl = Uri.https(baseDomain, "/developers", {
      if (language != null) "language": language,
      if (since != null) "since": since,
    });
    final resp = await _client.get(requestUrl);

    if (resp.statusCode != 200) {
      throw GitHubTrendingApiError(resp.body);
    }

    return jsonDecode(resp.body)
        .map<Developer>((developer) => Developer.fromJson(developer))
        .toList();
  }

其實這兩個方法大同小異,分成五部份:

  1. 設定能傳入方法的參數 {String language, String since}: 搭配 API Request 得 GET 參數。
  2. 建立 requestUrl: 用 Uri.https 這 Factory Constructor,帶入對應的參數 authorityunencodedPathqueryParameters
  3. _client 送 GET Request 到 requestUrl
  4. GitHubTrendingApiError 處理 Response 狀態碼不是 200 的情況。
  5. 成功得到回應後先用 jsonDecode 轉換 resp.bodyList<Map> ,最後再由 .fromJson() 轉換成 List<Project>List<Developer>

測試看看

既然是自己寫的輪子,就需要簡單測試一下,看能不能成功獲取到資料。

test/services/github_trending_api_test.dart

import 'package:flutter_test/flutter_test.dart';
import 'package:gitme_reborn/services/github_trending_api.dart';
import 'package:gitme_reborn/services/models/project.dart';
import 'package:gitme_reborn/services/models/developer.dart';

main() {
  group('Test GitHub trending APIs', () {
    test('Test method listProjects successfully', () async {
      final api = GitHubTrendingApiClient();

      expect(await api.listProjects(), isInstanceOf<List<Project>>());
    });

    test('Test method listDevelopers successfully', () async {
      final api = GitHubTrendingApiClient();

      expect(await api.listDevelopers(), isInstanceOf<List<Developer>>());
    });
  });
}

先建立一個非常簡易的測試,我主要是要測試 listProjectslistDevelopers 這兩個方法能不能 Work 而已。

接著在 VSCode 裡,在測試 function 上會出現 Run|Debug

day20-1.png

點擊 Run 就可以輕鬆跑測試囉~

day20-2.gif

看到綠色就代表測試通過~~ !!!

今天就先到這,明天能安心地使用自己建造的輪子拉~


上一篇
用 Flutter 開發一個 Android App 吧 - Day 19. JSON 序列化 及 如何應用在 App 中
下一篇
用 Flutter 開發一個 Android App 吧 - Day 21. 趨勢頁面(改)、切換趨勢區間
系列文
用 Flutter 開發一個 Android App 吧30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言