[Flutter] Freezed 사용해보기 #2 (feat. Retrofit)

leeeeeoy·2021년 9월 21일
0

저번에 freezedretrofit 기본 사용법에 대해서 알아보았다. 이번엔 두 라이브러리를 모두 이용해서 간단하게 로컬 서버와 연동해보았다. 서버와 통신해야 하는 데이터가 많다면 작성할 코드의 양이 상당히 많이 줄어들기 때문에 종종 자주 사용할 것 같기도 하다

코드작성

packages

pubspec.yaml

dependencies:
  dio:
  retrofit:
  freezed_annotation:

dev_dependencies:
  retrofit_generator:
  build_runner:
  json_serializable:
  freezed:
  
  • 기본적인 필수 패키지들과 함께 json_serializable을 추가해줬다.

Flutter code

rest_client.dart

import 'package:dio/dio.dart';
import 'package:flutter_study/pages/retrofit_with_freezed/student.dart';
import 'package:retrofit/retrofit.dart';

part 'rest_client.g.dart';

(baseUrl: 'http://localhost:8080')
abstract class RestClient {
  factory RestClient(Dio dio, {String baseUrl}) = _RestClient;

  ('/student')
  Future<List<Student>> getStudents();

  ('/student/{id}')
  Future<Student> getStudentByID(() int id);
}
  • 사용법은 지난 글에서 작성한 것과 같다
  • getStudents()와 getStudentByID() 두 메서드로 테스트 했다.
  • 애뮬레이터에서 로컬 서버와 연결할 때, 그냥 localhost로 적으면 통신이 되지 않는다. 서버쪽에서 실행중인 IP주소를 직접 적어주어야 애뮬레이터와 로컬 서버가 통신이 된다.
    ex) 192.123.456.789

student.dart

import 'package:freezed_annotation/freezed_annotation.dart';

part 'student.g.dart';
part 'student.freezed.dart';


class Student with _$Student {
  factory Student({
    required int id,
    required String name,
    required String email,
    (name: 'is_like_flutter') required bool isLikeFlutter,
  }) = _Student;

  factory Student.fromJson(Map<String, dynamic> json) =>
      _$StudentFromJson(json);
}
  • 서버에서 받아올 Student 데이터를 작성해주었다.
  • Json 메서드를 사용하기 위해 fromJson 메서드를 작성해주었다.
  • 기본적으로 property가 변수 이름 그대로 매핑되기 때문에 @JsonKey를 이용해 snake_case로 설정해줬다. 저번에 이거 때문에 엄청 애먹었다...하

위 두 파일을 작성해주고 flutter pub run build_runner build를 실행시켜준다. 파일에 생성될 코드 이외에 오류가 있으면 생성이 되지 않으므로 주의해야 한다. 이번에 작성하면서 여러번 실행시켰다

result_page.dart

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_study/pages/retrofit_with_freezed/rest_client.dart';
import 'package:flutter_study/pages/retrofit_with_freezed/student.dart';

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

  
  _ResultPageState createState() => _ResultPageState();
}

class _ResultPageState extends State<ResultPage> {
  late RestClient client;
  Dio dio = Dio();

  
  void initState() {
    super.initState();
    client = RestClient(dio);
  }

  studentColumn(Student student) {
    return Column(
      children: [
        Text('${student.id}'),
        Text('${student.name}'),
        Text('${student.email}'),
        Text('${student.isLikeFlutter}'),
      ],
    );
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Retrofit with Freezed'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Text('getStudents'),
            FutureBuilder(
              future: client.getStudents(),
              initialData: [],
              builder: (_, AsyncSnapshot snapshot) {
                if (snapshot.connectionState == ConnectionState.waiting) {
                  return Center(
                    child: CircularProgressIndicator(),
                  );
                }
                List<Student> students = snapshot.data;

                return Row(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: [
                    studentColumn(students[0]),
                    studentColumn(students[1]),
                    studentColumn(students[2]),
                  ],
                );
              },
            ),
            SizedBox(
              height: 50,
            ),
            Text('getStudentByID'),
            FutureBuilder(
              future: client.getStudentByID(1),
              builder: (_, AsyncSnapshot snapshot) {
                if (snapshot.connectionState == ConnectionState.waiting) {
                  return Center(
                    child: CircularProgressIndicator(),
                  );
                }
                final Student student = snapshot.data;
                return studentColumn(student);
              },
            ),
          ],
        ),
      ),
    );
  }
}
  • 통신 결과를 보여주는 화면이다.
  • FutureBuilder를 이용해서 결과를 보여주도록 작성했다.

Server code

main.go

package main

'
'
'

type Student struct {
	Id            int    `json:"id"`
	Name          string `json:"name"`
	Email         string `json:"email"`
	IsLikeFlutter bool   `json:"is_like_flutter"`
}

var students = []Student{
	{
		Id:            1,
		Name:          "Kim",
		Email:         "naver.com",
		IsLikeFlutter: false,
	},
	{
		Id:            2,
		Name:          "Lee",
		Email:         "google.com",
		IsLikeFlutter: true,
	},
	{
		Id:            3,
		Name:          "Jung",
		Email:         "kakao.com",
		IsLikeFlutter: false,
	},
}

func main() {
	e := echo.New()
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())

	e.GET("/student", func(c echo.Context) error {
		return c.JSON(http.StatusOK, students)
	})
	e.GET("/student/:id", func(c echo.Context) error {
		id, _ := strconv.Atoi(c.Param("id"))
       
		var s Student
        
		for _, student := range students {
			if student.Id == id {
				s = student
			}
		}
		return c.JSON(http.StatusOK, s)
	})
	e.Logger.Fatal(e.Start(":8080"))
}
  • 응답 서버를 간단하게 Go로 작성했다.
  • Student를 작성하고, 각각 핸들러 함수를 작성해줬다.

결과

  • 서버로부터 데이터가 전달된 것을 확인할 수 있다.

정리

간단하게 서버와 연동을 해봤다. 서버와 통신할 데이터가 많지 않다면 직접 작성을 해도 되겠지만 데이터의 양이 많고 변경할 상황이 많지 않다면 사용하면서 많은 이점을 얻을 수 있는 것 같다. 사실 작성할 코드가 줄어드는 것만 해도 신세계였다.

그건 그렇고 이미지 크기를 조절하는게 되지 않는다. 이번엔 한 장 뿐이라 첨부했다. 구글링을 해보니 마크업 문법이 적용된다고 하는데 크기는 왜 조절이 되지 않는지 잘 모르겠다.

소스코드 https://github.com/leeeeeoy/flutter_personal_study/tree/master/lib/pages/retrofit_with_freezed


참고자료

profile
100년 후엔 풀스택

0개의 댓글