gRPC plugin for Spakky framework
Project description
spakky-grpc
Spakky Framework를 위한 code-first gRPC 플러그인입니다.
pydantic BaseModel로 메시지를 선언하고 @GrpcController + @rpc 데코레이터로 서비스를 정의하면, 런타임에 protobuf descriptor를 자동 생성하여 grpc.aio.Server에 등록합니다. .proto 파일이나 codegen 단계가 필요 없습니다. protobuf ↔ BaseModel 변환은 google.protobuf.json_format 브릿지(JSON 중간 표현)로 수행됩니다.
설치
pip install spakky-grpc
의존성: grpcio, protobuf, pydantic>=2.4, spakky, spakky-tracing.
빠른 시작
from typing import Annotated
from pydantic import BaseModel
from spakky.core.application.application import SpakkyApplication
from spakky.core.application.application_context import ApplicationContext
from spakky.core.pod.annotations.pod import Pod
import spakky.plugins.grpc
from spakky.plugins.grpc.annotations.field import ProtoField
from spakky.plugins.grpc.decorators.rpc import rpc
from spakky.plugins.grpc.schema.registry import DescriptorRegistry
from spakky.plugins.grpc.server_spec import GrpcServerSpec
from spakky.plugins.grpc.stereotypes.grpc_controller import GrpcController
import apps # `@GrpcController`-decorated classes live in your own package
class HelloRequest(BaseModel):
name: Annotated[str, ProtoField(number=1)]
class HelloReply(BaseModel):
message: Annotated[str, ProtoField(number=1)]
@GrpcController(package="example.hello")
class HelloController:
@rpc()
async def say_hello(self, request: HelloRequest) -> HelloReply:
return HelloReply(message=f"Hello, {request.name}!")
@Pod()
def get_spec() -> GrpcServerSpec:
spec = GrpcServerSpec()
spec.add_insecure_port("127.0.0.1:50051")
return spec
@Pod()
def get_registry() -> DescriptorRegistry:
return DescriptorRegistry()
app = (
SpakkyApplication(ApplicationContext())
.load_plugins(include={spakky.plugins.grpc.PLUGIN_NAME})
.scan(apps) # your package containing HelloController above
.add(get_spec)
.add(get_registry)
)
app.start() # 서버가 별도 이벤트 루프 스레드에서 구동됩니다
GrpcServerSpec는 핸들러·인터셉터·바인드 주소를 누적합니다. 실제 grpc.aio.Server는 ApplicationContext의 이벤트 루프 스레드에서 spec.build()로 생성되므로 grpc.aio 내부 Future가 올바른 루프에 바인딩됩니다.
타입 매핑
ProtoField 어노테이션이 부착된 pydantic BaseModel 필드(Annotated[T, ProtoField(number=N)])를 protobuf 필드로 매핑합니다. 필드 번호는 BaseModel.model_fields[name].metadata에서 읽어옵니다.
| Python | Protobuf |
|---|---|
str |
string |
int |
int64 |
float |
double |
bool |
bool |
bytes |
bytes |
list[T] |
repeated T |
T | None |
optional T |
중첩 BaseModel |
message |
지원되지 않는 타입은 UnsupportedFieldTypeError를 던집니다.
스트리밍
@rpc(method_type=...)로 네 가지 gRPC 스트리밍 패턴을 모두 지원합니다.
RpcMethodType |
시그니처 |
|---|---|
UNARY |
async def m(self, req: Req) -> Resp |
SERVER_STREAMING |
async def m(self, req: Req) -> AsyncIterator[Resp] |
CLIENT_STREAMING |
async def m(self, reqs: AsyncIterator[Req]) -> Resp |
BIDI_STREAMING |
async def m(self, reqs: AsyncIterator[Req]) -> AsyncIterator[Resp] |
인터셉터
플러그인이 자동으로 다음 인터셉터를 설치합니다.
| 인터셉터 | 조건 | 역할 |
|---|---|---|
ErrorHandlingInterceptor |
항상 | 예외 → gRPC status 매핑 |
TracingInterceptor |
spakky-tracing 로드 시 |
W3C Trace Context 전파 |
에러 매핑
AbstractGrpcStatusError 서브클래스의 status_code가 그대로 gRPC status로 전달됩니다.
| 에러 | gRPC Status |
|---|---|
InvalidArgument |
INVALID_ARGUMENT |
NotFound |
NOT_FOUND |
AlreadyExists |
ALREADY_EXISTS |
PermissionDenied |
PERMISSION_DENIED |
Unauthenticated |
UNAUTHENTICATED |
FailedPrecondition |
FAILED_PRECONDITION |
Unavailable |
UNAVAILABLE |
InternalError |
INTERNAL |
예상되지 않은 예외는 INTERNAL로 정규화됩니다.
트레이싱
spakky-tracing 플러그인을 함께 로드하면 W3C traceparent 메타데이터를 추출하여 TraceContext.get()으로 핸들러 내부에서 사용할 수 있고, 응답 trailing metadata에 자동 주입합니다.
app.load_plugins(include={
spakky.plugins.grpc.PLUGIN_NAME,
spakky.tracing.PLUGIN_NAME,
})
PostProcessor 실행 순서
| Order | PostProcessor | 역할 |
|---|---|---|
| 0 | RegisterServicesPostProcessor |
@GrpcController → generic handler를 GrpcServerSpec에 추가 |
| 1 | AddInterceptorsPostProcessor |
에러/트레이싱 인터셉터를 GrpcServerSpec에 추가 |
| 2 | BindServerPostProcessor |
GrpcServerService를 ApplicationContext에 등록 (start_async에서 spec.build()) |
라이선스
MIT License입니다. Spakky Framework repository를 참고하세요.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file spakky_grpc-6.5.0.tar.gz.
File metadata
- Download URL: spakky_grpc-6.5.0.tar.gz
- Upload date:
- Size: 18.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a8e5f838eaa7ac395307c3b33c19933ac365c2a3395e0826b56dd1178f709727
|
|
| MD5 |
78d133b10eb1e4343ab4ad6ebf961978
|
|
| BLAKE2b-256 |
d2dd34d9083f4bb1c9aee9fd5c7a8a371110aa445a42736cd1bde5e8367566c0
|
Provenance
The following attestation bundles were made for spakky_grpc-6.5.0.tar.gz:
Publisher:
release.yml on E5presso/spakky-framework
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spakky_grpc-6.5.0.tar.gz -
Subject digest:
a8e5f838eaa7ac395307c3b33c19933ac365c2a3395e0826b56dd1178f709727 - Sigstore transparency entry: 1437042884
- Sigstore integration time:
-
Permalink:
E5presso/spakky-framework@86c1d43bdc948ac432f27efeeeb2b56692d18ee4 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/E5presso
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@86c1d43bdc948ac432f27efeeeb2b56692d18ee4 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file spakky_grpc-6.5.0-py3-none-any.whl.
File metadata
- Download URL: spakky_grpc-6.5.0-py3-none-any.whl
- Upload date:
- Size: 29.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a30ed7bb8c068a02705a9a0b2ae6ea6c4590e182f97b6f42243fce066518c5d
|
|
| MD5 |
0697abb6b0512556d308d1d67413d4b0
|
|
| BLAKE2b-256 |
544dc897ddbe4cba7933afb01bff3662948b35860b4e162b7a4b0437c68de160
|
Provenance
The following attestation bundles were made for spakky_grpc-6.5.0-py3-none-any.whl:
Publisher:
release.yml on E5presso/spakky-framework
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spakky_grpc-6.5.0-py3-none-any.whl -
Subject digest:
0a30ed7bb8c068a02705a9a0b2ae6ea6c4590e182f97b6f42243fce066518c5d - Sigstore transparency entry: 1437042891
- Sigstore integration time:
-
Permalink:
E5presso/spakky-framework@86c1d43bdc948ac432f27efeeeb2b56692d18ee4 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/E5presso
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@86c1d43bdc948ac432f27efeeeb2b56692d18ee4 -
Trigger Event:
workflow_dispatch
-
Statement type: