Workspace IndexDev Notes › Web stack layers

#143PoC

Web stack layers

A five-layer map of the stack, with this project overlaid on it.

Reference — docs/knowledge/web-stack-layers.html.

Why

An orientation map rather than a study: which layer each piece of this project actually lives at, and where the gaps are. Useful mostly for noticing that several cards which sound like different problems turn out to sit at the same layer — and that one or two layers have nothing on them at all.

How it works

A static five-layer diagram with the project's routes and demos placed on it. No code.

Related code

"""Web stack layers PoC -- a request flowing through a chain of middleware layers.
Illustrates the core mechanism: each layer wraps the next, adding something on the way
in and/or the way out, and the order in which layers run is visible in the output.
"""

from typing import Callable

Handler = Callable[[dict], dict]


def logging_layer(next_layer: Handler) -> Handler:
    def handle(request: dict) -> dict:
        print(f"  [logging]  in:  {request['path']}")
        response = next_layer(request)
        print(f"  [logging]  out: status={response['status']}")
        return response
    return handle


def auth_layer(next_layer: Handler) -> Handler:
    def handle(request: dict) -> dict:
        print(f"  [auth]     checking token for {request['path']}")
        request["user"] = "jay"
        return next_layer(request)
    return handle


def cache_layer(cache: dict) -> Callable[[Handler], Handler]:
    def wrap(next_layer: Handler) -> Handler:
        def handle(request: dict) -> dict:
            if request["path"] in cache:
                print(f"  [cache]    hit for {request['path']}")
                return cache[request["path"]]
            print(f"  [cache]    miss for {request['path']}")
            response = next_layer(request)
            cache[request["path"]] = response
            return response
        return handle
    return wrap


def app_layer(request: dict) -> dict:
    print(f"  [app]      handling {request['path']} for user={request.get('user')}")
    return {"status": 200, "body": f"hello, {request.get('user')}"}


if __name__ == "__main__":
    cache: dict = {}
    # Layers compose from the outside in: logging -> auth -> cache -> app.
    stack = logging_layer(auth_layer(cache_layer(cache)(app_layer)))

    print("request 1 (/profile):")
    stack({"path": "/profile"})

    print("\nrequest 2 (/profile again -- cache should hit):")
    stack({"path": "/profile"})

← All Dev Notes · Workspace Index · Top ↑

웹 스택 계층

스택의 5계층 지도 위에 이 프로젝트를 얹어 본 것.

참조 — docs/knowledge/web-stack-layers.html.

스터디라기보다 방향 지도입니다: 이 프로젝트의 각 조각이 실제로 어느 계층에 사는지, 그리고 빈 곳은 어디인지. 서로 다른 문제처럼 들리던 카드 여럿이 사실 같은 계층에 앉아 있다는 것, 그리고 어떤 계층은 아예 비어 있다는 것을 알아차리는 데 주로 쓸모가 있습니다.

동작 방식

프로젝트의 라우트와 데모를 얹은 정적 5계층 다이어그램. 코드는 없습니다.

관련 코드

"""Web stack layers PoC -- a request flowing through a chain of middleware layers.
Illustrates the core mechanism: each layer wraps the next, adding something on the way
in and/or the way out, and the order in which layers run is visible in the output.
"""

from typing import Callable

Handler = Callable[[dict], dict]


def logging_layer(next_layer: Handler) -> Handler:
    def handle(request: dict) -> dict:
        print(f"  [logging]  in:  {request['path']}")
        response = next_layer(request)
        print(f"  [logging]  out: status={response['status']}")
        return response
    return handle


def auth_layer(next_layer: Handler) -> Handler:
    def handle(request: dict) -> dict:
        print(f"  [auth]     checking token for {request['path']}")
        request["user"] = "jay"
        return next_layer(request)
    return handle


def cache_layer(cache: dict) -> Callable[[Handler], Handler]:
    def wrap(next_layer: Handler) -> Handler:
        def handle(request: dict) -> dict:
            if request["path"] in cache:
                print(f"  [cache]    hit for {request['path']}")
                return cache[request["path"]]
            print(f"  [cache]    miss for {request['path']}")
            response = next_layer(request)
            cache[request["path"]] = response
            return response
        return handle
    return wrap


def app_layer(request: dict) -> dict:
    print(f"  [app]      handling {request['path']} for user={request.get('user')}")
    return {"status": 200, "body": f"hello, {request.get('user')}"}


if __name__ == "__main__":
    cache: dict = {}
    # Layers compose from the outside in: logging -> auth -> cache -> app.
    stack = logging_layer(auth_layer(cache_layer(cache)(app_layer)))

    print("request 1 (/profile):")
    stack({"path": "/profile"})

    print("\nrequest 2 (/profile again -- cache should hit):")
    stack({"path": "/profile"})

← 전체 개발 노트 · 워크스페이스 인덱스 · 맨 위 ↑