DEV Community

codebangkok
codebangkok

Posted on

Flutter & Dart: Call RESTful API and Authen with JWT

Agenda

  • Call REST API with GET Method
  • Call REST API with POST Method
  • JSON Serialization (jsonEncode)
  • JSON Deserializaton (jsonDecode)
  • Call Authorized REST API with JWT

Prerequisite

1. สร้างโปรเจ็ค แล้ว migrate ให้ dart ซัพพอร์ท null safety

dart create rest_api
cd rest_api
dart migrate --apply-changes
Enter fullscreen mode Exit fullscreen mode

2. ติดตั้ง http package

dart pub add http
Enter fullscreen mode Exit fullscreen mode

เข้าไปดูได้ที่ https://pub.dev/packages/http
Alt Text

3. เตรียม API

ผมทำเอาไว้เพื่อทดสอบแล้วที่ https://techcoach.azurewebsites.net
Alt Text

4. ตัวอย่างที่ 1 การเรียก API แบบ GET กับการดึงค่า Gender

URL: https://techcoach.azurewebsites.net/registration/genders
Alt Text

4.1 import http,io,convert package แล้วสร้างฟังชั่น getGender แบบ async
import 'package:http/http.dart' as http;
import 'dart:io';
import 'dart:convert';

void main(List<String> arguments) {

}

Future getGenders() async {

}
Enter fullscreen mode Exit fullscreen mode
4.2 เขียนโปรแกรมที่ฟังชั่น getGenders เรียกฟังชั่น http.get แล้วส่ง URL เข้าไปดังนี้
final response = await http.get(
  Uri.parse('https://techcoach.azurewebsites.net/registration/genders'),
);
Enter fullscreen mode Exit fullscreen mode
4.2 ตรวจสอบว่าถ้าสถานะไม่ใช่ ok (200) ก็จะหยุดการทำงาน
if (response.statusCode != HttpStatus.ok) {
  print('Response: ${response.statusCode}');
  return;
}
Enter fullscreen mode Exit fullscreen mode
4.3 พิมพ์ผลที่ได้ออกมาดูก่อน
print(response.body);
Enter fullscreen mode Exit fullscreen mode
4.3 เปลี่ยนที่ฟังชั่น main เป็นแบบ async แล้วเรียกฟังชั่น getGenders
void main(List<String> arguments) async {
  await getGenders();
}
Enter fullscreen mode Exit fullscreen mode

ผลลัพธ์ที่ได้หลังจากการรันคำสั่ง

dart run
[{"id":1,"name":"ชาย"},{"id":2,"name":"หญิง"}]
Enter fullscreen mode Exit fullscreen mode

Alt Text

4.4 สร้างคลาส Gender โดยมี id กับ name เป็น arribute พร้อมกับสร้าง constructor เพื่อรับค่าด้วย
class Gender {
  final int id;
  final String name;
  Gender({
    required this.id,
    required this.name,
  });
}
Enter fullscreen mode Exit fullscreen mode
4.4 เพิ่ม factory constructor ให้กับ Gender เพื่อความสะดวกในการแปลงจาก Map เป็น Object
class Gender {
  final int id;
  final String name;
  Gender({
    required this.id,
    required this.name,
  });

  factory Gender.fromJson(Map<String, dynamic> json) => Gender(
        id: json['id'],
        name: json['name'],
      );
}
Enter fullscreen mode Exit fullscreen mode
4.5 แก้ไขฟังชั่น getGenders ลบบรรทัด print ออกแล้วเพิ่มคำสั่ง jsonDecode เพื่อแปลงจาก JSON String ให้เป็น List ของ Map
final json = jsonDecode(response.body) as List;
Enter fullscreen mode Exit fullscreen mode
4.6 ใช้ map เพื่อแปลงจาก Map ให้กลายเป็น List ของ Gender
final genders = json.map((e) => Gender.fromJson(e)).toList();
Enter fullscreen mode Exit fullscreen mode
4.6 แสดงผลที่ได้จาก List ของ Gender
for (var gender in genders) {
  print('id: ${gender.id}, name: ${gender.name}');
}
Enter fullscreen mode Exit fullscreen mode

ผลลัพธ์ที่ได้หลังจากการรันคำสั่ง

dart run
id: 1, name: ชาย
id: 2, name: หญิง
Enter fullscreen mode Exit fullscreen mode

Alt Text
โค้ดทั้งหมด

import 'package:http/http.dart' as http;
import 'dart:io';
import 'dart:convert';

void main(List<String> arguments) async {
  await getGenders();
}

Future getGenders() async {
  final response = await http.get(
    Uri.parse('https://techcoach.azurewebsites.net/registration/genders'),
  );

  if (response.statusCode != HttpStatus.ok) {
    print('Response: ${response.statusCode}');
    return;
  }

  final json = jsonDecode(response.body) as List;
  final genders = json.map((e) => Gender.fromJson(e)).toList();
  for (final gender in genders) {
    print('id: ${gender.id}, name: ${gender.name}');
  }
}

class Gender {
  int id;
  String name;
  Gender({
    required this.id,
    required this.name,
  });

  factory Gender.fromJson(Map<String, dynamic> json) => Gender(
        id: json['id'],
        name: json['name'],
      );
}
Enter fullscreen mode Exit fullscreen mode

5. ตัวอย่างที่ 2 การเรียก API แบบ POST กับการลงทะเบียน User โดยจะต้องส่ง payload ในรูปแบบ JSON ที่ body ด้วย

URL: https://techcoach.azurewebsites.net/registration/users
Alt Text

5.1 สร้างฟังชั่น signup แบบ async รับพารามิเตอร์ที่ต้องการ แล้วเรียกฟังชั่น http.post แล้วส่ง URL เข้าไปดังนี้
Future signup({
  required final String firstName,
  required final String lastName,
  required final String email,
  required final String password,
  required final int genderId,
}) async {
  final response = await http.post(
    Uri.parse('https://techcoach.azurewebsites.net/registration/users'),
  );
}
Enter fullscreen mode Exit fullscreen mode
5.2 เพิ่ม content-type: application/json เข้าไปที่ headers
final response = await http.post(
  Uri.parse('https://techcoach.azurewebsites.net/registration/users'),
  headers: {'content-type': 'application/json'},
);
Enter fullscreen mode Exit fullscreen mode
5.3 ที่ body สร้าง Map ของคีย์ต่างๆที่ payload ต้องการ แล้วใช้ jsonEncode เพื่อแปลงจาก Map ให้เป็น JSON String
final response = await http.post(
  Uri.parse('https://techcoach.azurewebsites.net/registration/users'),
  headers: {'content-type': 'application/json'},
  body: jsonEncode({
    'firstName': firstName,
    'lastName': lastName,
    'email': email,
    'password': password,
    'genderId': genderId,
  }),
);
Enter fullscreen mode Exit fullscreen mode
5.4 ตรวจสอบว่าถ้าสถานะ ok (200) แสดงผลคำว่า signup success
if (response.statusCode != HttpStatus.ok) {
  print('Response: ${response.statusCode}');
  return;
}

print('signup success');
Enter fullscreen mode Exit fullscreen mode
5.5 ที่ฟังชั่น main ให้เรียกฟังชั่น signup ตัวอย่างดังนี้
void main(List<String> arguments) async {
  await signup(
    firstName: 'Code',
    lastName: 'Bangkok',
    email: 'codebangkok@gmail.com',
    password: 'iloveyou',
    genderId: 1,
  );
}
Enter fullscreen mode Exit fullscreen mode

ผลลัพธ์ที่ได้หลังจากการรันคำสั่ง

dart run
signup success
Enter fullscreen mode Exit fullscreen mode

Alt Text

โค้ดที่เกี่ยวข้องทั้งหมด

import 'package:http/http.dart' as http;
import 'dart:io';
import 'dart:convert';

void main(List<String> arguments) async {
  await signup(
    firstName: 'Code',
    lastName: 'Bangkok',
    email: 'codebangkok@gmail.com',
    password: 'iloveyou',
    genderId: 1,
  );
}

