1 - | import misc.input
|
2 - | import misc.middleware
|
3 - | import misc.output
|
4 - | import misc.tls
|
5 - | import typing
|
6 - |
|
7 - | Ctx = typing.TypeVar('Ctx')
|
8 - |
|
9 - | class App(typing.Generic[Ctx]):
|
10 - | """
|
11 - | Main Python application, used to register operations and context and start multiple
|
12 - | workers on the same shared socket.
|
13 - |
|
14 - | Operations can be registered using the application object as a decorator (`@app.operation_name`).
|
15 - |
|
16 - | Here's a full example to get you started:
|
17 - |
|
18 - | ```python
|
19 - | from misc import input
|
20 - | from misc import output
|
21 - | from misc import error
|
22 - | from misc import middleware
|
23 - | from misc import App
|
24 - |
|
25 - | @dataclass
|
26 - | class Context:
|
27 - | counter: int = 0
|
28 - |
|
29 - | app = App()
|
30 - | app.context(Context())
|
31 - |
|
32 - | @app.request_middleware
|
33 - | def request_middleware(request: middleware::Request):
|
34 - | if request.get_header("x-amzn-id") != "secret":
|
35 - | raise middleware.MiddlewareException("Unsupported `x-amz-id` header", 401)
|
36 - |
|
37 - | @app.required_header_collection_operation
|
38 - | def required_header_collection_operation(input: input::RequiredHeaderCollectionOperationInput, ctx: Context) -> output::RequiredHeaderCollectionOperationOutput:
|
39 - | raise NotImplementedError
|
40 - |
|
41 - | # This operation tests that (de)serializing required values from a nested
|
42 - | # shape works correctly.
|
43 - | @app.required_inner_shape_operation
|
44 - | def required_inner_shape_operation(input: input::RequiredInnerShapeOperationInput, ctx: Context) -> output::RequiredInnerShapeOperationOutput:
|
45 - | raise NotImplementedError
|
46 - |
|
47 - | # This operation tests that the response code defaults to 200 when no other
|
48 - | # code is set.
|
49 - | @app.response_code_default_operation
|
50 - | def response_code_default_operation(input: input::ResponseCodeDefaultOperationInput, ctx: Context) -> output::ResponseCodeDefaultOperationOutput:
|
51 - | raise NotImplementedError
|
52 - |
|
53 - | # This operation tests that the response code defaults to `@http`'s code.
|
54 - | @app.response_code_http_fallback_operation
|
55 - | def response_code_http_fallback_operation(input: input::ResponseCodeHttpFallbackOperationInput, ctx: Context) -> output::ResponseCodeHttpFallbackOperationOutput:
|
56 - | raise NotImplementedError
|
57 - |
|
58 - | # This operation tests that `@httpResponseCode` is `@required`
|
59 - | # and is used over `@http's` code.
|
60 - | @app.response_code_required_operation
|
61 - | def response_code_required_operation(input: input::ResponseCodeRequiredOperationInput, ctx: Context) -> output::ResponseCodeRequiredOperationOutput:
|
62 - | raise NotImplementedError
|
63 - |
|
64 - | # An operation whose shapes generate complex Rust types.
|
65 - | # See https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity.
|
66 - | @app.type_complexity_operation
|
67 - | def type_complexity_operation(input: input::TypeComplexityOperationInput, ctx: Context) -> output::TypeComplexityOperationOutput:
|
68 - | raise NotImplementedError
|
69 - |
|
70 - | app.run()
|
71 - | ```
|
72 - |
|
73 - | Any of operations above can be written as well prepending the `async` keyword and
|
74 - | the Python application will automatically handle it and schedule it on the event loop for you.
|
75 - | """
|
76 - |
|
77 - | def context(self, context: Ctx) -> None:
|
78 - | """
|
79 - | Register a context object that will be shared between handlers.
|
80 - | """
|
81 - | ...
|
82 - |
|
83 - |
|
84 - | def middleware(self, func: typing.Callable[[misc.middleware.Request, typing.Callable[[misc.middleware.Request], typing.Awaitable[misc.middleware.Response]]], typing.Awaitable[misc.middleware.Response]]) -> None:
|
85 - | """
|
86 - | Register a Python function to be executed inside a Tower middleware layer.
|
87 - | """
|
88 - | ...
|
89 - |
|
90 - |
|
91 - | def required_header_collection_operation(self, func: typing.Union[typing.Callable[[misc.input.RequiredHeaderCollectionOperationInput, Ctx], typing.Union[misc.output.RequiredHeaderCollectionOperationOutput, typing.Awaitable[misc.output.RequiredHeaderCollectionOperationOutput]]], typing.Callable[[misc.input.RequiredHeaderCollectionOperationInput], typing.Union[misc.output.RequiredHeaderCollectionOperationOutput, typing.Awaitable[misc.output.RequiredHeaderCollectionOperationOutput]]]]) -> None:
|
92 - | """
|
93 - | Method to register `required_header_collection_operation` Python implementation inside the handlers map.
|
94 - | It can be used as a function decorator in Python.
|
95 - | """
|
96 - | ...
|
97 - |
|
98 - |
|
99 - | def required_inner_shape_operation(self, func: typing.Union[typing.Callable[[misc.input.RequiredInnerShapeOperationInput, Ctx], typing.Union[misc.output.RequiredInnerShapeOperationOutput, typing.Awaitable[misc.output.RequiredInnerShapeOperationOutput]]], typing.Callable[[misc.input.RequiredInnerShapeOperationInput], typing.Union[misc.output.RequiredInnerShapeOperationOutput, typing.Awaitable[misc.output.RequiredInnerShapeOperationOutput]]]]) -> None:
|
100 - | """
|
101 - | Method to register `required_inner_shape_operation` Python implementation inside the handlers map.
|
102 - | It can be used as a function decorator in Python.
|
103 - | """
|
104 - | ...
|
105 - |
|
106 - |
|
107 - | def response_code_default_operation(self, func: typing.Union[typing.Callable[[misc.input.ResponseCodeDefaultOperationInput, Ctx], typing.Union[misc.output.ResponseCodeDefaultOperationOutput, typing.Awaitable[misc.output.ResponseCodeDefaultOperationOutput]]], typing.Callable[[misc.input.ResponseCodeDefaultOperationInput], typing.Union[misc.output.ResponseCodeDefaultOperationOutput, typing.Awaitable[misc.output.ResponseCodeDefaultOperationOutput]]]]) -> None:
|
108 - | """
|
109 - | Method to register `response_code_default_operation` Python implementation inside the handlers map.
|
110 - | It can be used as a function decorator in Python.
|
111 - | """
|
112 - | ...
|
113 - |
|
114 - |
|
115 - | def response_code_http_fallback_operation(self, func: typing.Union[typing.Callable[[misc.input.ResponseCodeHttpFallbackOperationInput, Ctx], typing.Union[misc.output.ResponseCodeHttpFallbackOperationOutput, typing.Awaitable[misc.output.ResponseCodeHttpFallbackOperationOutput]]], typing.Callable[[misc.input.ResponseCodeHttpFallbackOperationInput], typing.Union[misc.output.ResponseCodeHttpFallbackOperationOutput, typing.Awaitable[misc.output.ResponseCodeHttpFallbackOperationOutput]]]]) -> None:
|
116 - | """
|
117 - | Method to register `response_code_http_fallback_operation` Python implementation inside the handlers map.
|
118 - | It can be used as a function decorator in Python.
|
119 - | """
|
120 - | ...
|
121 - |
|
122 - |
|
123 - | def response_code_required_operation(self, func: typing.Union[typing.Callable[[misc.input.ResponseCodeRequiredOperationInput, Ctx], typing.Union[misc.output.ResponseCodeRequiredOperationOutput, typing.Awaitable[misc.output.ResponseCodeRequiredOperationOutput]]], typing.Callable[[misc.input.ResponseCodeRequiredOperationInput], typing.Union[misc.output.ResponseCodeRequiredOperationOutput, typing.Awaitable[misc.output.ResponseCodeRequiredOperationOutput]]]]) -> None:
|
124 - | """
|
125 - | Method to register `response_code_required_operation` Python implementation inside the handlers map.
|
126 - | It can be used as a function decorator in Python.
|
127 - | """
|
128 - | ...
|
129 - |
|
130 - |
|
131 - | def run(self, address: typing.Optional[str] = ..., port: typing.Optional[int] = ..., backlog: typing.Optional[int] = ..., workers: typing.Optional[int] = ..., tls: typing.Optional[misc.tls.TlsConfig] = ...) -> None:
|
132 - | """
|
133 - | Main entrypoint: start the server on multiple workers.
|
134 - | """
|
135 - | ...
|
136 - |
|
137 - |
|
138 - | def run_lambda(self) -> None:
|
139 - | """
|
140 - | Lambda entrypoint: start the server on Lambda.
|
141 - | """
|
142 - | ...
|
143 - |
|
144 - |
|
145 - | def start_worker(self) -> None:
|
146 - | """
|
147 - | Build the service and start a single worker.
|
148 - | """
|
149 - | ...
|
150 - |
|
151 - |
|
152 - | def type_complexity_operation(self, func: typing.Union[typing.Callable[[misc.input.TypeComplexityOperationInput, Ctx], typing.Union[misc.output.TypeComplexityOperationOutput, typing.Awaitable[misc.output.TypeComplexityOperationOutput]]], typing.Callable[[misc.input.TypeComplexityOperationInput], typing.Union[misc.output.TypeComplexityOperationOutput, typing.Awaitable[misc.output.TypeComplexityOperationOutput]]]]) -> None:
|
153 - | """
|
154 - | Method to register `type_complexity_operation` Python implementation inside the handlers map.
|
155 - | It can be used as a function decorator in Python.
|
156 - | """
|
157 - | ...
|
158 - |
|
159 - |
|
160 - | def __init__(self) -> None:
|
161 - | ...
|
162 - |
|
163 - |
|
164 - | CODEGEN_VERSION: str = ...
|