[flutter] 플러터 http api 호출해보기

     

플러터를 이용해서 간단하게 API 호출을 해보겠습니다.

 

환경은 MacOS, intelliJ

 

 

프로젝트 만들기

일단 신규 프로젝트를 만듭니다.

 

인텔리J를 활용

 

저는 젯브레인즈 툴을 많이 쓰기 때문에(전부 샀기 때문에,,) 인텔리J를 활용해서 플러터를 사용하고 있습니다. 각자 자신이 쓰는 툴 쓰시면 되용~

 

 

프로젝트 만들었으면 괜히 한번 실행해주는 게 예의죠. 

 

API 사용하기 위한 회원가입

이번에 사용할 API는 뉴스 API인데요, newsapi.org에 접속해서 간단하게 가입하면 사용할 수 있습니다.

 

홈페이지에 접속해서 회원가입~!

이메일 주소만 있으면 가입이 가능합니다. 

 

가입하고 나면 API 키를 줍니다. 이 키를 이용해서 API를 호출할 수 있습니다.

 

요롷게 API키를 줍니다.

API키를 받고 나서 다시 홈페이지에 있는 get start메뉴를 들어가면 어떻게 API를 호출하는지 문서가 나옵니다. 대부분의 open-api의 경우 이렇게 문서 형태로 사용법을 제공하기 때문에 이런 방식에 익숙해지시는 게 좋습니다. ㅎㅎ 

 

API 사용 문서가 제공된다

대부분의 API 문서는 영어로 제공되기 때문에 영어 공부도 꾸준히... ^^

저희가 이번에 사용해볼 API는 Top headlines라고 최신 기사를 가져오는 API입니다. 

공식문서를 보시면 아래처럼 호출하는 것을 알 수 있습니다.

 

GET https://newsapi.org/v2/top-headlines?country=us&apiKey=b526c8b83fb34be89a54447881072c1c

 

GET으로 호출하고 param으로 country와 apiKey만 넣으면 됩니다. 이 API가 잘 호출되는지 보기 위해서 간단하게 툴로 확인해 볼까요?

바로 호출되네요?

insomnia 툴을 이용해 get호출을 해봤더니 바로 나옵니다. 아마도 API key를 제껄로 세팅해서 문서가 만들어지나 보네요 ㅋㅋ 여기서 우리는 한국기사를 보고 싶으니까 country를 kr로 바꿔봅시다.

 

kr로 바꾸니까 바로 한글로 나오네요

정상 작동되네요. 이제 이 api를 플러터로 옮겨보겠습니다.

 

 

플러터에 구현하기

 

일단 api호출을 위해 http 모듈을 설치합니다.

 

pubspec.yaml

pubspec.yaml에 http를 추가합니다. 최신 버전은 pub.dev 사이트에서 확인 가능합니다. 지금은 0.13.4가 최신이네요. 모듈을 추가하고 pub get을 해줘야 실제로 설치됩니다.

 

flutter pub get

 

이제 News 데이터를 위한 모델을 먼저 생성해줍니다. 보통 모델은 lib/models라는 폴더를 만들어서 관리합니다.

 

models 폴더로 관리

코드는 아래와 같습니다.

 

class News{
  late String title;
  late String content;

  News({
    required this.title,
    required this.content
});

  News.fromMap(Map<String, dynamic>? map) {
    title = map?['title'] ?? '';
    content = map?['description'] ?? '';
  }
}

 

fromMap에다가 Map<String, dynamic>으로 하면 Json -> object 형태로 파싱이 됩니다. API의 응답 결과가 Json형태로 오기 때문에 fromMap을 이용해 파싱을 추가해줍니다.

 

여기서 실제 API의 응답으로는 title과 description 필드가 오지만, 제가 임의로 title, content로 바꿨습니다. ㅎㅎ 헷갈리지 마시길..

 

모델을 만들었으니 이제 화면을 만들어줍시다. 화면은 뭐 대충 리스트 형태로 나오기만 하면 됩니다.

 

화면은 screens

화면은 screens폴더에 모아둡니다. views라고 해도 되고 widgets라고 해도 됩니다. 취향이에요 ^오^

 

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import '../models/news.dart';

class NewsScreen extends StatefulWidget {

  @override
  _NewsScreenState createState() {
    return new _NewsScreenState();
  }
}

class _NewsScreenState extends State<NewsScreen> {

  List<News> news = [];
  bool isLoading = true;