Future signup({
  required final String firstName,
  required final String lastName,
  required final String email,
  required final String password,
  required final int genderId,
}) async {
  final response = await http.post(
    Uri.parse('https://techcoach.azurewebsites.net/registration/users'),
    headers: {'content-type': 'application/json'},
    body: jsonEncode({
      'firstName': firstName,
      'lastName': lastName,
      'email': email,
      'password': password,
      'genderId': genderId,
    }),
  );

  if (response.statusCode != HttpStatus.ok) {
    print('Response: ${response.statusCode}');
    return;
  }

  print('signup success');
}
Enter fullscreen mode Exit fullscreen mode

6. ตัวอย่างที่ 3 การเรียก API แบบ POST กับการ Login โดยจะต้องส่ง payload ในรูปแบบ JSON ที่ body และรับค่า response กลับมาด้วย

URL: https://techcoach.azurewebsites.net/registration/login
Alt Text

6.1 สร้างฟังชั่น login แบบ async รับพารามิเตอร์ที่ต้องการ แล้วเรียกฟังชั่น http.post แล้วส่ง URL เข้าไปดังนี้
Future login({
  required final String email,
  required final String password,
}) async {
  final response = await http.post(
    Uri.parse('https://techcoach.azurewebsites.net/registration/login'),
  );
}
Enter fullscreen mode Exit fullscreen mode
6.2 เพิ่ม content-type: application/json เข้าไปที่ headers
final response = await http.post(
  Uri.parse('https://techcoach.azurewebsites.net/registration/login'),
  headers: {'content-type': 'application/json'},
);
Enter fullscreen mode Exit fullscreen mode
6.3 ที่ body สร้าง Map ของคีย์ต่างๆที่ payload ต้องการ แล้วใช้ jsonEncode เพื่อแปลงจาก Map ให้เป็น JSON String
final response = await http.post(
  Uri.parse('https://techcoach.azurewebsites.net/registration/login'),
  headers: {'content-type': 'application/json'},
  body: jsonEncode({
    'email': email,
    'password': password,
  }),
);
Enter fullscreen mode Exit fullscreen mode
6.4 ตรวจสอบว่าถ้าสถานะไม่ใช่ ok (200) ก็จะหยุดการทำงาน
if (response.statusCode != HttpStatus.ok) {
  print('Response: ${response.statusCode}');
  return;
}
Enter fullscreen mode Exit fullscreen mode
6.5 สร้างคลาส User โดยมี arribute ต่างๆตาม response พร้อมกับสร้าง constructor เพื่อรับค่าด้วย
class User {
  final int id;
  final String firstName;
  final String lastName;
  final String email;
  final Gender gender;
  final String jwtToken;
  User({
    required this.id,
    required this.firstName,
    required this.lastName,
    required this.email,
    required this.gender,
    required this.jwtToken,
  });
}
Enter fullscreen mode Exit fullscreen mode
6.6 เพิ่ม factory constructor ให้กับ User เพื่อความสะดวกในการแปลงจาก Map เป็น Object
class User {
  final int id;
  final String firstName;
  final String lastName;
  final String email;
  final Gender gender;
  final String jwtToken;
  User({
    required this.id,
    required this.firstName,
    required this.lastName,
    required this.email,
    required this.gender,
    required this.jwtToken,
  });

  factory User.fromJson(Map<String, dynamic> json) => User(
        id: json['id'],
        firstName: json['firstName'],
        lastName: json['lastName'],
        email: json['email'],
        gender: Gender.fromJson(json['gender']),
        jwtToken: json['jwtToken'],
      );
}
Enter fullscreen mode Exit fullscreen mode
6.7 แก้ไขฟังชั่น login เพิ่มคำสั่ง jsonDecode เพื่อแปลงจาก JSON String ไปเป็น Map
final json = jsonDecode(response.body);
Enter fullscreen mode Exit fullscreen mode
6.8 แปลงจาก Map ให้กลายเป็น User object ด้วย fromJson
final user = User.fromJson(json);
Enter fullscreen mode Exit fullscreen mode
6.9 แสดงผลที่ได้จาก User object
print('First Name: ${user.firstName}');
print('Last Name: ${user.lastName}');
print('Email: ${user.email}');
print('Gender: ${user.gender.name}');
print('JWT Token: ${user.jwtToken}');
Enter fullscreen mode Exit fullscreen mode
6.10 ที่ฟังชั่น main ให้เรียกฟังชั่น login ตัวอย่างดังนี้
void main(List<String> arguments) async {
  await login(
    email: 'codebangkok@gmail.com',
    password: 'iloveyou',
  );
}
Enter fullscreen mode Exit fullscreen mode

