DEV Community

codebangkok
codebangkok

Posted on

5 3

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

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

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay