10.1. 첫 번째 엔드포인트¶
카메라가 흥미로운 일을 하기 전에, 먼저 네트워크의 나머지 부분이 카메라에 도달할 수 있어야 합니다. 서버가 살아 있음을 증명하는 가장 간단한 방법은 JSON을 반환하는 단일 경로 HTTP 엔드포인트입니다:
from microdot import Microdot
app = Microdot()
frame_count = 0
trigger_count = 0
@app.get('/status')
async def status(request):
return {'frames': frame_count, 'triggers': trigger_count}
app.run(host='0.0.0.0', port=80)
IDE에서 실행하세요. LAN의 다른 어떤 컴퓨터에서든 http://<cam-ip>/status 를 엽니다. 브라우저에는 다음이 표시됩니다:
{"frames": 0, "triggers": 0}
카운터는 자리표시자일 뿐이며 아직 아무것도 건드리지 않습니다. 하지만 요청이 네트워크를 건너갔고, 카메라가 이를 라우팅하고, 핸들러를 실행하고, JSON을 다시 보냈습니다.
10.1.1. 각 줄이 하는 일¶
스크립트당 하나의 microdot.Microdot 인스턴스를 둡니다. 이 인스턴스는 라우팅 테이블, 오류 핸들러, 그리고 생명주기(시작, 서비스, 중지)를 소유합니다. 큰 앱은 여러 Python 모듈로 나뉘지만 여전히 하나의 app 객체를 공유합니다.
@app.get('/status') 는 라우트 데코레이터입니다. 여기서는 microdot.Microdot.get() 만 사용합니다. post(), put(), delete() 는 카메라가 쓰기 작업을 받기 시작하는 이후 페이지에서 등장합니다.
모든 라우트 핸들러는 asyncio 코루틴이며 첫 번째 인자로 요청을 받습니다. 핸들러가 반드시 request 를 사용해야 하는 것은 아니지만(이 핸들러는 이를 무시합니다), 시그니처의 일관성을 위해 매개변수는 항상 존재합니다.
dict를 반환하는 것이 JSON을 보내는 가장 짧은 방법입니다. Microdot는 dict를 자동으로 JSON으로 직렬화하고 응답에 Content-Type: application/json 을 설정합니다. 문자열을 반환하면 text/plain 을 보냅니다. microdot.Response 를 명시적으로 반환하는 것이 긴 형식이며, 본문이 바이너리이거나 응답에 커스텀 헤더가 필요할 때 쓰입니다.
app.run(host='0.0.0.0', port=80) 가 서버를 시작합니다. 0.0.0.0 은 카메라가 가진 모든 인터페이스에서 수신 대기 한다는 뜻으로, 유선 이더넷과 wifi STA가 둘 다 켜져 있다면 둘 모두에서 수신합니다. 포트 80은 HTTP 기본값이므로 브라우저가 포트 번호를 입력할 필요가 없습니다.
10.1.2. 요청 하나, 처음부터 끝까지¶
휴대폰이 TCP 연결을 열고, 요청 라인과 헤더를 쓴 뒤 기다립니다. 카메라는 소켓에서 바이트를 읽어 microdot.Request 객체로 파싱하고, 경로와 메서드를 라우팅 테이블과 대조한 다음, 핸들러 코루틴을 await하고, 반환된 것이 무엇이든 직렬화하고, 상태 라인과 헤더와 본문을 다시 소켓으로 쓰고, 연결을 닫거나(HTTP/1.0 기본값) 재사용합니다(Connection: keep-alive 가 있는 HTTP/1.1). 전체 교환에 걸리는 시간은 네트워크 왕복 시간에 핸들러가 한 일을 더한 정도입니다.
10.1.3. 블로킹에 관한 참고 사항¶
run() 은 블로킹 입니다. 서버가 멈출 때까지 절대 반환하지 않습니다. 단일 목적 서버라면 괜찮습니다. 프레임도 캡처하거나 다른 코루틴도 실행하는 앱은 대신 asyncio.run() 안에서 start_server() 를 사용하여 HTTP 서버가 나머지 모든 것과 루프를 공유하도록 합니다.
앱이 하나의 URL에 응답합니다.