ผลลัพธ์ที่ได้หลังจากการรันคำสั่ง (jwt token จะเปลี่ยนทุกครั้งที่รัน)

dart run
First Name: Code
Last Name: Bangkok
Email: codebangkok@gmail.com
Gender: ชาย
JWT Token: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJJZCI6IjYiLCJzdWIiOiJjb2RlYmFuZ2tva0BnbWFpbC5jb20iLCJlbWFpbCI6ImNvZGViYW5na29rQGdtYWlsLmNvbSIsIm5iZiI6MTYxOTY5MDkwMSwiZXhwIjoxNjE5NzEyNTAxLCJpYXQiOjE2MTk2OTA5MDF9.BBQ6RDSIZodGdn19Af5HrZLHSyGOJJReXAsSXfN2LG1dc4kTK6SlLc6U7e65-9iSBqiM4MA97EMvJvRUYKbUwQ
Enter fullscreen mode Exit fullscreen mode

Alt Text

โค้ดที่เกี่ยวข้องทั้งหมด

import 'package:http/http.dart' as http;
import 'dart:io';
import 'dart:convert';

void main(List<String> arguments) async {
  await login(
    email: 'codebangkok@gmail.com',
    password: 'iloveyou',
  );
}

Future login({
  required final String email,
  required final String password,
}) async {
  final response = await http.post(
    Uri.parse('https://techcoach.azurewebsites.net/registration/login'),
    headers: {'content-type': 'application/json'},
    body: jsonEncode({
      'email': email,
      'password': password,
    }),
  );

  if (response.statusCode != HttpStatus.ok) {
    print('Response: ${response.statusCode}');
    return;
  }

  final json = jsonDecode(response.body);
  final user = User.fromJson(json);
  print('First Name: ${user.firstName}');
  print('Last Name: ${user.lastName}');
  print('Email: ${user.email}');
  print('Gender: ${user.gender.name}');
  print('JWT Token: ${user.jwtToken}');
}

class User {
  final int id;
  final String firstName;
  final String lastName;
  final String email;
  final Gender gender;
  final String jwtToken;
  User({
    required this.id,
    required this.firstName,
    required this.lastName,
    required this.email,
    required this.gender,
    required this.jwtToken,
  });

  factory User.fromJson(Map<String, dynamic> json) => User(
        id: json['id'],
        firstName: json['firstName'],
        lastName: json['lastName'],
        email: json['email'],
        gender: Gender.fromJson(json['gender']),
        jwtToken: json['jwtToken'],
      );
}
Enter fullscreen mode Exit fullscreen mode

7. ตัวอย่างที่ 4 การเรียก Authorized API แบบ GET ด้วยการใช้ JWT Token

URL: https://techcoach.azurewebsites.net/registration/users
Alt Text

7.1 สร้างฟังชั่น getUsers แบบ async รับ jwt token เข้ามา แล้วเรียกฟังชั่น http.get แล้วส่ง URL เข้าไปดังนี้
Future getUsers({required String jwtToken}) async {
  final response = await http.get(
    Uri.parse('https://techcoach.azurewebsites.net/registration/users'),
  );
}

Enter fullscreen mode Exit fullscreen mode
7.2 เพิ่ม Authorization: Bearer เข้าไปที่ headers นำค่า jwt token ที่ได้จากการ login มาใส่
final response = await http.get(
  Uri.parse('https://techcoach.azurewebsites.net/registration/users'),
  headers: {'authorization': 'Bearer $jwtToken'},
);
Enter fullscreen mode Exit fullscreen mode
7.3 ตรวจสอบว่าถ้าสถานะ ok (200) ก็พิมพ์ผลลัพธ์ที่ได้ออกมาดู
if (response.statusCode != HttpStatus.ok) {
  print('Response: ${response.statusCode}');
  return;
}

