spakky-fastapi 1.7.0__py3-none-any.whl → 2.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,508 +1,10 @@
1
- from enum import Enum
2
- from typing import Any, Callable, Sequence, TypeAlias
3
1
  from dataclasses import dataclass
2
+ from enum import Enum
4
3
 
5
- from fastapi import Response, params
6
- from fastapi.responses import JSONResponse
7
- from fastapi.routing import APIRoute
8
- from spakky.core.annotation import FunctionAnnotation
9
- from spakky.core.types import FuncT
10
4
  from spakky.stereotype.controller import Controller
11
- from starlette.routing import Route as StarletteRoute
12
-
13
- SetIntStr: TypeAlias = set[int | str]
14
- DictIntStrAny: TypeAlias = dict[int | str, Any]
15
-
16
-
17
- class HTTPMethod(str, Enum):
18
- GET = "GET"
19
- POST = "POST"
20
- PUT = "PUT"
21
- PATCH = "PATCH"
22
- DELETE = "DELETE"
23
- HEAD = "HEAD"
24
- OPTIONS = "OPTIONS"
25
- TRACE = "TRACE"
26
-
27
- def __repr__(self) -> str:
28
- return self.value
29
-
30
-
31
- @dataclass
32
- class Route(FunctionAnnotation):
33
- path: str
34
- response_model: type[Any] | None = None
35
- status_code: int | None = None
36
- tags: list[str] | None = None
37
- dependencies: Sequence[params.Depends] | None = None
38
- summary: str | None = None
39
- description: str | None = None
40
- response_description: str = "Successful Response"
41
- responses: dict[int | str, dict[str, Any]] | None = None
42
- deprecated: bool | None = None
43
- methods: set[HTTPMethod] | list[HTTPMethod] | None = None
44
- operation_id: str | None = None
45
- response_model_include: SetIntStr | DictIntStrAny | None = None
46
- response_model_exclude: SetIntStr | DictIntStrAny | None = None
47
- response_model_by_alias: bool = True
48
- response_model_exclude_unset: bool = False
49
- response_model_exclude_defaults: bool = False
50
- response_model_exclude_none: bool = False
51
- include_in_schema: bool = True
52
- response_class: type[Response] = JSONResponse
53
- name: str | None = None
54
- route_class_override: type[APIRoute] | None = None
55
- callbacks: list[StarletteRoute] | None = None
56
- openapi_extra: dict[str, Any] | None = None
57
-
58
-
59
- @dataclass
60
- class WebSocketRoute(FunctionAnnotation):
61
- path: str
62
- name: str | None = None
63
- dependencies: Sequence[params.Depends] | None = None
64
-
65
-
66
- def route(
67
- path: str,
68
- response_model: type[Any] | None = None,
69
- status_code: int | None = None,
70
- tags: list[str] | None = None,
71
- dependencies: Sequence[params.Depends] | None = None,
72
- summary: str | None = None,
73
- description: str | None = None,
74
- response_description: str = "Successful Response",
75
- responses: dict[int | str, dict[str, Any]] | None = None,
76
- deprecated: bool | None = None,
77
- methods: set[HTTPMethod] | list[HTTPMethod] | None = None,
78
- operation_id: str | None = None,
79
- response_model_include: SetIntStr | DictIntStrAny | None = None,
80
- response_model_exclude: SetIntStr | DictIntStrAny | None = None,
81
- response_model_by_alias: bool = True,
82
- response_model_exclude_unset: bool = False,
83
- response_model_exclude_defaults: bool = False,
84
- response_model_exclude_none: bool = False,
85
- include_in_schema: bool = True,
86
- response_class: type[Response] = JSONResponse,
87
- name: str | None = None,
88
- route_class_override: type[APIRoute] | None = None,
89
- callbacks: list[StarletteRoute] | None = None,
90
- openapi_extra: dict[str, Any] | None = None,
91
- ) -> Callable[[FuncT], FuncT]:
92
- def wrapper(method: FuncT) -> FuncT:
93
- return Route(
94
- path=path,
95
- response_model=response_model,
96
- status_code=status_code,
97
- tags=tags,
98
- dependencies=dependencies,
99
- summary=summary,
100
- description=description,
101
- response_description=response_description,
102
- responses=responses,
103
- deprecated=deprecated,
104
- methods=methods,
105
- operation_id=operation_id,
106
- response_model_include=response_model_include,
107
- response_model_exclude=response_model_exclude,
108
- response_model_by_alias=response_model_by_alias,
109
- response_model_exclude_unset=response_model_exclude_unset,
110
- response_model_exclude_defaults=response_model_exclude_defaults,
111
- response_model_exclude_none=response_model_exclude_none,
112
- include_in_schema=include_in_schema,
113
- response_class=response_class,
114
- name=name,
115
- route_class_override=route_class_override,
116
- callbacks=callbacks,
117
- openapi_extra=openapi_extra,
118
- )(method)
119
-
120
- return wrapper
121
-
122
-
123
- def get(
124
- path: str,
125
- response_model: type[Any] | None = None,
126
- status_code: int | None = None,
127
- tags: list[str] | None = None,
128
- dependencies: Sequence[params.Depends] | None = None,
129
- summary: str | None = None,
130
- description: str | None = None,
131
- response_description: str = "Successful Response",
132
- responses: dict[int | str, dict[str, Any]] | None = None,
133
- deprecated: bool | None = None,
134
- operation_id: str | None = None,
135
- response_model_include: SetIntStr | DictIntStrAny | None = None,
136
- response_model_exclude: SetIntStr | DictIntStrAny | None = None,
137
- response_model_by_alias: bool = True,
138
- response_model_exclude_unset: bool = False,
139
- response_model_exclude_defaults: bool = False,
140
- response_model_exclude_none: bool = False,
141
- include_in_schema: bool = True,
142
- response_class: type[Response] = JSONResponse,
143
- name: str | None = None,
144
- route_class_override: type[APIRoute] | None = None,
145
- callbacks: list[StarletteRoute] | None = None,
146
- openapi_extra: dict[str, Any] | None = None,
147
- ) -> Callable[[FuncT], FuncT]:
148
- return route(
149
- path=path,
150
- methods=[HTTPMethod.GET],
151
- response_model=response_model,
152
- status_code=status_code,
153
- tags=tags,
154
- dependencies=dependencies,
155
- summary=summary,
156
- description=description,
157
- response_description=response_description,
158
- responses=responses,
159
- deprecated=deprecated,
160
- operation_id=operation_id,
161
- response_model_include=response_model_include,
162
- response_model_exclude=response_model_exclude,
163
- response_model_by_alias=response_model_by_alias,
164
- response_model_exclude_unset=response_model_exclude_unset,
165
- response_model_exclude_defaults=response_model_exclude_defaults,
166
- response_model_exclude_none=response_model_exclude_none,
167
- include_in_schema=include_in_schema,
168
- response_class=response_class,
169
- name=name,
170
- route_class_override=route_class_override,
171
- callbacks=callbacks,
172
- openapi_extra=openapi_extra,
173
- )
174
-
175
-
176
- def post(
177
- path: str,
178
- response_model: type[Any] | None = None,
179
- status_code: int | None = None,
180
- tags: list[str] | None = None,
181
- dependencies: Sequence[params.Depends] | None = None,
182
- summary: str | None = None,
183
- description: str | None = None,
184
- response_description: str = "Successful Response",
185
- responses: dict[int | str, dict[str, Any]] | None = None,
186
- deprecated: bool | None = None,
187
- operation_id: str | None = None,
188
- response_model_include: SetIntStr | DictIntStrAny | None = None,
189
- response_model_exclude: SetIntStr | DictIntStrAny | None = None,
190
- response_model_by_alias: bool = True,
191
- response_model_exclude_unset: bool = False,
192
- response_model_exclude_defaults: bool = False,
193
- response_model_exclude_none: bool = False,
194
- include_in_schema: bool = True,
195
- response_class: type[Response] = JSONResponse,
196
- name: str | None = None,
197
- route_class_override: type[APIRoute] | None = None,
198
- callbacks: list[StarletteRoute] | None = None,
199
- openapi_extra: dict[str, Any] | None = None,
200
- ) -> Callable[[FuncT], FuncT]:
201
- return route(
202
- path=path,
203
- methods=[HTTPMethod.POST],
204
- response_model=response_model,
205
- status_code=status_code,
206
- tags=tags,
207
- dependencies=dependencies,
208
- summary=summary,
209
- description=description,
210
- response_description=response_description,
211
- responses=responses,
212
- deprecated=deprecated,
213
- operation_id=operation_id,
214
- response_model_include=response_model_include,
215
- response_model_exclude=response_model_exclude,
216
- response_model_by_alias=response_model_by_alias,
217
- response_model_exclude_unset=response_model_exclude_unset,
218
- response_model_exclude_defaults=response_model_exclude_defaults,
219
- response_model_exclude_none=response_model_exclude_none,
220
- include_in_schema=include_in_schema,
221
- response_class=response_class,
222
- name=name,
223
- route_class_override=route_class_override,
224
- callbacks=callbacks,
225
- openapi_extra=openapi_extra,
226
- )
227
-
228
-
229
- def put(
230
- path: str,
231
- response_model: type[Any] | None = None,
232
- status_code: int | None = None,
233
- tags: list[str] | None = None,
234
- dependencies: Sequence[params.Depends] | None = None,
235
- summary: str | None = None,
236
- description: str | None = None,
237
- response_description: str = "Successful Response",
238
- responses: dict[int | str, dict[str, Any]] | None = None,
239
- deprecated: bool | None = None,
240
- operation_id: str | None = None,
241
- response_model_include: SetIntStr | DictIntStrAny | None = None,
242
- response_model_exclude: SetIntStr | DictIntStrAny | None = None,
243
- response_model_by_alias: bool = True,
244
- response_model_exclude_unset: bool = False,
245
- response_model_exclude_defaults: bool = False,
246
- response_model_exclude_none: bool = False,
247
- include_in_schema: bool = True,
248
- response_class: type[Response] = JSONResponse,
249
- name: str | None = None,
250
- route_class_override: type[APIRoute] | None = None,
251
- callbacks: list[StarletteRoute] | None = None,
252
- openapi_extra: dict[str, Any] | None = None,
253
- ) -> Callable[[FuncT], FuncT]:
254
- return route(
255
- path=path,
256
- methods=[HTTPMethod.PUT],
257
- response_model=response_model,
258
- status_code=status_code,
259
- tags=tags,
260
- dependencies=dependencies,
261
- summary=summary,
262
- description=description,
263
- response_description=response_description,
264
- responses=responses,
265
- deprecated=deprecated,
266
- operation_id=operation_id,
267
- response_model_include=response_model_include,
268
- response_model_exclude=response_model_exclude,
269
- response_model_by_alias=response_model_by_alias,
270
- response_model_exclude_unset=response_model_exclude_unset,
271
- response_model_exclude_defaults=response_model_exclude_defaults,
272
- response_model_exclude_none=response_model_exclude_none,
273
- include_in_schema=include_in_schema,
274
- response_class=response_class,
275
- name=name,
276
- route_class_override=route_class_override,
277
- callbacks=callbacks,
278
- openapi_extra=openapi_extra,
279
- )
280
-
281
-
282
- def patch(
283
- path: str,
284
- response_model: type[Any] | None = None,
285
- status_code: int | None = None,
286
- tags: list[str] | None = None,
287
- dependencies: Sequence[params.Depends] | None = None,
288
- summary: str | None = None,
289
- description: str | None = None,
290
- response_description: str = "Successful Response",
291
- responses: dict[int | str, dict[str, Any]] | None = None,
292
- deprecated: bool | None = None,
293
- operation_id: str | None = None,
294
- response_model_include: SetIntStr | DictIntStrAny | None = None,
295
- response_model_exclude: SetIntStr | DictIntStrAny | None = None,
296
- response_model_by_alias: bool = True,
297
- response_model_exclude_unset: bool = False,
298
- response_model_exclude_defaults: bool = False,
299
- response_model_exclude_none: bool = False,
300
- include_in_schema: bool = True,
301
- response_class: type[Response] = JSONResponse,
302
- name: str | None = None,
303
- route_class_override: type[APIRoute] | None = None,
304
- callbacks: list[StarletteRoute] | None = None,
305
- openapi_extra: dict[str, Any] | None = None,
306
- ) -> Callable[[FuncT], FuncT]:
307
- return route(
308
- path=path,
309
- methods=[HTTPMethod.PATCH],
310
- response_model=response_model,
311
- status_code=status_code,
312
- tags=tags,
313
- dependencies=dependencies,
314
- summary=summary,
315
- description=description,
316
- response_description=response_description,
317
- responses=responses,
318
- deprecated=deprecated,
319
- operation_id=operation_id,
320
- response_model_include=response_model_include,
321
- response_model_exclude=response_model_exclude,
322
- response_model_by_alias=response_model_by_alias,
323
- response_model_exclude_unset=response_model_exclude_unset,
324
- response_model_exclude_defaults=response_model_exclude_defaults,
325
- response_model_exclude_none=response_model_exclude_none,
326
- include_in_schema=include_in_schema,
327
- response_class=response_class,
328
- name=name,
329
- route_class_override=route_class_override,
330
- callbacks=callbacks,
331
- openapi_extra=openapi_extra,
332
- )
333
-
334
-
335
- def delete(
336
- path: str,
337
- response_model: type[Any] | None = None,
338
- status_code: int | None = None,
339
- tags: list[str] | None = None,
340
- dependencies: Sequence[params.Depends] | None = None,
341
- summary: str | None = None,
342
- description: str | None = None,
343
- response_description: str = "Successful Response",
344
- responses: dict[int | str, dict[str, Any]] | None = None,
345
- deprecated: bool | None = None,
346
- operation_id: str | None = None,
347
- response_model_include: SetIntStr | DictIntStrAny | None = None,
348
- response_model_exclude: SetIntStr | DictIntStrAny | None = None,
349
- response_model_by_alias: bool = True,
350
- response_model_exclude_unset: bool = False,
351
- response_model_exclude_defaults: bool = False,
352
- response_model_exclude_none: bool = False,
353
- include_in_schema: bool = True,
354
- response_class: type[Response] = JSONResponse,
355
- name: str | None = None,
356
- route_class_override: type[APIRoute] | None = None,
357
- callbacks: list[StarletteRoute] | None = None,
358
- openapi_extra: dict[str, Any] | None = None,
359
- ) -> Callable[[FuncT], FuncT]:
360
- return route(
361
- path=path,
362
- methods=[HTTPMethod.DELETE],
363
- response_model=response_model,
364
- status_code=status_code,
365
- tags=tags,
366
- dependencies=dependencies,
367
- summary=summary,
368
- description=description,
369
- response_description=response_description,
370
- responses=responses,
371
- deprecated=deprecated,
372
- operation_id=operation_id,
373
- response_model_include=response_model_include,
374
- response_model_exclude=response_model_exclude,
375
- response_model_by_alias=response_model_by_alias,
376
- response_model_exclude_unset=response_model_exclude_unset,
377
- response_model_exclude_defaults=response_model_exclude_defaults,
378
- response_model_exclude_none=response_model_exclude_none,
379
- include_in_schema=include_in_schema,
380
- response_class=response_class,
381
- name=name,
382
- route_class_override=route_class_override,
383
- callbacks=callbacks,
384
- openapi_extra=openapi_extra,
385
- )
386
-
387
-
388
- def head(
389
- path: str,
390
- response_model: type[Any] | None = None,
391
- status_code: int | None = None,
392
- tags: list[str] | None = None,
393
- dependencies: Sequence[params.Depends] | None = None,
394
- summary: str | None = None,
395
- description: str | None = None,
396
- response_description: str = "Successful Response",
397
- responses: dict[int | str, dict[str, Any]] | None = None,
398
- deprecated: bool | None = None,
399
- operation_id: str | None = None,
400
- response_model_include: SetIntStr | DictIntStrAny | None = None,
401
- response_model_exclude: SetIntStr | DictIntStrAny | None = None,
402
- response_model_by_alias: bool = True,
403
- response_model_exclude_unset: bool = False,
404
- response_model_exclude_defaults: bool = False,
405
- response_model_exclude_none: bool = False,
406
- include_in_schema: bool = True,
407
- response_class: type[Response] = JSONResponse,
408
- name: str | None = None,
409
- route_class_override: type[APIRoute] | None = None,
410
- callbacks: list[StarletteRoute] | None = None,
411
- openapi_extra: dict[str, Any] | None = None,
412
- ) -> Callable[[FuncT], FuncT]:
413
- return route(
414
- path=path,
415
- methods=[HTTPMethod.HEAD],
416
- response_model=response_model,
417
- status_code=status_code,
418
- tags=tags,
419
- dependencies=dependencies,
420
- summary=summary,
421
- description=description,
422
- response_description=response_description,
423
- responses=responses,
424
- deprecated=deprecated,
425
- operation_id=operation_id,
426
- response_model_include=response_model_include,
427
- response_model_exclude=response_model_exclude,
428
- response_model_by_alias=response_model_by_alias,
429
- response_model_exclude_unset=response_model_exclude_unset,
430
- response_model_exclude_defaults=response_model_exclude_defaults,
431
- response_model_exclude_none=response_model_exclude_none,
432
- include_in_schema=include_in_schema,
433
- response_class=response_class,
434
- name=name,
435
- route_class_override=route_class_override,
436
- callbacks=callbacks,
437
- openapi_extra=openapi_extra,
438
- )
439
-
440
-
441
- def options(
442
- path: str,
443
- response_model: type[Any] | None = None,
444
- status_code: int | None = None,
445
- tags: list[str] | None = None,
446
- dependencies: Sequence[params.Depends] | None = None,
447
- summary: str | None = None,
448
- description: str | None = None,
449
- response_description: str = "Successful Response",
450
- responses: dict[int | str, dict[str, Any]] | None = None,
451
- deprecated: bool | None = None,
452
- operation_id: str | None = None,
453
- response_model_include: SetIntStr | DictIntStrAny | None = None,
454
- response_model_exclude: SetIntStr | DictIntStrAny | None = None,
455
- response_model_by_alias: bool = True,
456
- response_model_exclude_unset: bool = False,
457
- response_model_exclude_defaults: bool = False,
458
- response_model_exclude_none: bool = False,
459
- include_in_schema: bool = True,
460
- response_class: type[Response] = JSONResponse,
461
- name: str | None = None,
462
- route_class_override: type[APIRoute] | None = None,
463
- callbacks: list[StarletteRoute] | None = None,
464
- openapi_extra: dict[str, Any] | None = None,
465
- ) -> Callable[[FuncT], FuncT]:
466
- return route(
467
- path=path,
468
- methods=[HTTPMethod.OPTIONS],
469
- response_model=response_model,
470
- status_code=status_code,
471
- tags=tags,
472
- dependencies=dependencies,
473
- summary=summary,
474
- description=description,
475
- response_description=response_description,
476
- responses=responses,
477
- deprecated=deprecated,
478
- operation_id=operation_id,
479
- response_model_include=response_model_include,
480
- response_model_exclude=response_model_exclude,
481
- response_model_by_alias=response_model_by_alias,
482
- response_model_exclude_unset=response_model_exclude_unset,
483
- response_model_exclude_defaults=response_model_exclude_defaults,
484
- response_model_exclude_none=response_model_exclude_none,
485
- include_in_schema=include_in_schema,
486
- response_class=response_class,
487
- name=name,
488
- route_class_override=route_class_override,
489
- callbacks=callbacks,
490
- openapi_extra=openapi_extra,
491
- )
492
-
493
-
494
- def websocket(
495
- path: str,
496
- name: str | None = None,
497
- dependencies: Sequence[params.Depends] | None = None,
498
- ) -> Callable[[FuncT], FuncT]:
499
- return WebSocketRoute(
500
- path=path,
501
- name=name,
502
- dependencies=dependencies,
503
- )
504
5
 
