[python] json-server, requests module
A A

목차

    728x90

     

    json-server

    JSON을 정보 전달의 순단으로 사용하기 위해서는 

    웹 서비스를 제공하는 서버가 필요하고, 서비스와 통신할 수있는 socket모듈 보다 더 간단한 도구가 필요하다.

    socket 모듈의 경우 너무 까다롭고 또 강력하다.

    socket 모듈은 TCP 수준에서 네트워크 문제를 이해하고 OS가 인터넷 연결을 설정, 유지, 종료를 할 때 사용하기 좋은  모듈이다.

    하지만, 웹 서비스와 간단하게 대화하기 위한 용도의 사용으로는 socket이 복잡성을 가지고, 너무 크다.

     

    이러한 니즈를 충족하기 위해 우리는 RESTful API 기반으로 수행하는 HTTP 서버가 필요하다.

    Node.js 환경으로 구현된 무료이고, 오픈 패키지로 json-server를 사용한다. 

    브라우저 외부에서 JavaScript 코드를 실행하는 오픈 소스 플랫폼 Node.js.의 환경으로 JavaScript를 접하게 되지만,

    코드를 작성하지 않아도 된다.

    너무 걱정할 필요 없이 시작해보도록 하자.

     

    먼저 Node.js가 설치되어야 한다. 설치단계는 사용하는 OS에 따라 다르다.

    http://nodejs.org/en/download

     

    Node.js — Download Node.js®

    Node.js® is a free, open-source, cross-platform JavaScript runtime environment that lets developers create servers, web apps, command line tools and scripts.

    nodejs.org

     

    Windows 사용자라면 cmd를 , linux나 macOS 사용자라면 선호하는 터미널 에뮬레이터를 실행한다.

    참고로 관리자 권한이 필요할 수 있다.

     

    npm

    Node.js 구성요소를 설치하고 업데이트하기 위해 자체 도구를 사용하는데 모든 플랫폼에서 이름이 동일하므로

    해당 명령어를 실행한다.

    해당 명령어를 실행시에 짧은 도움말 화면이 표시되는 것을 볼 수 있다.

     

    npm install -g json-server

    npm을 통해 json-server 패키지를 설치한다.

    패키지를 실행하는 데 필요한 모든 패키지들을 함께 다운로드 해야하므로 약간의 지연이 발생할 수 있다.

     

    json 샘플 파일을 하나 만들고, 홈 디렉토리나 쓰기 권한이 있는 다른 디렉토리에 저장한다.

    https://microsoftedge.github.io/Demos/json-dummy-data/

     

    JSON dummy data

    Web pages and apps used to demo various DevTools, PWA, WebView, Extensions, and Web Platform features of Microsoft Edge

    microsoftedge.github.io

    (JSON 샘플 파일)

    import json,os
    
    # Python 딕셔너리 및 리스트로 데이터 구성
    cars_data = {
        "cars": [
            {
                "id": 1,
                "brand": "Ford",
                "model": "Mustang",
                "production_year": 1972,
                "price": {
                    "currency": "USD",
                    "value": 35900
                }
            },
            {
                "id": 2,
                "brand": "Aston Martin",
                "model": "Rapide",
                "production_year": 2010,
                "price": {
                    "currency": "GBP",
                    "value": 32000
                }
            },
            {
                "id": 3,
                "brand": "Audi",
                "model": "A4",
                "production_year": 2018,
                "price": {
                    "currency": "EUR",
                    "value": 45000
                }
            },
            {
                "id": 4,
                "brand": "Tesla",
                "model": "Model S",
                "production_year": 2020,
                "price": {
                    "currency": "USD",
                    "value": 70000
                }
            },
            {
                "id": 5,
                "brand": "BMW",
                "model": "M3",
                "production_year": 2022,
                "price": {
                    "currency": "EUR",
                    "value": 80000
                }
            }
        ]
    }
    
    # JSON 파일로 저장
    
    # 저장할 디렉토리 경로 정의
    output_dir = 'resources'
    output_file_path = os.path.join(output_dir, 'cars.json')
    
    # indent=4는 가독성을 위해 들여쓰기를 4칸으로 설정
    with open(output_file_path, 'w', encoding='utf-8') as f:
        json.dump(cars_data, f, indent=4, ensure_ascii=False)
    
    print("cars.json 파일이 성공적으로 생성되었습니다.")
    
    # 생성된 JSON 파일 내용 확인
    try:
        with open(output_file_path, 'r', encoding='utf-8') as f:
            print("\n--- cars.json 내용 ---")
            print(f.read())
            print("--------------------")
    except FileNotFoundError:
        print(f"오류: '{output_file_path}' 파일을 찾을 수 없습니다. 경로를 다시 확인해주세요.")
    except Exception as e:
        print(f"파일을 읽는 중 오류 발생: {e}")

     

    json-server --watch resources/cars.json

    뒤에 json 파일 경로를 지정한다.

     

    모든 것이 바르게 지정되었다면 

    Watching... 

    이라는 문구가 뜨며 이는 서버가 작동중이고 수신 연결을 처리할 준비가 되었다는 의미다.

    이제 http://localhost:3000 을 열어보면 JSON Server 페이지가 열리고, 이는 서버가 정상적으로 작동한 것이다.

    만약 터미널에서 실행했다면 서버를 종료하기 위해서는 Ctrl + C 를 눌러 종료할 수 있다.

    터미널 실행이 아닌, 다른 노트북환경에서 실행한 경우 터미널 창을 열어 3000포트의 프로세스를 찾아 종료한다.

    >netstat -ano | findstr :3000
      TCP    0.0.0.0:3000           0.0.0.0:0              LISTENING       17292
      TCP    [::]:3000              [::]:0                 LISTENING       17292
    
    >taskkill /PID 17292 /F
    성공: 프로세스(PID 17292)가 종료되었습니다.

     

     

    requests 모듈

    첫번째로 살펴볼 requests 모듈은 아주 기본적으로 활용한다.

    import requests
    
    reponse = requests.get('https://www.google.com')
    print(reponse.status_code)
    200

     

    HTTP 프로토콜은 메소드를 이용하여 작동한다.

    HTTP 메소드는 클라이언트와 서버간의 양방양 상호작용(물론 클라이언트가 전송을 시작.)으로 특정 동작을 실행하는데 사용한다.

    GET 메소드는 이러한 상호작용중 하나로, 클라이언트가 요청한 리소스를 서버에게 전송하도록 유도하는 데 사용된다.

     

    requests의get()이라는 함수가 HTTP GET 메서드를 실행하여 서버의 응답을 받는다.

    보다시피 코드는 간단하고 간결하다.

    socket처럼 복잡한 상수, 기호, 함수, 개념을 다룰 필요가 없다.

     

    브라우저 주소창을 사용할 때와 마찬가지로 서버주소와 서비스 포트번호만 제공하면된다.

    포트번호의 경우 HTTP 기본 포트인 80 일 경우 생략이 가능하다.

     

    get()을 통해 응답결과를 반환한다. 해당 객체는 HTTP GET 메서드 실행에 대한 모든 정보를 가지고 있다.

    물론 가장 중요한 것은 성공여부이다. 

    성공여부를 알기 위해 status_code를 통해 확인할 수 있다.

    import requests
    
    # 응답 코드 확인 
    print(requests.codes.__dict__)

    https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status

     

    HTTP response status codes - HTTP | MDN

    HTTP response status codes indicate whether a specific HTTP request has been successfully completed. Responses are grouped in five classes:

    developer.mozilla.org

     

     

    code 상태 코드를 정수값과 비교하는 것 보다 아래와 같이 변경하면 더욱 더 이해를 도울 수 있다.

    import requests
    
    
    reponse = requests.get('https://www.google.com')
    if response.status_code == requests.codes.ok:
        print('정상입니다.')
    else:
        print('문제가 생겼습니다.', response.status_code)

    숫자 200 으로 표현되는 것 보다 훨씬 나아보인다.

     

    이제 응답(response) 객체에 대해 살펴보도록 하자.

    • response.headers
    import requests
    
    
    reponse = requests.get('https://www.google.com')
    print(response.headers)

    보기 어려운 관계로

    import requests
    
    reponse = requests.get('https://www.google.com')
    headers = response.headers
    for key, value in headers.items():
      print(f"-- {key} : {value}")

    보다 시피 응답 헤더는 연관된 값을 여러 필드로 구성되어 있고,

    대부분은 중요하지 않지만 Content-Type의 경우 중요하다.

    딕셔너리형태의 검색을 통해 직접 액세스 할 수 있다.

    import requests
    
    
    reponse = requests.get('https://www.google.com')
    content_type = response.headers['Content-Type']
    print(content_type)
    text/html; charset=ISO-8859-1

     

    • response.text
    import requests
    
    
    reponse = requests.get('https://www.google.com')
    text = response.text
    print(text)

    text 속성은 데이터 스트림에서 그대로 가져온 텍스트를 포함하는 문자열로 변환은 적용되지 않는다.

     

     

    참고로 클라이언트와 서버 모두 컨텐츠에 JSON 메세지가 포함되어 있다는 사실을 알 경우

    딕셔너리 형태를 반환하는 json() 이라는 메서드를 사용할 수도 있다.

     

     

    HTTP method

    GET

    GET은 서버에 정보를 가져오는 것을 목적으로 한다.

    물론 간단한 서버는 두 개 이상의 리소스를 제공하므로 GET 방법은

    클라이언트가 요구사항을 정확하게 지정할 수 있는 수단을 제공한다.

    클라이언트에 요구사항이 없고, 리소스 식별 없이 시작하면 서버에 응답은 루트 문서가 포함된다.

    이는 위의 예제에서 response.text를 확인했던 것과 같다.

    즉, 서버에게 "뭔가를 줘 !"라고 요청하는 방법이다.

    POST

    POST도 GET과 같이 리소스를 전송하는 데 사용되지만,

    목표를 반대로 클라이언트에서 서버로 전송하는 것을 한다.

    GET과 마찬가지로 리소스의 식별 정보를 제공해야한다.

    또한 클라이언트가 보내는 리소스는 서버에 새로운 리소스라고 가정하고, 이전에 수집된 데이터를 대체하거나 덮어 쓰지 않는다.

    즉, 서버에 새로운 것을 주고 싶다면 POST 요청을 한다.

    PUT

    POST와 유사하게 클라이언트에서 서버로 리소스를 전송하지만 의도가 다르다.

    전송되는 리소스는 이전에 저장된 데이터를 대체하기 위한것이다.

    즉, 서버가 현재 가지고 있는 것을 업데이트 하고 싶다면 PUT 요청을 한다.

    DELETE

    메서드 이름에 목적이 담겨있따.

    서버에서 지정된 식별자에서 리소스를 제거하도록 명령하는데 사용하고,

    이후 해당 리소스를 더이상 사용할 수 없다.

     

     

    requests의 예외

    만약 서버에 장애가 발생하거나, 전송 매체가 다운되는 등 여러가지 일이 일어날 수 있다.

    requests 모듈은 통신 문제가 발생하면 예외를 발생시키려는 경향이 있지만,

    일부 문제는 또 다른 형태로 나타난다.

     

    • request.exceptions.Timeout

    서버가 즉시 응답하지 않는 일은 정상이다.

    연결 -> 데이터전송 -> 리소스 검색 등 모든 단계에서 시간이 걸린다.

    하지만, 우리 인내심의 한계가 있다.

    보통 얼마나 기다릴지, 더이상 기다리고 싶지 않을지 알수 있다.

    이에 대한 시간 값을 넣어, 요청에 대한 timeout을 지정할 수 있다.

    #timeout= 1
    import requests
    
    
    try:
      response = requests.get('https://www.google.com', timeout=1)
    except requests.exceptions.Timeout:
      print('timeout')
    else:
      print(response.status_code)
    200
    #timeout= 0.00001
    import requests
    
    
    try:
      response = requests.get('https://www.google.com', timeout=0.00001)
    except requests.exceptions.Timeout:
      print('timeout')
    else:
      print(response.status_code)
    timeout

     

    해당 시간에 응답을 못받을 경우 위의 처럼 exception이 일어나면서

    그에 대한 대응을 마련한다.

    • requests.exceptions.ConnectionError
    import requests
    
    
    try:
      response = requests.get('https://www.google.com:4000', timeout=5)
    except requests.exceptions.ConnectionError:
      print('ConnectionError')
    else:
      print(response.status_code)
    ConnectionError

    또한 서버가 기다리는 포트가 아닌 다른 포트로 접근을 시도하려고 할 경우

    클라이언트와 서버가 만나지 못해 request.exceptions.ConnectionError의 이름으로 예외가 발생한다.

     

    • reqests.exceptions.InvalidURL
    import requests
    
    
    try:
      response = requests.get('https://///')
    except requests.exceptions.InvalidURL:
      print('InvalidURL')
    else:
      print(response.status_code)
    invalidURL

    리소스 URL을 다소 잘못된 형태로 기입하는 경우 다음과 같은 예외가 발생한다.

     

    'Developer > Python' 카테고리의 다른 글

    [python] SQLite, sqlite3을 활용한 CRUD  (1) 2025.07.14
    [python] requests CRUD  (3) 2025.07.14
    [python] XML , XML 모듈  (0) 2025.07.13
    [python] JSON, JSON 모듈  (6) 2025.07.12
    [python] socket  (1) 2025.07.12
    Copyright 2024. GRAVITY all rights reserved