관리 메뉴

Bull

[Flutter] dart에 upbit api 호출하기 본문

Software Framework/Flutter

[Flutter] dart에 upbit api 호출하기

Bull_ 2024. 1. 24. 20:36

 

main.dart

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Trading Dashboard',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: DashboardScreen(),
    );
  }
}

class DashboardScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Trading Dashboard'),
      ),
//------------------------------------------------------------------------
      body: FutureBuilder(
        future: fetchWithJwt(), // 비동기 함수를 FutureBuilder에 전달
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            // 데이터 로딩 중일 때 로딩 인디케이터 표시
            return Center(child: CircularProgressIndicator());
          } else if (snapshot.hasError) {
            // 오류 발생 시 오류 메시지 표시
            return Center(child: Text('Error: ${snapshot.error}'));
          }
//------------------------------------------------------------------------
          return Row(
            // 올리고 싶은 UI
          );
        },
      ),
    );
  }
}

 

request_api.dart

import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:http/http.dart' as http;
import 'package:uuid/uuid.dart';
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';

Future<void> fetchWithJwt() async {
  await dotenv.load(fileName: ".env");
  final accessKey = dotenv.env['ACCESS_KEY']!;
  final secretKey = dotenv.env['SECRET_KEY']!;


  var query = {
    // API에 필요한 쿼리 입력
    'market': 'KRW-BTC'
  };

  var m = utf8.encode(Uri(queryParameters: query).query);
  var queryHash = sha512.convert(m).toString();

  var nonce = Uuid().v4();
  var jwt = JWT({
    'access_key': accessKey,
    'nonce': nonce,
    'query_hash': queryHash,
    'query_hash_alg': 'SHA512',
  });

  var jwtToken = jwt.sign(SecretKey(secretKey), algorithm: JWTAlgorithm.HS256);
  var authorizationToken = 'Bearer $jwtToken';

  var headers = {
    'Authorization': authorizationToken,
    // 추가 헤더
  };

  // API 요청 URL 입력
  const url = 'https://api.upbit.com/v1/market/all';

  try {
    var response = await http.get(Uri.parse(url), headers: headers);

    if (response.statusCode == 200) {
      print('Data: ${response.body}');
    } else {
      print('Failed to load data: ${response.statusCode}');
    }
  } catch (e) {
    print('Error occurred: $e');
  }
}

 

 

라이브러리 / .env 추가

dependencies:
      flutter_dotenv: ^5.1.0
      http: ^1.2.0
      uuid: ^4.3.3
      dart_jsonwebtoken: ^2.12.2
      crypto: ^3.0.3
 
flutter:
      assets:
      - .env

 

 

 

 

 

 

 


본문

플러터로 윈도우앱을 만들어 비트코인 자동매매를 만들고 싶은데 업비트 api의 가이드북은 다른 언어로 한정되어 있어서 gpt로 코드를 만들어보았다.

 

비동기처리를 아직 제대로 이해하지 못해 학습용으로 괜찮을 거 같아서 포스팅으로 기록해보려한다.

 

 

 

 

 

 

 

 

 

main UI

      body: FutureBuilder(
        future: fetchWithJwt(), // 비동기 함수를 FutureBuilder에 전달
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            // 데이터 로딩 중일 때 로딩 인디케이터 표시
            return Center(child: CircularProgressIndicator());
          } else if (snapshot.hasError) {
            // 오류 발생 시 오류 메시지 표시
            return Center(child: Text('Error: ${snapshot.error}'));
          }

 

FutureBuilder

 

비동기 작업을 처리할 request_api.dart를 따로 모듈화 하였고 함수로 정의되었기 때문에 UI를 불러오는 동시에 비동기 작업을 하기 위해서는 위와같이 FutureBuilder 위젯을 사용한다.

 

인자로는 context로 현재 위젯의 위치정보와 snapshot은 현재 비동기 작업 처리 상태를 보낸다.

 

 

 

 

 

 

 

 

 

 

.env에서 access_key, secret_key 가져오기

 

flutter_dotenv 라이브러리를 이용하여 다음과 같이 변수를 불러올 수 있다.

  await dotenv.load(fileName: ".env");
  final accessKey = dotenv.env['ACCESS_KEY']!;
  final secretKey = dotenv.env['SECRET_KEY']!;

 

이또한 반드시 비동기 처리가 되기 때문에 await 키워드를 붙여준다.

 

참고로 .env파일에 변수는 발급 받은 key로 이렇게 설정하면 된다.

 

 

 

 

 

 

 

 

 

 

Python과 비교해서 보기

# Python 3

import jwt    # PyJWT 
import uuid
import hashlib
from urllib.parse import urlencode

# query는 dict 타입입니다.
m = hashlib.sha512()
m.update(urlencode(query).encode())
query_hash = m.hexdigest()

payload = {
    'access_key': '발급받은 Access Key',
    'nonce': str(uuid.uuid4()),
    'query_hash': query_hash,
    'query_hash_alg': 'SHA512',
}
    
jwt_token = jwt.encode(payload, '발급받은 Secret Key')
authorization_token = 'Bearer {}'.format(jwt_token)

https://docs.upbit.com/docs/create-authorization-request

 

Open API | 업비트 개발자 센터

 

docs.upbit.com

 

실제 제공해주는 python 코드와 비교해서 나타내 보겠다.

 

 

 

 

 

nonce

나의 uuid를 넣으면된다.

 

python

str(uuid.uuid4()),

dart

var nonce = Uuid().v4();

 

 

 

query_hash

내가 보낼 쿼리이다. python 예제는 어떤 쿼리인지 초기화 없이 해싱만 해서 적용했지만 만약 쿼리가 있을 때 어떤 식으로 보내는 지 dart를 통해 적용해보았다.

 

python

# query는 dict 타입입니다.
m = hashlib.sha512()
m.update(urlencode(query).encode())
query_hash = m.hexdigest()

 

query = {'어떤': '딕셔너리라는 가정하에'} 적용됐다고 하면 위와같이 인코딩 후 해싱을 하고 16진수로 전환해준다.

m이 순서때문에 혼동 될 수 있지만 풀어써보면

m = hashlib.sha512().update(urlencode(query).encode()) 이므로

 

(인코딩 → sha512해싱 → 16진수 전환) 이다.

 

dart

  var m = utf8.encode(Uri(queryParameters: query).query);
  var queryHash = sha512.convert(m).toString();

 

따라서 dart에서도 인코딩 → sha512해싱 →16진수로 전환해준다.

 

 

 

 

 

jwt

이제 보낼 payload를 jwt 토큰으로 감싸는 역할을 한다. 

 

python

jwt_token = jwt.encode(payload, '발급받은 Secret Key')
authorization_token = 'Bearer {}'.format(jwt_token)

 

dart

  var jwtToken = jwt.sign(SecretKey(secretKey), algorithm: JWTAlgorithm.HS256);
  var authorizationToken = 'Bearer $jwtToken';

 

 

(request하는 코드비교는 업비트 가이드 북에 안나와서 생략)

 

 

결과

 

 

내 자산을 보고 싶다면 url을 [https://api.upbit.com/v1/accounts]  로 바꾸면 된다.

 

(짜잔~ 1000원도 안되는 내 계좌 잔고이다.)