question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[QUESTION] How do I use a string-formatted BaseModel as a path param?

See original GitHub issue

Example

from fastapi import FastAPI
from pydantic import BaseModel

class Multihash(BaseModel):
    func: int
    digest: bytes

class MultihashHex(Multihash):
    @classmethod
    def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None:
        field_schema.update({"type": "string", "format": "multihash-hex"})

    @classmethod
    def __get_validators__(cls) -> Iterator[Callable[..., Any]]:
        yield cls.validate

    @classmethod
    def validate(cls, value: Union[str, bytes]) -> Multihash:
        if isinstance(value, str):
            value = bytes.fromhex(value)
        return Multihash(...)


app = FastAPI()

@app.get("/data/{mh}")
def read(mh:MultihashHex):
    return ...

Description

When I run the above, I get:

$ uvicorn test:app
...
  File "./test.py", line 32, in <module>
    def read(mh:MultihashHex):
  File "/home/amnesia/Persistent/venv/lib/python3.7/site-packages/fastapi/routing.py", line 574, in decorator
    callbacks=callbacks,
  File "/home/amnesia/Persistent/venv/lib/python3.7/site-packages/fastapi/routing.py", line 520, in add_api_route
    callbacks=current_callbacks,
  File "/home/amnesia/Persistent/venv/lib/python3.7/site-packages/fastapi/routing.py", line 380, in __init__
    self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
  File "/home/amnesia/Persistent/venv/lib/python3.7/site-packages/fastapi/dependencies/utils.py", line 308, in get_dependant
    ), "Path params must be of one of the supported types"
AssertionError: Path params must be of one of the supported types

I’m building an app that vends content-addressable data. I’d like to use a multihash as a path param. Multihash is just a (hash-function, hash-digest) tuple, with well-defined encoding.

My intent is to have my path param be a hexadecimal multihash, and use the Multihash type internally. There seem to be other examples of string-representable objects, like NameEmail or IPv4Address.

But, I can’t seem to make my Multihash class be a BaseModel. I get the above error.

I can make Multihash a base object instead, but I lose pydantic features.

Is it an error that BaseModel objects can’t be used this way, or is there a better way to do what I’m doing?

Environment

  • OS: tails 4.17
  • python: 3.7.3
  • packages:
fastapi==0.63.0
pydantic==1.8.1

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:2
  • Comments:5

github_iconTop GitHub Comments

2reactions
AllSeeingEyeTolledEweSewcommented, Apr 12, 2021

as you can see here in the docs: https://fastapi.tiangolo.com/tutorial/body/#request-body-path-query-parameters

Reading that:

If the parameter is also declared in the path, it will be used as a path parameter. If the parameter is of a singular type (like int, float, str, bool, etc) it will be interpreted as a query parameter. If the parameter is declared to be of the type of a Pydantic model, it will be interpreted as a request body.

Reading it in order, I thought it says plainly that if a parameter is declared in the path then it’s used as a path parameter, even if it’s a BaseModel.

If it intends to say that “BaseModels will always be interpreted as request body”, then… I feel it should be written differently 😃

I know is_scalar_field is part of the stack that blocks this usage. But surely an undocumented utility function is not ground truth for APIs or intent

Extending my example from above:

class Outer(BaseModel):
    mh: MultihashHex

parse_raw_as(Outer, '{"mh": "0a2b3c..."}')
"""
Outer(mh=MultihashHex(...))
"""

Pydantic lets me parse a string field into a BaseModel just fine, so I expect to be able to parse a path parameter into a BaseModel as well. The two seem perfectly analogous to me

0reactions
g0dicommented, May 4, 2021

Came to the exact same issue when I wanted to provide a path parameter which is an object with several keys. As mentioned previously, a test in source code prevent us from being able to provide something else than scalars as path parameters…

However, the OpenAPI specification currently allow and define a way to document path parameters as objects or arrays thanks to schema, style and explode properties of path parameter objects, see https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object

IMO, It could be interesting to implement such a thing

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to pass the path parameter to the Pydantic model?
Pydantic in FastAPI is used to define data model. You can do as follows: from typing import Optional from fastapi import FastAPI from...
Read more >
Vincit/objection.js - Gitter
is there a way to use modify on a relation definition to filter on something that's relevant to the originating object? Basically, I'd...
Read more >
What is the String.format() method in Java? - Educative.io
The Java String.format() method returns the formatted string by a given locale, format, and argument. If the locale is not specified in the...
Read more >
Body - Nested Models - FastAPI
To declare types that have type parameters (internal types), like list , dict , tuple : If you are in a Python version...
Read more >
Parse JSON-encoded query strings in FastAPI
Can I turn complex parameters in the query string into Pydantic models? class Quarter(BaseModel): q: int year: int @app.get("/api/v1/chart") ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found