Closed6
FlutterのREST APIクライアントを使ってみる
はじめに
Chopper, dio, json_serializable, freezedを使ってみる
Chopper
準備コマンド
dart create hello_chopper
cd hello_chopper
dart pub get chopper
dart pub get --dev build_runner chopper_generator
dart pub get
touch api.js
ソースコード
hello_chopper/bin/hello_chopper.dart
import 'package:chopper/chopper.dart';
part "hello_chopper.chopper.dart";
(baseUrl: "/todos")
abstract class TodosListService extends ChopperService {
  static TodosListService create([ChopperClient? client]) =>
      _$TodosListService(client);
  ()
  Future<Response> getTodos();
}
Future<void> main() async {
  final chopper = ChopperClient(
    baseUrl: "http://localhost:8000",
    services: [
      TodosListService.create(),
    ],
  );
  final todosService = chopper.getService<TodosListService>();
  final response = await todosService.getTodos();
  if (response.isSuccessful) {
    final body = response.body;
    print(body);
  } else {
    final code = response.statusCode;
    final error = response.error;
    print("code = $code, error = $error");
  }
}
api.js
const http = require('http');
const server = http.createServer();
server.on('request', (req, res) => {
  const content = JSON.stringify([
    {title: 'Todo 1', completed: true},
    {title: 'Todo 2', completed: false},
    {title: 'Todo 3', completed: false},
  ], null, 2);
  res.writeHead(200, {
    'Content-Type': 'application/json',
    'Content-Length': '' + content.length,
  });
  res.write(content);
  res.end();
})
const port = parseInt(process.env.PORT || '8000', 10);
server.listen(port, () => console.info(`Listening on ${port}`));
実行コマンド
dart pub run build_runner build
dart run
実行結果
[
  {
    "title": "Todo 1",
    "completed": true
  },
  {
    "title": "Todo 2",
    "completed": false
  },
  {
    "title": "Todo 3",
    "completed": false
  }
]
コメント
Chopperは公式ドキュメントが充実してなくて初心者にはつらい
dio
準備コマンド
dart create hello_dio
cd hello_dio
dart pub add dio
dart pub get
touch api.js
コード
hello_dio/bin/hello_dio.dart
import 'package:dio/dio.dart';
Future<void> main() async {
  try {
    final response = await Dio().get("http://localhost:8000/todos");
    print(response);
    print(response.data[0]["title"]);
  } catch (err) {
    print(err);
  }
}
api.js
const http = require('http');
const server = http.createServer();
server.on('request', (req, res) => {
  const content = JSON.stringify([
    {title: 'Todo 1', completed: true},
    {title: 'Todo 2', completed: false},
    {title: 'Todo 3', completed: false},
  ], null, 2);
  res.writeHead(200, {
    'Content-Type': 'application/json',
    'Content-Length': '' + content.length,
  });
  res.write(content);
  res.end();
})
const port = parseInt(process.env.PORT || '8000', 10);
server.listen(port, () => console.info(`Listening on ${port}`));
実行コマンド
dart run
実行結果
[{title: Todo 1, completed: true}, {title: Todo 2, completed: false}, {title: Todo 3, completed: false}]
Todo 1
コメント
dioはJavaScriptのfetch並みに使いやすい
でもJSONデコードなどはどうすれば良いのだろうか...
調べたところなんとJSONはデフォルトでMapにエンコードされる、すごい!
あとはjson_serializableやfreezedなどのパーサーを使えば良さそう
json_serializable
準備コマンド
dart create hello_json_serializable
cd hello_json_serializable
hello_json_serializable/pubspec.yaml
dependencies:
  json_annotation: ^4.7.0
dev_dependencies:
  build_runner: ^2.0.0
  json_serializable: ^6.0.0
コード
hello_json_serializable/bin/hello_json_serializable.dart
import 'dart:convert';
import 'package:json_annotation/json_annotation.dart';
part 'hello_json_serializable.g.dart';
()
class Person {
  final String firstName, lastName;
  final DateTime? dateOfBirth;
  Person({
    required this.firstName,
    required this.lastName,
    this.dateOfBirth,
  });
  factory Person.fromJson(Map<String, dynamic> json) {
    return _$PersonFromJson(json);
  }
  Map<String, dynamic> toJson() {
    return _$PersonToJson(this);
  }
}
void main() {
  final person = Person(
    firstName: "Tatsuya",
    lastName: "Susukida",
    dateOfBirth: DateTime(1987, 8, 27),
  );
  final encoded = jsonEncode(person.toJson());
  print(encoded);
  final decoded = Person.fromJson(jsonDecode(encoded));
  print(decoded.firstName);
  print(decoded.lastName);
  print(decoded.dateOfBirth);
}
実行コマンド
dart run build_runner build
dart run
実行結果
{"firstName":"Tatsuya","lastName":"Susukida","dateOfBirth":"1987-08-27T00:00:00.000"}
Tatsuya
Susukida
1987-08-27 00:00:00.000
メモ
Flutter公式ドキュメントにJSONエンコード/デコードに関するページがある
freezed
準備コマンド
dart create hello_freezed
cd hello_freezed
dart pub add freeze_annotation json_annotation
dart pub add --dev build_runner freezed json_serializable
コード
import 'dart:convert';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'hello_freezed.freezed.dart';
part 'hello_freezed.g.dart';
@freezed
class Person with _$Person {
  const factory Person({
    required String firstName,
    required String lastName,
    required int age,
  }) = _Person;
  factory Person.fromJson(Map<String, Object?> json) => _$PersonFromJson(json);
}
void main() {
  final person = Person(
    firstName: 'Tatsuya',
    lastName: 'lastName',
    age: 35,
  );
  final copied = person.copyWith();
  final encoded = jsonEncode(person.toJson());
  final decoded = Person.fromJson(jsonDecode(encoded));
  print(person);
  print(person == copied);
  print(encoded);
  print(decoded);
}
実行コマンド
dart run build_runner build
dart run
実行結果
Person(firstName: Tatsuya, lastName: lastName, age: 35)
true
{"firstName":"Tatsuya","lastName":"lastName","age":35}
Person(firstName: Tatsuya, lastName: lastName, age: 35)
メモ
公式ドキュメントの内容が充実していて素晴らしい
fromJsonには=>を使用する必要がある
Freezed will only generate a fromJson if the factory is using =>.
おわりに
以上で一旦クローズ、次はデータ管理パッケージを使ってみる
このスクラップは2023/01/10にクローズされました