print(response.body);
Enter fullscreen mode Exit fullscreen mode
7.4 ที่ฟังชั่น main ให้เรียกฟังชั่น getUsers ตัวอย่างดังนี้
void main(List<String> arguments) async {
  final jwtToken = ''; //นำค่า jwt ที่ได้จากการ login มาใส่ที่นี่
  await getUsers(jwtToken: jwtToken);
}
Enter fullscreen mode Exit fullscreen mode

ผลลัพธ์ที่ได้หลังจากการรันคำสั่ง

dart run
[{"id":1,"firstName":"Code","lastName":"Bangkok","email":"codebangkok@gmail.com","gender":{"id":1,"name":"ชาย"}}]
Enter fullscreen mode Exit fullscreen mode

Alt Text

โค้ดทั้งหมด

import 'package:http/http.dart' as http;
import 'dart:io';
import 'dart:convert';

void main(List<String> arguments) async {
  final jwtToken = ''; //นำค่า jwt ที่ได้จากการ login มาใส่ที่นี่
  await getUsers(jwtToken: jwtToken);
}

Future getUsers({required String jwtToken}) async {
  final response = await http.get(
    Uri.parse('https://techcoach.azurewebsites.net/registration/users'),
    headers: {'authorization': 'Bearer $jwtToken'},
  );

  if (response.statusCode != HttpStatus.ok) {
    print('Response: ${response.statusCode}');
    return;
  }

  print(response.body);
}

Future login({
  required final String email,
  required final String password,
}) async {
  final response = await http.post(
    Uri.parse('https://techcoach.azurewebsites.net/registration/login'),
    headers: {'content-type': 'application/json'},
    body: jsonEncode({
      'email': email,
      'password': password,
    }),
  );

  if (response.statusCode != HttpStatus.ok) {
    print('Response: ${response.statusCode}');
    return;
  }

  final json = jsonDecode(response.body);
  final user = User.fromJson(json);
  print('First Name: ${user.firstName}');
  print('Last Name: ${user.lastName}');
  print('Email: ${user.email}');
  print('Gender: ${user.gender.name}');
  print('JWT Token: ${user.jwtToken}');
}

Future signup({
  required final String firstName,
  required final String lastName,
  required final String email,
  required final String password,
  required final int genderId,
}) async {
  final response = await http.post(
    Uri.parse('https://techcoach.azurewebsites.net/registration/users'),
    headers: {'content-type': 'application/json'},
    body: jsonEncode({
      'firstName': firstName,
      'lastName': lastName,
      'email': email,
      'password': password,
      'genderId': genderId,
    }),
  );

  if (response.statusCode != HttpStatus.ok) {
    print('Response: ${response.statusCode}');
    return;
  }

  print('signup success');
}

Future getGenders() async {
  final response = await http.get(
    Uri.parse('https://techcoach.azurewebsites.net/registration/genders'),
  );

  if (response.statusCode != HttpStatus.ok) {
    print('Response: ${response.statusCode}');
    return;
  }

  final json = jsonDecode(response.body) as List;
  final genders = json.map((e) => Gender.fromJson(e)).toList();
  for (final gender in genders) {
    print('id: ${gender.id}, name: ${gender.name}');
  }
}

class Gender {
  final int id;
  final String name;
  Gender({
    required this.id,
    required this.name,
  });

  factory Gender.fromJson(Map<String, dynamic> json) => Gender(
        id: json['id'],
        name: json['name'],
      );
}

class User {
  final int id;
  final String firstName;
  final String lastName;
  final String email;
  final Gender gender;
  final String jwtToken;
  User({
    required this.id,
    required this.firstName,
    required this.lastName,
    required this.email,
    required this.gender,
    required this.jwtToken,
  });

  factory User.fromJson(Map<String, dynamic> json) => User(
        id: json['id'],
        firstName: json['firstName'],
        lastName: json['lastName'],
        email: json['email'],
        gender: Gender.fromJson(json['gender']),
        jwtToken: json['jwtToken'],
      );
}
Enter fullscreen mode Exit fullscreen mode

ติดตามผลงานได้ที่

Discussion (0)