505
6
 
506
7
  @dataclass(eq=False)
507
8
  class ApiController(Controller):
9
+ prefix: str
508
10
  tags: list[str | Enum] | None = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spakky-fastapi
3
- Version: 1.7.0
3
+ Version: 2.0.1
4
4
  Summary: Highly abstracted Framework core to use DDD & DI/IoC & AOP & Etc...
5
5
  Author: Spakky
6
6
  Author-email: sejong418@icloud.com
@@ -11,7 +11,7 @@ Classifier: Programming Language :: Python :: 3.11
11
11
  Classifier: Programming Language :: Python :: 3.12
12
12
  Requires-Dist: fastapi (>=0.115.5,<0.116.0)
13
13
  Requires-Dist: orjson (>=3.10.11,<4.0.0)
14
- Requires-Dist: spakky-core (>=1.8,<2.0)
14
+ Requires-Dist: spakky-core (>=2.10)
15
15
  Requires-Dist: websockets (>=14.1,<15.0)
16
16
  Description-Content-Type: text/markdown
17
17
 
@@ -0,0 +1,26 @@
1
+ spakky_fastapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ spakky_fastapi/error.py,sha256=IkSzZmbE7W4cy5owmKqzwIck-JZKeY0gZ9MhPHNmHuQ,1670
3
+ spakky_fastapi/main.py,sha256=TRWTpo_oktbFq2eJ-AynpWsZH2MoFTBuEldMrlxHHrQ,399
4
+ spakky_fastapi/middlewares/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ spakky_fastapi/middlewares/error_handling.py,sha256=KXMivDNY8ly87GcTyvCTuIsOSzMafFd6h5cAJtlKlBQ,985
6
+ spakky_fastapi/middlewares/manage_context.py,sha256=K9jFih1uU3LQzwLbj8kpLgPPln_KKM0D02qv7tzea-E,901
7
+ spakky_fastapi/post_processors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ spakky_fastapi/post_processors/add_builtin_middlewares.py,sha256=ePyVYV5CssbRIGxakS85RvsGmHr8LVMFkcu-_QttSCc,1185
9
+ spakky_fastapi/post_processors/register_routes.py,sha256=dtJ6zmNdEmXPkfqf003P7toMQTBkIwvKZ4270sRec0I,4503
10
+ spakky_fastapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ spakky_fastapi/routes/__init__.py,sha256=ZYkuBMCeCeIwe2Oym8oL6CpzM1kWdjpXyqerFzT-ACQ,360
12
+ spakky_fastapi/routes/delete.py,sha256=Mu-newjej3_SAPaWEuwbPkRc7lS9WuUgGY4PuiUSVD8,2428
13
+ spakky_fastapi/routes/get.py,sha256=t9jAoUreLj2dj_mLIPsgSEZ0TB7F_4bTwoRGxHULGBc,2422
14
+ spakky_fastapi/routes/head.py,sha256=Yy68T4y3JJbjBTJOfpvHuZiwLUm2vL6Fp41ai2awads,2424
15
+ spakky_fastapi/routes/options.py,sha256=CBPMV8YllCnbyUdShtBDE-FVupRTiVaXdez0WJyUz2o,2430
16
+ spakky_fastapi/routes/patch.py,sha256=uwZFpFuO3uYn55u8NIwBZigz7i9M2cR0MQhgedOzHZ8,2426
17
+ spakky_fastapi/routes/post.py,sha256=mmR3QAiZGYOHI3kPqpdqF5KE6rMp5lOz84Myq_bSo6k,2424
18
+ spakky_fastapi/routes/put.py,sha256=MOg2nhsIZuWY8Wol6r16fTWvlVlD__A6L1kmA5Rcs3w,2422
19
+ spakky_fastapi/routes/route.py,sha256=LhUOq9wZJjHc8C0A59BrraipBsb_5gX_WDI6wkcUO9U,4147
20
+ spakky_fastapi/routes/websocket.py,sha256=UA9qVduqAbGyToOUo4giPhdy9lKWJkHhrNF9LnKMRgU,703
21
+ spakky_fastapi/stereotypes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ spakky_fastapi/stereotypes/api_controller.py,sha256=gnUVdQnK2miMMwBgQ88bbMajMAvmBwjwS3semtLBkBY,222
23
+ spakky_fastapi-2.0.1.dist-info/METADATA,sha256=Fv5iezr-kTO2NSeYuKThxWd4kZSRIWod_ZsWF3WaBZ8,1850
24
+ spakky_fastapi-2.0.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
25
+ spakky_fastapi-2.0.1.dist-info/entry_points.txt,sha256=m_VotPZLovg4sBMBm_XK5ateHrUizil9dQ11-2v-ZMw,57
26
+ spakky_fastapi-2.0.1.dist-info/RECORD,,
@@ -0,0 +1,3 @@
1
+ [spakky.plugins]
2
+ fastapi=spakky_fastapi.main:initialize
3
+
@@ -1,107 +0,0 @@
1
- from typing import Any, TypeVar, Callable, Annotated, Awaitable, TypeAlias, Concatenate
2
- from inspect import iscoroutinefunction
3
- from logging import Logger
4
- from dataclasses import InitVar, field, dataclass
5
-
6
- from fastapi import Depends
7
- from fastapi.security import OAuth2PasswordBearer
8
- from spakky.aop.aspect import Aspect, AsyncAspect, IAspect, IAsyncAspect
9
- from spakky.aop.error import SpakkyAOPError
10
- from spakky.aop.pointcut import Around
11
- from spakky.core.annotation import FunctionAnnotation
12
- from spakky.core.types import AsyncFunc, Func, P
13
- from spakky.pod.order import Order
14
- from spakky.security.error import InvalidJWTFormatError, JWTDecodingError
15
- from spakky.security.jwt import JWT
16
- from spakky.security.key import Key
17
-
18
- from spakky_fastapi.error import Unauthorized
19
-
20
- R_co = TypeVar("R_co", covariant=True)
21
-
22
-
23
- class AuthenticationFailedError(SpakkyAOPError):
24
- message = "사용자 인증에 실패했습니다."
25
-
26
-
27
- IAuthenticateFunction: TypeAlias = (
28
- Callable[Concatenate[Any, JWT, P], R_co]
29
- | Callable[Concatenate[Any, JWT, P], Awaitable[R_co]]
30
- )
31
-
32
-
33
- @dataclass
34
- class Authenticate(FunctionAnnotation):
35
- token_url: InitVar[str]
36
- authenticator: OAuth2PasswordBearer = field(init=False)
37
- token_keywords: list[str] = field(init=False, default_factory=list)
38
-
39
- def __post_init__(self, token_url: str) -> None:
40
- self.authenticator = OAuth2PasswordBearer(tokenUrl=token_url)
41
-
42
- def __call__(
43
- self, obj: IAuthenticateFunction[P, R_co]
44
- ) -> IAuthenticateFunction[P, R_co]:
45
- for key, value in obj.__annotations__.items():
46
- if value == JWT:
47
- obj.__annotations__[key] = Annotated[JWT, Depends(self.authenticator)]
48
- self.token_keywords.append(key)
49
- return super().__call__(obj)
50
-
51
-
52
- @Order(1)
53
- @Aspect()
54
- class AuthenticationAspect(IAspect):
55
- __logger: Logger
56
- __key: Key
57
-
58
- def __init__(self, logger: Logger, key: Key) -> None:
59
- super().__init__()
60
- self.__logger = logger
61
- self.__key = key
62
-
63
- @Around(lambda x: Authenticate.exists(x) and not iscoroutinefunction(x))
64
- def around(self, joinpoint: Func, *args: Any, **kwargs: Any) -> Any:
65
- annotation: Authenticate = Authenticate.get(joinpoint)
66
- for keyword in annotation.token_keywords:
67
- token: str = kwargs[keyword]
68
- try:
69
- jwt: JWT = JWT(token=token)
70
- except (InvalidJWTFormatError, JWTDecodingError) as e:
71
- raise Unauthorized(AuthenticationFailedError()) from e
72
- if jwt.is_expired:
73
- raise Unauthorized(AuthenticationFailedError())
74
- if jwt.verify(self.__key) is False:
75
- raise Unauthorized(AuthenticationFailedError())
76
- self.__logger.info(f"[{type(self).__name__}] {jwt.payload!r}")
77
- kwargs[keyword] = jwt
78
- return joinpoint(*args, **kwargs)
79
-
80
-
81
- @Order(1)
82
- @AsyncAspect()
83
- class AsyncAuthenticationAspect(IAsyncAspect):
84
- __logger: Logger
85
- __key: Key
86
-
87
- def __init__(self, logger: Logger, key: Key) -> None:
88
- super().__init__()
89
- self.__logger = logger
90
- self.__key = key
91
-
92
- @Around(lambda x: Authenticate.exists(x) and iscoroutinefunction(x))
93
- async def around_async(self, joinpoint: AsyncFunc, *args: Any, **kwargs: Any) -> Any:
94
- annotation: Authenticate = Authenticate.get(joinpoint)
95
- for keyword in annotation.token_keywords:
96
- token: str = kwargs[keyword]
97
- try:
98
- jwt: JWT = JWT(token=token)
99
- except (InvalidJWTFormatError, JWTDecodingError) as e:
100
- raise Unauthorized(AuthenticationFailedError()) from e
101
- if jwt.is_expired:
102
- raise Unauthorized(AuthenticationFailedError())
103
- if jwt.verify(self.__key) is False:
104
- raise Unauthorized(AuthenticationFailedError())
105
- self.__logger.info(f"[{type(self).__name__}] {jwt.payload!r}")
106
- kwargs[keyword] = jwt
107
- return await joinpoint(*args, **kwargs)
File without changes
@@ -1,13 +0,0 @@
1
- from spakky.application.interfaces.pluggable import IPluggable
2
- from spakky.application.interfaces.registry import IPodRegistry
3
-
4
- from spakky_fastapi.aspects.authenticate import (
5
- AsyncAuthenticationAspect,
6
- AuthenticationAspect,
7
- )
8
-
9
-
10
- class AuthenticatePlugin(IPluggable):
11
- def register(self, registry: IPodRegistry) -> None:
12
- registry.register(AuthenticationAspect)
13
- registry.register(AsyncAuthenticationAspect)