Question: In my FastAPI project, if I create a common header definition with Pydantic, I find that kebab-case header fields aren't behaving as expected. The "magic" conversion from kebab-case header fields in the request to their snake_case counterparts is not working, in addition to inconsistencies in the generated Swagger docs. What is the right way to specify this Pydantic header class so that the Swagger docs and behavior match? Here's a minimal reproduction of the problem: ### main.py from typing import Annotated from fastapi import FastAPI, Header from pydantic import BaseModel, Field app = FastAPI() class CommonHeaders(BaseModel): simpleheader: str a_kebab_header: str | None = Field( default=None, title="a-kebab-header", alias="a-kebab-header", description="This is a header that should be specified as `a-kebab-header`", ) @app.get("/") def root_endpoint( headers: Annotated[CommonHeaders, Header()], ): result = {"headers received": headers} return result  If I run this and look at the Swagger docs at http://localhost:8000/docs I see this, which looks correct:  And if I "try it out" it will generate what I would expect as the correct request: curl -X 'GET' \ 'http://localhost:8000/' \ -H 'accept: application/json' \ -H 'simpleheader: foo' \ -H 'a-kebab-header: bar'  But in the response, it becomes clear it did not correctly receive the kebab-case header: { "headers received": { "simpleheader": "foo", "a-kebab-header": null } }  Changing the header name to snake_case "a_kebab_header" in the request does not work, either. Updating the header definition to look like this doesn't work as expected, either. The Swagger docs and actual behavior are inconsistent. class CommonHeaders(BaseModel): simpleheader: str a_kebab_header: str | None = Field( default=None, description="This is a header that should be specified as `a-kebab-header`", )  Notice this now results in the Swagger docs specifying it in snake_case:  And using "try it out" results in the snake_case variant: curl -X 'GET' \ 'http://localhost:8000/' \ -H 'accept: application/json' \ -H 'simpleheader: foo' \ -H 'a_kebab_header: bar'  But SURPRISINGLY this doesn't work! The response: { "headers received": { "simpleheader": "foo", "a_kebab_header": null } }  But in a SURPRISE ENDING, if I manually re-write the request in kebab-case: curl -X 'GET' \ 'http://localhost:8000/' \ -H 'accept: application/json' \ -H 'simpleheader: foo' \ -H 'a-kebab-header: bar'  it finally picks up that header value via the magic translation and I get the desired results back: {"headers received":{"simpleheader":"foo","a_kebab_header":"bar"}}  What is the right way to specify this Pydantic header class so that the Swagger docs and behavior match? If the docs are inconsistent with behavior I'm going to get hassled.  As a final thought: the following way works correctly in both the OpenAPI documentation and in the application (displaying and working as kebab-case), BUT it doesn't use Pydantic and so I lose the ability to define and use a common header structure easily across my project, and instead need to declare them individually for each endpoint: """Alternative version without Pydantic.""" from typing import Annotated from fastapi import FastAPI, Header app = FastAPI() @app.get("/") def root_endpoint( simpleheader: Annotated[str, Header()], a_kebab_header: Annotated[ str | None, Header( title="a-kebab-header", description="This is a header that should be specified as `a-kebab-header`", ), ] = None, ): result = { "headers received": { "simpleheader": simpleheader, "a_kebab_header": a_kebab_header, } } return result 

Answer: The only way I found is to define parameters without using Pydantic model. To use this common parameters in different endpoints you can define them using dependency function: from typing import Annotated from fastapi import Depends, FastAPI, Header from pydantic import BaseModel app = FastAPI() class CommonHeaders(BaseModel): simpleheader: str a_kebab_header: str | None def get_common_headers( simpleheader: Annotated[str, Header()], a_kebab_header: str | None = Header( default=None, title="a-kebab-header", alias="a-kebab-header", description="This is a header that should be specified as `a-kebab-header`", ), ): return CommonHeaders(simpleheader=simpleheader, a_kebab_header=a_kebab_header) @app.get("/") def root_endpoint( headers: Annotated[CommonHeaders, Depends(get_common_headers)], ): result = {"headers received": headers} return result @app.get("/another") def another_endpoint( headers: Annotated[CommonHeaders, Depends(get_common_headers)], ): result = {"headers received": headers} return result