220610_TIL / API

신두다·2022년 6월 10일
0

TIL

목록 보기
39/82

Key words

API, Server/Client, RESTful API, HTTP, 실습(OpenWeather API, Tweeter API)

1. API

  • 이전 회사에서 API라는 단어를 많이 썼었고, 관련 운영 업무를 진행했었다. 그때 API가 뭐야?! 라고 누가 물어본 적이 있었는데, 그때의 나는 '우리 서버에서 원하는 데이터를 가져갈 수 있도록 해주는 열쇠야!'라고 답변해줬던 기억이 난다. 과연 적절한 정의였을까?
  • API(Application Programming Interface)는 광범위하고 추상적인 의미로 사용하기 때문에 정의하기가 쉽지는 않다고 한다. 평범한 정의로는 기존에 존재하는 프로그램과 어떻게 소통할 수 있는지 알려주는 인터페이스 / 어떤 프로그램을 다룰 수 있는 조작 방법 혹은 메뉴얼과 비슷이 있다.
    • 나는 여러 비유 중에서 컴퓨터 키보드, TV 리모컨이 가장 와닿았다. (리모컨 이 버튼을 누르면 뒤에서 어떤 일이 슈루룩 일어나며 그 버튼이 정의된 행동이 일어난다. 이와 비슷하게 코드를 통해 누르면 빽딴에서 슈루룩 돌아가서 원하는 결과를 가져온다!)
  • 좀 다른 방식으로 말해보겠다. API를 말할 때 가장 핵심적인 개념은 (Service) Server, App/Client다.
    • 클라이언트가 A를 요청하면 서버는 그 A를 내주게 되는데, 만약 클라이언가 A를 서버가 이해 못하게 아무렇게나 요청하면, 서버는 내줄 수가 없잖아! 그래서 API라는 메뉴얼을 통해 원활하게 소통할 수 있도록 해주는 거다.
  • 참고로 API Server라는 것도 있는데, 쉽게 말해 ClientServer 사이의 중간다리 역할을 하는 것이다. 서버가 직접 모든 요청을 다 소화할 수 없을 때 사용하는 것으로 난 이해했다.
  • API를 통해 데이터를 받아오면 대부분 JSON형식으로 돌려준다고 한다. 물론 꼭 그런 건 아니다. 관습적으로 통용된다고 이해해도 될 것 같다. 받아오는 형식을 직접 정할 수 있도록 해주기도 하는 등 상황에 따라 다른 것으로 생각해도 된다.
    • 어떤 형식으로 받아오게 되느냐에 따라 그 데이터를 가공할 우리가 할 일이 달라지겠쥬? 그래서 중요한 거다.
    • 참고로 json 파일은 파이썬의 Dict와 유사하게 생겼는데, 둘의 공통점은 Key값을 통해 Value를 불러올 수 있다는 것이다. 차이점은 json에서는 문자열 표시는 반드시 큰따옴표만 써야 한다는 것? 큰 차이는 없다고 들었다.

2. HTTP

  • HyperText Transfer Protocal의 약어로 컴퓨터들의 통신 규약중 하나이다.
  • 난 이 상황 설명이 가장 와닿았다. 웹이 막 퍼지던 시절을 상상해보자. 당시에는 HTTP같이 정해진 통신 규약이 없었기 때문에, 컴퓨터 간에 일어나던 많은 소통이 저마다의 방식으로 이루어졌다고 한다. 그렇게 지나다보니 나중에 가서는 너무 혼란스러운 상황이 일어난 거다!
  • 그때 등장한게 바로 HTTP이다. '자, 자, 우리 서로 통신하는 규칙을 좀 만들어봤어~ 우리 앞으로 이대로 소통하면 혼란이 덜할 것 같은데!' 라는 컨셉으로 이해할 수 있겠다.
  • HTTP는 크게 요청과 응답으로 나뉘어져있다.
  • HTTP Request
    • 위에서 얘기했던 것처럼 클라이언트가 서버에 '이거 주세요~'하는 거다.
    • CRUD(기본적인 데이터 처리 기능 Creat, Read, Update, Delete)에 사용되는 주요 HTTP 메소드는 다음이 있다.
      • 이외에 다양한 메소드에 대해서는 MDN HTTP Request Methods 를 참고하면 된다. (웹과 관련해서는 이 MDN 사이트 기억해~!!)
GET : 특정 리소스를 달라고 할 때에 사용됨.
	예시: 페이지 로딩할 때
    
POST : 클라이언트에서 서버측에 많은 정보를 전달할 때 사용됨.
	예시: 회원가입을 할 때에 특정 유저의 정보를 서버에 저장
    
