Skip to content

routes

stac_fastapi.api.routes

Route factories.

Scope

Bases: TypedDict

More strict version of Starlette's Scope.

Source code in stac_fastapi/api/routes.py
81
82
83
84
85
86
87
class Scope(TypedDict, total=False):
    """More strict version of Starlette's Scope."""

    # https://github.com/encode/starlette/blob/6af5c515e0a896cbf3f86ee043b88f6c24200bcf/starlette/types.py#L3
    path: str
    method: str
    type: Optional[str]

add_direct_response

add_direct_response(app: FastAPI) -> None

Setup FastAPI application's endpoints to return Response Object directly, avoiding Pydantic validation and FastAPI (slow) serialization.

ref: gist.github.com/Zaczero/00f3a2679ebc0a25eb938ed82bc63553

Source code in stac_fastapi/api/routes.py
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
def add_direct_response(app: FastAPI) -> None:
    """
    Setup FastAPI application's endpoints to return Response Object directly, avoiding
    Pydantic validation and FastAPI (slow) serialization.

    ref: https://gist.github.com/Zaczero/00f3a2679ebc0a25eb938ed82bc63553
    """

    def wrap_endpoint(endpoint: Callable, cls: Type[Response]):
        @functools.wraps(endpoint)
        async def wrapper(*args, **kwargs):
            content = await endpoint(*args, **kwargs)
            return content if isinstance(content, Response) else cls(content)

        return wrapper

    for route in app.routes:
        if not isinstance(route, APIRoute):
            continue

        response_class = route.response_class
        if isinstance(response_class, DefaultPlaceholder):
            response_class = response_class.value

        if issubclass(response_class, Response):
            route.endpoint = wrap_endpoint(route.endpoint, response_class)
            route.dependant = get_dependant(path=route.path_format, call=route.endpoint)
            route.app = request_response(route.get_route_handler())

add_route_dependencies

add_route_dependencies(
    routes: List[BaseRoute], scopes: List[Scope], dependencies: List[Depends]
) -> None

Add dependencies to routes.

Allows a developer to add dependencies to a route after the route has been defined.

"*" can be used for path or method to match all allowed routes.

Returns:

  • None

    None

Source code in stac_fastapi/api/routes.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
def add_route_dependencies(
    routes: List[BaseRoute], scopes: List[Scope], dependencies: List[params.Depends]
) -> None:
    """Add dependencies to routes.

    Allows a developer to add dependencies to a route after the route has been
    defined.

    "*" can be used for path or method to match all allowed routes.

    Returns:
        None
    """
    for scope in scopes:
        _scope = copy.deepcopy(scope)
        for route in routes:
            if scope["path"] == "*":
                _scope["path"] = route.path

            if scope["method"] == "*":
                _scope["method"] = list(route.methods)[0]

            match, _ = route.matches({"type": "http", **_scope})
            if match != Match.FULL:
                continue

            # Ignore paths without dependants, e.g. /api, /api.html, /docs/oauth2-redirect
            if not hasattr(route, "dependant"):
                continue

            # Mimicking how APIRoute handles dependencies:
            # https://github.com/tiangolo/fastapi/blob/1760da0efa55585c19835d81afa8ca386036c325/fastapi/routing.py#L408-L412
            for depends in dependencies[::-1]:
                route.dependant.dependencies.insert(
                    0,
                    get_parameterless_sub_dependant(
                        depends=depends, path=route.path_format
                    ),
                )

            # Register dependencies directly on route so that they aren't ignored if
            # the routes are later associated with an app (e.g.
            # app.include_router(router))
            # https://github.com/tiangolo/fastapi/blob/58ab733f19846b4875c5b79bfb1f4d1cb7f4823f/fastapi/applications.py#L337-L360
            # https://github.com/tiangolo/fastapi/blob/58ab733f19846b4875c5b79bfb1f4d1cb7f4823f/fastapi/routing.py#L677-L678
            route.dependencies.extend(dependencies)

create_async_endpoint

create_async_endpoint(
    func: Callable, request_model: Union[Type[APIRequest], Type[BaseModel], Dict]
)

Wrap a function in a coroutine which may be used to create a FastAPI endpoint.

Synchronous functions are executed asynchronously using a background thread.

Source code in stac_fastapi/api/routes.py
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
def create_async_endpoint(
    func: Callable,
    request_model: Union[Type[APIRequest], Type[BaseModel], Dict],
):
    """Wrap a function in a coroutine which may be used to create a FastAPI endpoint.

    Synchronous functions are executed asynchronously using a background thread.
    """

    if not inspect.iscoroutinefunction(func):
        func = sync_to_async(func)

    if issubclass(request_model, APIRequest):

        async def _endpoint(
            request: Request,
            request_data: request_model = Depends(),  # type:ignore
        ):
            """Endpoint."""
            return _wrap_response(await func(request=request, **request_data.kwargs()))

    elif issubclass(request_model, BaseModel):

        async def _endpoint(
            request: Request,
            request_data: request_model,  # type:ignore
        ):
            """Endpoint."""
            return _wrap_response(await func(request_data, request=request))

    else:

        async def _endpoint(
            request: Request,
            request_data: Dict[str, Any],  # type:ignore
        ):
            """Endpoint."""
            return _wrap_response(await func(request_data, request=request))

    return _endpoint

sync_to_async

sync_to_async(func)

Run synchronous function asynchronously in a background thread.

Source code in stac_fastapi/api/routes.py
29
30
31
32
33
34
35
36
def sync_to_async(func):
    """Run synchronous function asynchronously in a background thread."""

    @functools.wraps(func)
    async def run(*args, **kwargs):
        return await run_in_threadpool(func, *args, **kwargs)

    return run