Python에서 JSON 처리와 API 통신 완벽 가이드 | 유효성 검사와 보안 대책

1. JSON이란?(기초 지식)

JSON 개요

JSON(JavaScript Object Notation)는 클라이언트와 서버 간 통신에 자주 사용되는 데이터 포맷입니다. 가볍고 읽기 쉬우며 구조가 단순하기 때문에 웹 애플리케이션과 모바일 애플리케이션에서 널리 사용됩니다. JSON은 텍스트 형식이라 어떤 언어에서도 쉽게 다룰 수 있어 매우 범용성이 높습니다。

JSON의 기본 구조

JSON은 키와 값의 쌍으로 데이터를 표현합니다. 예를 들어, 다음과 같은 JSON 구조가 있습니다:
{
  "이름": "사토",
  "나이": 30,
  "취미": ["독서", "영화"]
}
이 예에서는、이름은 문자열, 나이는 숫자, 취미는 배열입니다. 구조가 단순하고 가독성이 높기 때문에 데이터의 주고받기가 매우 효율적입니다。

JSON의 장점

  1. 가볍고 효율적: 텍스트 형식이므로 전송량이 적어 네트워크 부하가 줄어듭니다.
  2. 호환성이 높음: 거의 모든 프로그래밍 언어에서 지원되며, 여러 플랫폼에서 사용할 수 있습니다。
  3. 파싱이 간단: 데이터의 읽기/쓰기가 쉬워, 특히 API 통신에서 강력한 도구입니다。

2. Python에서의 JSON 다루기(기본편)

Python의json모듈

Python에서는 json 모듈을 사용해 JSON 데이터를 쉽게 읽고 쓸 수 있습니다. 예를 들어, JSON 데이터를 Python의 딕셔너리형으로 변환하려면 json.loads() 함수를 사용합니다。
import json

json_data = '{"이름": "사토", "나이": 30}'
python_obj = json.loads(json_data)

print(python_obj)  # {'이름': '사토', '나이': 30}
반대로, Python 객체를 JSON 형식으로 변환하려면 json.dumps()를 사용합니다。
python_obj = {"이름": "사토", "나이": 30}
json_data = json.dumps(python_obj, ensure_ascii=False)

print(json_data)  # {"이름": "사토", "나이": 30}

파일 입출력

JSON 데이터를 파일에서 읽거나 파일에 쓸 수도 있습니다。
# 파일에서 읽기
with open('data.json', 'r') as f:
    data = json.load(f)

# 파일에 쓰기
with open('data.json', 'w') as f:
    json.dump(python_obj, f, ensure_ascii=False)

3. Python에서의 JSON 통신(실전편)

requests 모듈을 사용한 API 통신

requests 모듈을 사용하면 API를 통해 JSON 데이터를 쉽게 송수신할 수 있습니다. 아래는 POST 요청으로 JSON을 전송하고 응답을 받는 예시입니다.

POST 요청으로 JSON 데이터를 전송

import requests

url = 'https://example.com/api'
data = {'이름': '사토', '나이': 30}

response = requests.post(url, json=data)
json_response = response.json()

print(json_response)

GET 요청으로 JSON 데이터를 수신

GET 요청을 사용해 API에서 JSON 데이터를 가져오는 것도 간단합니다.
response = requests.get('https://example.com/api/user/1')
data = response.json()

print(data)

4. 오류 처리와 모범 사례

API 통신에서의 오류 처리

API 통신 중 오류가 발생한 경우, 적절한 오류 처리를 수행하는 것이 중요합니다. 아래 예시에서는 네트워크 오류나 타임아웃 등의 예외를 캐치합니다.
try:
    response = requests.post(url, json=data)
    response.raise_for_status()
except requests.exceptions.HTTPError as errh:
    print("Http Error:", errh)
except requests.exceptions.ConnectionError as errc:
    print("Error Connecting:", errc)
except requests.exceptions.Timeout as errt:
    print("Timeout Error:", errt)
except requests.exceptions.RequestException as err:
    print("OOps: Something Else", err)

재시도 처리

네트워크가 불안정한 경우 재시도 처리를 구현하는 것도 중요합니다. requests 모듈에서는 재시도 처리를 Retry 클래스를 사용해 간단히 구현할 수 있습니다.
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

session = requests.Session()
retry = Retry(connect=3, backoff_factor=0.5)
adapter = HTTPAdapter(max_retries=retry)
session.mount('http://', adapter)
session.mount('https://', adapter)

response = session.get(url)

5. JSON 유효성 검사

jsonschema를 사용한 유효성 검사

API로부터 받는 JSON 데이터가 기대한 형식인지 확인하려면, jsonschema 라이브러리를 사용해 유효성 검사를 수행할 수 있습니다。
from jsonschema import validate, ValidationError

schema = {
    "type": "object",
    "properties": {
        "이름": {"type": "string"},
        "나이": {"type": "number"}
    },
    "required": ["이름", "나이"]
}

json_data = {"이름": "사토", "나이": 30}

try:
    validate(instance=json_data, schema=schema)
    print("JSON is valid")
except ValidationError as e:
    print("Validation Error:", e)
복잡한 스키마나 중첩된 객체도 처리할 수 있어, 이를 통해 API에서 오는 데이터를 확실하게 검증할 수 있습니다。

6. 보안에 관한 모범 사례

API 키 관리

API 키는 소스 코드에 하드코딩하지 말고, 환경 변수 등으로 관리하는 것이 권장됩니다. 이렇게 하면 보안 위험을 줄일 수 있습니다。
import os

api_key = os.getenv('API_KEY')

데이터 정제

사용자로부터 받은 입력 데이터를 서버로 전송하기 전에 적절한 정제 처리를 수행하면、SQL 인젝션이나 크로스 사이트 스크립팅(XSS)으로부터 보호할 수 있습니다。
from html import escape

safe_data = escape(user_input)
年収訴求