"CF. GET 도 클라이언트의 정보를 전달하는데도 사용됩니다. POST 는 주로 JSON 과 같이 한줄로 표현되기 힘든 데이터를 전달할 때 사용합니다."

PUT/PATCH : 서버 측의 특정 리소스를 업데이트 할 때 사용. PUT 은 데이터 전부를 바꿀 때, PATCH 는 부분적으로 변경할 때 사용됨.
	예시: 사용자 닉넴임 변경

DELETE : 서버 측의 특정 리소스를 삭제할 때 사용.
	예시: 유저 탈퇴
  • HTTP Response
    • 이건 익숙하다! 404에러 같은거! 이런 status code를 정리하면 아래와 같다.
      - 100 번대 : 정보 응답
      - 200 번대 : 성공 응답
      - 300 번대 : 리다이렉션 메시지
      - 400 번대 : 클라이언트 에러 응답
      - 500 번대 : 서버 에러 응답

다음으로 넘어가기 전에 기억해야할 것은

  • 이 HTTP는 권고사항이지 의무 사항이 아니었다는 것이다. 즉, 위에 적어둔 요청이나 응답을 무조건 지켜야 한다는 건 아니다.
  • 하지만 이런 규약을 잘 지키면, 여러 사람이 함께
    작업할 때, 소통할 때 혼란을 줄일 수 있다는 점에서 의미가 있다. 따라야 해!!
  • 오늘 들은 설명에 의하면, 웹 초기 HTTP method 등의 권고사항을 통해 규칙을 통일하고 혼란을 줄이려고 했지만, 그럼에도 사람들이 권고사항을 잘 지키지 않아 혼란이 계속되었다.
  • 그래서 바야흐로 REST API라는게 등장하게 된다.

3. REST API

  • REST API는 하나의 형식이다. API 안에 web API(=HTTP API)가 있고, 그 안에 REST API가 있다고 생각하면 된다.
  • 위에서 말했던 등장 배경을 보면 이게 어떤 역할을 하기 위해 만들어졌는지 눈치챌 수 있을 것이다. 그건 바로, 우리 정해진 규칙들 좀 잘 좀! 잘 좀! 지켜보자!라는 것이다. 즉, 소프트웨어의 아키텍쳐를 어떻게 형성할지에 대한 '가이드 라인'이다.
    • (파이썬의 PEP-8 같이 생각해도 될 듯?)
  • 이 규칙(가이드라인)들을 잘 지키면, 여러 명이 일할 때도 특정인이 만든 API에 대해서 굳이 구구절절 설명을 듣지 않아도, 직관적으로 이해할 수 있게 되는 거다.
  • 이렇게 REST를 잘 지킨 API를 RESTful API라고 부른다.
    • 만약 회사 내 타팀에서 API를 만들어달라고 요청하는데, RESTful한 API로 만들어줄 필요는 없어요~라고 하면 만드는 사람에게 좀 더 자율권이 생기는 것으로 이해할 수 있다. (예를 들어, OK에 대한 Status Code를 꼭 딱 200으로 안 해도 된다거나..)
    • 참고 참고! REST API Tutorial
  • 생각해보니 이전 회사에서 URL 형식의 API로 고객사 데이터 불러오는 작업할 때, URL만 보고도 어떤 데이터를 가져오려는지 나도 바로 알 수 있었고, 날짜만 바꿔서 여러 날의 데이터를 가져오기도 했는데 딱 그게 RESTful한 API였다!!

4. 실습한 것

오늘은 아래 실습을 해보았다.

  • OpenWeather API 키를 발급받고, 원하는 데이터 가져오기.
  • 트위터 API 키를 발급받고, 원하는 데이터 가져오기.
    (tweepy 사용함.)

풀었던 코드를 그대로 옮겨둔다.

[OpenWeather]

from ast import If
import requests
import json

API_KEY = '00'


def get_city_data(city_name):
    """
    현재 날씨를 보고 싶은 도시 이름을 넣으면 해당 데이터를 json 형태로 리턴하기.
    """

    url = f"https://api.openweathermap.org/data/2.5/weather?q={city_name}&appid={API_KEY}"

    data = requests.get(url) #실행하면 이상없을 때 'Response [200]' 응답 넘겨준다.

    current_weather = json.loads(data.text) # json parsing 
    
    return current_weather



def get_weather_description(json_data):
    """
    받아온 json 데이터 중 '날씨'에 대해서 담고 있는 문자열을 리턴하기
    """

    weather_description = json_data['weather'][0]['description']

    return weather_description


def get_minimum_temp(json_data):
    """
    최저 온도를 섭씨(℃) 단위로 리턴하기
    """
    temp_min_kelvin = json_data['main']['temp_min']

    temp_min = round(temp_min_kelvin - 273.15, 2) # kelvin to celius fomula => C = K - 273.15

    return temp_min

[Twetter API]

import tweepy

def connect_api():
    """
    tweepy 로 API 를 연결한 'api' 객체를 리턴하기
    """

    api_key = '00'
    api_key_secret = '00'
    access_token = '00'
    access_token_secret = '00'

    auth = tweepy.OAuthHandler(api_key, api_key_secret)
    auth.set_access_token(access_token, access_token_secret)

    api = tweepy.API(auth)

    return api
    # 참고 - tweeter portal에서 elevated auth로 업그레이드 하였음. Essential이면 접근 안되서 오류 남.
    # 지금은 api ver2가 latest version이지만, v1도 지원이 되며, 위 코드는 v1기준 작동 코드인 듯.


def get_tweets(api, username):
    """
    'username' 이 주어지면 해당 유저의 트윗들을 가지고 오기
    (140 자 이상이어도 모든 내용을 가지고 올 수 있어야 함)
    """

    tweets = api.user_timeline(username, tweet_mode = "extended")

    return tweets
    
    #참고한 자료 https://exupery-1.tistory.com/203

[도전과제 - 트위터 이어서]

from locale import NOEXPR
import os
from pickle import NONE
import sqlite3
# DB_FILENAME, DB_FILEPATH 변경하지 마세요
DB_FILENAME = "twitter_db.sqlite3"
DB_FILEPATH = os.path.join(os.getcwd(), DB_FILENAME)

def get_cursor(DB_FILEPATH):
    """
    데이터베이스와 연결된 커서 객체를 리턴하기
    """
    connection = sqlite3.Connection(DB_FILENAME) 
    cursor = connection.cursor()

    return connection, cursor

def init_database(connection, cursor):
    """
    기존에 데이터가 있다면 지우고, 주어진 스키마에 따라 데이터베이스 테이블을 생성한다.
    """
    
    #DROP - tables (sqlite에는 DROP DATABASE statement가 없다. 그래서 그냥 하나씩 한다.)
    cursor.execute("DROP TABLE IF EXISTS user;")
    cursor.execute("DROP TABLE IF EXISTS tweet;")

    #CREATE
    cursor.execute("""CREATE TABLE user(
        id INTEGER NOT NULL,
        screen_name VARCHAR,
        PRIMARY KEY (id)
    );
    """) 

    cursor.execute("""CREATE TABLE tweet(
        id INTEGER NOT NULL,
        full_text VARCHAR,
        user_id INTEGER,
        PRIMARY KEY (id),
        FOREIGN KEY (user_id) REFERENCES user (id) 
    );
    """) 
    # 참고 - 외래키 정책 => ON UPDATE, ON DELETE cascade, no action등 적용 가능
    # 메모: one-to-many => 한 명의 user는 여러 tweet을 가질 수 있다. 반대로 여러 명의 유저는 하나의 트윗을 가질 수 없다. 

    connection.commit();
  • 도전과제는 위까지 풀었는데, 그 다음 문제에서 막혀서 진전이 안되었다. 주말을 위해 남겨두는 걸로 하자. ㅎ

5. 그 외

  • 어떤 형식으로 반환되는지를 알면, 내가 원하는 결과를 얻기 위해 어떻게 해야하는지를 아는데 도움이 될 것이라는 점!
data = requests.get(’url’)

print(type(data)) #=> requests.models.Esponse
print(type(data.content)) #=> bytes
print(type(data.text)) #=> text

Feeling


  • 처음에 오픈웨더 API에서 원하는 날씨 직접 뽑아오는거까지 해보니 너무 신기했다. API 되게 무서운 것처럼 생각했었는데, 그건 아니였구만!
  • 도전과제까지 오늘 다 쓱 풀어버리고 싶었는데,, 막힌 문제 하나에 거의 2-3시간 정도를 썼지만 결국 못 풀었다.
    • (이 정도 안되면 혼자 매달리는 것도 병이야~라는 생각에 다른 동기 코드를 봤는데 솔직히 이게 왜 맞지? 라는 생각이 들었던 거 보면 내가 문제를 잘 못 이해하고 있는 것 같다.)
    • 속상하긴 한데 주말에 공부할거 남겨두었다고 생각하니 뭔가 괜찮은 것 같기도? (주말에 거대한거 하면 뭔가 심리적 부담감이 있지만, 이렇게 문제 몇개 정도야 좋지~)(정신승리일 수도 있다)
  • 암튼 오늘 배운 것도, 한 번 배우고 머릿속에서 썩기만 할게 아니라 내가 앞으로 실질적으로 활용할 수 있을만한 것들인 것 같아 아주 재밌게 배웠다.
profile
B2B SaaS 회사에서 Data Analyst로 일하고 있습니다.

0개의 댓글