mincom
mincom

Reputation: 979

FastAPI's auto generated OpenAPI file not valid according to Insomnia

I am trying to import an openapi.json into Insomnia to generate a collection, but Insomnia says it is not valid.

Is there a difference in rulesets between FastAPI/Swagger and Insomnia? If not, what causes this difference in compatibility?

Here's a trimmed down example of an automatically generated OpenAPI specification:

{
    "openapi": "3.0.2",
    "info": {
        "title": "Test API",
        "description": "description",
        "contact": {
            "name": "example",
            "url": "https://example.com/contact-us/",
            "email": "[email protected]"
        },
        "license": {
            "name": "Copyright 2023 example"
        },
        "version": "0.0.1"
    },
    "paths": {
        "/test_build": {
            "get": {
                "tags": [
                    "Test endpoints"
                ],
                "summary": "Test",
                "description": "",
                "operationId": "test_build_get",
                "responses": {
                    "200": {
                        "description": "Successful Response",
                        "content": {
                            "application/json": {
                                "schema": {}
                            }
                        }
                    }
                }
            }
        },
        "/api/search_something": {
            "get": {
                "tags": [
                    "Main endpoints"
                ],
                "summary": "Search something",
                "description": "",
                "operationId": "search_something_get",
                "parameters": [
                    {
                        "required": false,
                        "schema": {
                            "title": "something",
                            "maximum": 50.0,
                            "exclusiveMinimum": 0.0,
                            "type": "integer",
                            "default": 50
                        },
                        "name": "something",
                        "in": "query"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Successful Response",
                        "content": {}
                    }
                }
            }
        }
    }
}

This is rejected by Insomnia for many reasons, but here are some examples of errors and warnings:

Is there a way to make FastAPI's openapi.json file conform with Insomnia's ruleset?

Upvotes: 2

Views: 1383

Answers (2)

Edgy
Edgy

Reputation: 21

If it helps I just ran into this same issue, and followed the above suggestion as well to solve the issue locally. Below is a version of the solution I used.

import fastapi
from fastapi.openapi.utils import get_openapi 


app = fastapi.FastAPI()

def clean_property(prop: dict) -> None:
    for find, replace in [
        ("exclusiveMinimum", "minimum"),
        ("exclusiveMaximum", "maximum"),
    ]:
        if find in prop:
            prop[replace] = prop[find]
            prop[find] = True

def custom_openapi() -> dict:
    if app.openapi_schema:
        return app.openapi_schema

    openapi_schema = get_openapi(
        title="Custom title",
        version="3.0.1",
        description="Custom description",
        routes=app.routes,
    )

    for data in openapi_schema["paths"].values():
        for _method, method_data in data.items():
            for parameter in method_data.get("parameters", []):
                if "schema" in parameter:
                    clean_property(parameter["schema"])

    for schema in openapi_schema["components"]["schemas"].values():
        for prop in schema.get("properties", {}).values():
            clean_property(prop)

    app.openapi_schema = openapi_schema

    return app.openapi_schema

app.openapi = custom_openapi

Upvotes: 1

Helen
Helen

Reputation: 97991

oas3-schema "exclusiveMinimum" property type must be boolean.

exclusiveMinimum and exclusiveMaximum being generated as numbers instead of booleans is a known issue with Pydantic. Pydantic generates these keywords as numbers according to JSON Schema Draft 6+, but OpenAPI 3.0.x uses an earlier JSON Schema Draft 5 where the exclusive* keywords are booleans.

This won't be an issue if/when FastAPI and Pydantic migrate to OpenAPI 3.1 because it uses the latest JSON Schema.

But if you need to use OpenAPI 3.0.x, you have the following options.

Option 1: use ge/le instead of gt/lt (if suitable)

In case of integer parameters and schema fields, the easiest fix is to use the ge/le attributes ("greater/less than or equal") instead of gt/lt ("greater/less than"). For example, if the minimum value is 1 (inclusive), use ge=1 instead of gt=0:

something: int = Query(ge=1)

Pydantic translates ge to minimum and le to maximum without exclusive*.

Option 2: post-process the OpenAPI file

Another solution is to post-process your generated OpenAPI file (e.g. as suggested here) and replace

"exclusiveMinimum": <value>

with

"minimum": <value>,
"exclusiveMinimum": true

Similarly, replace

"exclusiveMaximum": <value>

with

"maximum": <value>,
"exclusiveMaximum": true

Upvotes: 4

Related Questions