[Flutter] API 불러오고 사용하기

leteu

·

2022. 1. 25. 09:32

Flutter는 화면을 위젯(Widget)으로 만든다.

포스팅 순서를 위젯을 먼저하고 API 사용을 올리려고 준비 중이었지만

Flutter 위젯 종류가 너무 많아서 포기했다.

그냥 API 호출하고 바로 뿌려보려고 한다.

다음에 flutter 많이 써보고 많이 쓰는 거 위주로 올려보려고 한다.


 

#1 들어가기 앞서...

 

API는 아래 주소로 접속하면 기본적인 예제를 볼 수 있다.

이 사이트에서 제공하는 API를 사용할 것이다.

https://jsonplaceholder.typicode.com/

 

JSONPlaceholder - Free Fake REST API

{JSON} Placeholder Free fake API for testing and prototyping. Powered by JSON Server + LowDB As of Oct 2021, serving ~1.7 billion requests each month.

jsonplaceholder.typicode.com

 

#2 Model 만들기

 

API를 호출해서 JSON으로 리턴을 받게 되면 직렬화를 해주어야 한다.

https://javiercbk.github.io/json_to_dart/

 

JSON to Dart

JSON to Dart Paste your JSON in the textarea below, click convert and get your Dart classes for free. Handcrafted by Javier Lecuona Github json_to_dart Code Twitter

javiercbk.github.io

(언제 사라지거나  할진 모르지만 그래도 없는 거보단 좋다.)

 

인터넷 주소창에 ( https://jsonplaceholder.typicode.com/todos ) 입력하고 들어가면 GET 메소드로 API를 쏴볼 수 있다.

(postman 같은 거 쓰는 사람들은 그거 써도 된다.)

 

 

todos 로 쏘게 되면 200개의 리스트가 나온다고 한다.
이 중 하나의 오브젝트를 복사하여 JSON to Dart에 붙여넣어 준다.

 

 

이렇게 간단하게 모델을 만들 수 있다.

클래스 명까지 입력해줄 수 있으니 그냥 복사해 붙여도 잘 돌아갈 거 같다.

 

class Todos {
  int? userId;
  int? id;
  String? title;
  bool? completed;

  Todos({this.userId, this.id, this.title, this.completed});

  Todos.fromJson(Map<String, dynamic> json) {
    userId = json['userId'];
    id = json['id'];
    title = json['title'];
    completed = json['completed'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['userId'] = this.userId;
    data['id'] = this.id;
    data['title'] = this.title;
    data['completed'] = this.completed;
    return data;
  }
}

 

#3 Service 만들기

 

우선 API를 호출해야 하기 때문에 http를 불러와 준다. (자바스크립트에선 fetch와 같음)

 

 

pubspec.yaml 파일에 dependencies 부분에 http: 라고 적어준다.

 

1. 마우스 올려놓고 기다리면 전구 마크가 나온다.

클릭하고 Pub get 눌러주면 패키지를 다운 받는 듯 하다.

 

 

2. 만약 위 방법으로 안 된다면 terminal을 열고 아래 명령어를 입력해준다.

flutter pub get

 

 

Future는 자바스크립트의 Promise에 대응한다.

Future 안에서 API를 호출하고 모델에 담아준다.

 

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

Future<List<Todos>> fetchTodos() async {
  final response = await http.get(
      Uri.parse('https://jsonplaceholder.typicode.com/todos')
  );

  if(response.statusCode == 200){
    return (jsonDecode(response.body) as List)
        .map((e) => Todos.fromJson(e))
        .toList();
  } else {
    throw Exception('Failed to load album');
  }
}

 

#4 화면에 뿌리기

 

FutureBuilder<List<Todos>>(

)

 

FutureBuilder 위젯을 통해 API를 호출하여 받은 데이터를 화면에 뿌려줄 수 있다.

 

late Future<List<Todos>> futureTodos;

@override
void initState() {
	super.initState();
	futureTodos = fetchTodos();
}

@override
Widget build(BuildContext context) {
	return FutureBuilder<List<Todos>>(
		future: futureTodos,
		builder: (context, snapshot) {
            if (snapshot.hasData) {
                return Column(
                    children: <Widget>[
                        ...snapshot.data!.map((e) => SizedBox(
                            width: double.infinity,
                                child: Card(
                                    elevation: 4,
                                    child: Text(e.title!),
                                ),
                            )),
                    ],
                );
            } else if(snapshot.hasError) {
                return Text('${snapshot.hasError}');
            }
            return const CircularProgressIndicator();
		}
	)
}

 

future에 어떤 함수를 사용할지 넣어주고

builder의 아규먼트인 snapshot을 통해 사용할 수 있다.

 

#5 전체 소스코드

 

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const TodosWidget(),
    );
  }
}

class Todos {
  int? userId;
  int? id;
  String? title;
  bool? completed;

  Todos({this.userId, this.id, this.title, this.completed});

  Todos.fromJson(Map<String, dynamic> json) {
    userId = json['userId'];
    id = json['id'];
    title = json['title'];
    completed = json['completed'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['userId'] = this.userId;
    data['id'] = this.id;
    data['title'] = this.title;
    data['completed'] = this.completed;
    return data;
  }
}

Future<List<Todos>> fetchTodos() async {
  final response = await http.get(
      Uri.parse('https://jsonplaceholder.typicode.com/todos')
  );

  if(response.statusCode == 200){
    return (jsonDecode(response.body) as List)
        .map((e) => Todos.fromJson(e))
        .toList();
  } else {
    throw Exception('Failed to load album');
  }
}

class TodosWidget extends StatefulWidget {
  const TodosWidget({Key? key}) : super(key: key);

  @override
  _TodosWidgetState createState() => _TodosWidgetState();
}

class _TodosWidgetState extends State<TodosWidget> {
  late Future<List<Todos>> futureTodos;

  @override
  void initState() {
    super.initState();
    futureTodos = fetchTodos();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<Todos>>(
        future: futureTodos,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return Column(
              children: <Widget>[
                ...snapshot.data!.map((e) => SizedBox(
                  width: double.infinity,
                  child: Card(
                    elevation: 4,
                    child: Text(e.title!),
                  ),
                )),
              ],
            );
          } else if(snapshot.hasError) {
            return Text('${snapshot.hasError}');
          }
          return const CircularProgressIndicator();
        }
    );
  }
}

 

아직 자세하게 아는 것도 아니고 앱 개발도 처음이라 더 좋은 방법이 있는지 더 알아보고 한 번 더 글을 써야겠다.