  @override
  void initState() {
    super.initState();
    setState(() {
      isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("뉴스 http"),
      ),
      body: isLoading ? Center(child: const CircularProgressIndicator(),) :
      GridView.builder(gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 4,
          childAspectRatio: 2 / 3,
          crossAxisSpacing: 20,
          mainAxisSpacing: 20
      ),
          itemCount: news.length,
          itemBuilder: (context, index) {
            return Container(
              padding: EdgeInsets.all(20),
              child: Column(
                children: [
                  Text(news[index].title),
                  Text(news[index].content),
                ],
              ),
            );
          }),
    );
  }
}

 

아직은 실행을 해도 데이터가 나오지 않습니다. api호출을 해서 데이터를 가지고 오는 부분이 없기 때문이죠. 데이터를 가져오는 provider를 만들어봅시다.

 

providers 폴더

import 'dart:convert';

import 'package:http_tutorial/models/news.dart';
import 'package:http/http.dart' as http;

class NewsProviders{
  Uri uri = Uri.parse("https://newsapi.org/v2/top-headlines?country=kr&apiKey=b526c8b83fb34be89a54447881072c1c");

  Future<List<News>> getNews() async {
    List<News> news = [];

    final response = await http.get(uri);

    if (response.statusCode == 200) {
      news = jsonDecode(response.body)['articles'].map<News>( (article) {
        return News.fromMap(article);
      }).toList();
    }

    return news;
  }


}

 

API Key 부분은 여러분이 발급받은 키를 넣으면 됩니다. 뉴스를 조회하는 기능밖에 없으니 getNews() 하나면 충분합니다. 만약 여러분이 RestApi를 만들었다면, get, post, delete, put에 각각 대응되는 method를 만들어서 구현하면 됩니다. 

 

이제 화면에서 만든 Provider를 적용하면 뉴스를 보여줄 수 있습니다.

 

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http_tutorial/providers/news_providers.dart';

import '../models/news.dart';

class NewsScreen extends StatefulWidget {

  @override
  _NewsScreenState createState() {
    return new _NewsScreenState();
  }
}

class _NewsScreenState extends State<NewsScreen> {

  List<News> news = [];
  bool isLoading = true;
  NewsProviders newsProvider = NewsProviders();

  Future initNews() async {
    news = await newsProvider.getNews();
  }

  @override
  void initState() {
    super.initState();
    initNews().then((_) {
      setState(() {
        isLoading = false;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("뉴스 http"),
      ),
      body: isLoading ? Center(child: const CircularProgressIndicator(),) :
      GridView.builder(gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 4,
          childAspectRatio: 2 / 3,
          crossAxisSpacing: 20,
          mainAxisSpacing: 20
      ),
          itemCount: news.length,
          itemBuilder: (context, index) {
            return Container(
              padding: EdgeInsets.all(20),
              child: Column(
                children: [
                  Text(news[index].title),
                  Text(news[index].content),
                ],
              ),
            );
          }),
    );
  }
}

 

initNews라는 새로운 함수를 만들고 InitState에서 InitNews를 먼저 실행하고 완료된 경우 setState를 실행하도록 수정했습니다. initNews를 initState 안에 넣어서 사용하고 싶으나 그렇게 하면 비동기 처리가 안되더군요. Future와 async, await를 이용해 getNews를 해야 하나 봅니다. 

 

이제 앱을 실행해보면 아래와 같이 화면이 나옵니다.

 

뉴스들이 나온다

2번째 보면 무슨 공사표지판 같은 게 나오는데, 텍스트가 공간을 넘어갔다는 뜻입니다. 지금 보면 뉴스 제목과 내용이 구분도 안되고 하는데,, 텍스트 스타일을 살짝 바꿔서 보기 좋게 바꿔봅시다. 내용도 한 100자 정도만 나오게 하면 짤리지 않겠죠?

 

살짝 수정

 

살짝 수정했습니다. ㅎㅎ 

제목은 bold처리를 하고, 내용은 maxLine을 5로 지정해줬더니 이제 어느 정도 깔끔하군요. 

 

마무리 

flutter에서 http모듈을 통해 아주 간단하게 get처리를 구현했습니다. http모듈이 아니라 다른 모듈을 활용해 더 쉽게 rest api를 구현할 수도 있지만, 가장 기본이 되는 http를 한번 살펴봤습니다. 앞으로 상태 관리를 위한 Bloc이나 getx를 사용해보면서 거기에 api를 붙여보는 작업을 해보도록 하겠습니다. 

 

 

 

 

 

반응형

댓글

Designed by JB FACTORY