spruceid / siwe-py

A Python implementation of Sign-In with Ethereum
https://login.xyz
Apache License 2.0
66 stars 28 forks source link

Issue in using `SiweMessage` as FastAPI body model #56

Closed fubuloubu closed 3 months ago

fubuloubu commented 4 months ago

The SiweMessage class barfs on a very basic usage with FastAPI, here's a MWE:

app.py:

import siwe
from fastapi import FastAPI

app = FastAPI()

@app.post("/login")
def siwe_login(data: siwe.SiweMessage):
    pass

If you run it using uvicorn app:app and then access http://127.0.0.1:8000/docs you will get:

$ uvicorn app:app
INFO:     Started server process [******]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     127.0.0.1:41242 - "GET /docs HTTP/1.1" 200 OK
INFO:     127.0.0.1:41242 - "GET /openapi.json HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "site-packages/uvicorn/protocols/http/httptools_impl.py", line 411, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/uvicorn/middleware/proxy_headers.py", line 69, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/fastapi/applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "site-packages/starlette/applications.py", line 123, in __call__
    await self.middleware_stack(scope, receive, send)
  File "site-packages/starlette/middleware/errors.py", line 186, in __call__
    raise exc
  File "site-packages/starlette/middleware/errors.py", line 164, in __call__
    await self.app(scope, receive, _send)
  File "site-packages/starlette/middleware/exceptions.py", line 62, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "site-packages/starlette/routing.py", line 758, in __call__
    await self.middleware_stack(scope, receive, send)
  File "site-packages/starlette/routing.py", line 778, in app
    await route.handle(scope, receive, send)
  File "site-packages/starlette/routing.py", line 299, in handle
    await self.app(scope, receive, send)
  File "site-packages/starlette/routing.py", line 79, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "site-packages/starlette/routing.py", line 74, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "site-packages/fastapi/applications.py", line 1009, in openapi
    return JSONResponse(self.openapi())
                        ^^^^^^^^^^^^^^
  File "site-packages/fastapi/applications.py", line 981, in openapi
    self.openapi_schema = get_openapi(
                          ^^^^^^^^^^^^
  File "site-packages/fastapi/openapi/utils.py", line 475, in get_openapi
    field_mapping, definitions = get_definitions(
                                 ^^^^^^^^^^^^^^^^
  File "site-packages/fastapi/_compat.py", line 227, in get_definitions
    field_mapping, definitions = schema_generator.generate_definitions(
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/pydantic/json_schema.py", line 372, in generate_definitions
    self.generate_inner(schema)
  File "site-packages/pydantic/json_schema.py", line 547, in generate_inner
    json_schema = current_handler(schema)
                  ^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/pydantic/_internal/_schema_generation_shared.py", line 36, in __call__
    return self.handler(__core_schema)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/pydantic/json_schema.py", line 504, in handler_func
    json_schema = generate_for_schema_type(schema_or_field)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/pydantic/json_schema.py", line 1164, in chain_schema
    return self.generate_inner(schema['steps'][step_index])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/pydantic/json_schema.py", line 547, in generate_inner
    json_schema = current_handler(schema)
                  ^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/pydantic/_internal/_schema_generation_shared.py", line 36, in __call__
    return self.handler(__core_schema)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/pydantic/json_schema.py", line 504, in handler_func
    json_schema = generate_for_schema_type(schema_or_field)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/pydantic/json_schema.py", line 977, in function_plain_schema
    return self._function_schema(schema)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/pydantic/json_schema.py", line 942, in _function_schema
    return self.handle_invalid_for_json_schema(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/pydantic/json_schema.py", line 2093, in handle_invalid_for_json_schema
    raise PydanticInvalidForJsonSchema(f'Cannot generate a JsonSchema for {error_info}')
pydantic.errors.PydanticInvalidForJsonSchema: Cannot generate a JsonSchema for core_schema.PlainValidatorFunctionSchema ({'type': 'with-info', 'function': <bound method BaseModel.validate of <class 'siwe.siwe.SiweMessage'>>})

For further information visit https://errors.pydantic.dev/2.6/u/invalid-for-json-schema

This might be related to #39