Skip to content

panel-openapi

panel_openapi

Accessible imports for the panel_openapi package.

__all__ = ['Field', 'OpenAPIForm', 'OpenAPIRecordEditor', '__version__', 'collect_fields', 'create_app', 'find_update_operations', 'get_operation', 'load_openapi', 'response_schema', 'schema_to_widget'] module-attribute

__version__ = importlib.metadata.version(__name__) module-attribute

Field dataclass

A single input derived from an operation's parameters or request body.

Parameters:

Name Type Description Default
name str

The parameter or property name used when assembling the request.

required
location FieldLocation

Where the value belongs in the request (path, query, header or body).

required
schema Schema

The resolved JSON schema describing the value.

required
required bool

Whether the field must be provided.

False
read_only bool

Whether the schema marks the value readOnly. Such fields are returned by the server but never sent in a request.

False

location instance-attribute

name instance-attribute

read_only = False class-attribute instance-attribute

required = False class-attribute instance-attribute

schema instance-attribute

OpenAPIForm

Bases: Viewer

Auto-generated form for a single OpenAPI operation.

Setting :attr:path or :attr:method rebuilds the widgets for the newly referenced operation in place, and setting :attr:base_url redirects subsequent requests, so one form can be pointed at any operation in the document it was constructed with. To change both at once use form.param.update(path=..., method=...), which rebuilds only once and avoids a transient pair the document does not define.

Parameters:

Name Type Description Default
openapi str or dict or OpenAPI

The OpenAPI document, as a URL, raw dict or parsed model.

required
base_url str

The base URL requests are issued against, e.g. https://api.example.com.

required
path str

The templated operation path, e.g. /pets/{petId}.

required
method str

The HTTP method for the operation.

'get'
headers dict

Static headers (e.g. authentication) sent with every request. The mapping is read on each submit, so mutating it swaps credentials at runtime.

None

Attributes:

Name Type Description
form Column

The widgets and submit button. Rebuilt in place when the operation changes, so the container may be laid out once and kept.

response Column

The status and body of the most recent response, empty until submit.

base_url = param.String(default='', doc='Base URL requests are issued against.') class-attribute instance-attribute

fields property

Descriptors for the inputs of the current operation.

form = pmui.Column(sizing_mode='stretch_width') instance-attribute

method = param.Selector(default='get', objects=['get', 'post', 'put', 'patch', 'delete'], doc='HTTP method of the operation.') class-attribute instance-attribute

operation property

The operation the form currently targets.

path = param.String(default='', doc='Templated path of the operation.') class-attribute instance-attribute

response = pmui.Column(sizing_mode='stretch_width') instance-attribute

skip_read_only = param.Boolean(default=False, constant=True, doc='Whether to omit body properties marked readOnly entirely. When False they are shown as disabled widgets. Either way they are never sent, since the server does not accept them.') class-attribute instance-attribute

title = param.String(default='', doc='Human-readable title, derived from the operation unless set explicitly.') class-attribute instance-attribute

values property

The values that would be sent, keyed by field name.

widgets property

The current widgets, keyed by field name.

get_values(location=None)

Return the values that would be sent, keyed by field name.

JSON text areas are returned parsed. Fields left empty and fields marked readOnly are omitted, mirroring the request.

Parameters:

Name Type Description Default
location str

Restrict the result to one of path, query, header or body. All locations are included when omitted.

None

Returns:

Type Description
dict

Field name to value.

populate(record)

Set widget values from a record, ignoring what does not fit.

Population is deliberately tolerant: a record fetched from a live API routinely carries keys the request body does not accept, and values a widget cannot represent. Rather than raising, both are skipped and reported, so a partially populated form is still usable.

Parameters:

Name Type Description Default
record dict

Field name to value, e.g. the parsed body of a GET response.

required

Returns:

Type Description
list of str

Names of keys that could not be applied, either because no widget matched or because the value was rejected.

submit(extra=None) async

Issue the request for the current values and render the response.

Parameters:

Name Type Description Default
extra dict

Additional body properties merged into the payload, overriding the widget values. Used to send a subset or superset of the form, e.g. a PATCH diff.

None

Returns:

Type Description
Response or None

The response, or None if validation failed or the request could not be made. In both cases the reason is shown in :attr:response.

OpenAPIRecordEditor

Bases: Viewer

Fetch a record from an operation and edit it via another.

The editor composes two :class:~panel_openapi.form.OpenAPIForm instances: a lookup form for the read operation, and an edit form for the update operation. Loading a record populates the edit form, and saving sends the edits back to the same resource.

The update operation is discovered on the same path, preferring PATCH over PUT over POST, unless update_method names one. Because POST on a path means "update this" in some APIs and "create a subresource" in others, the resolved operation is always displayed.

A PATCH save sends only the fields that differ from the loaded record, matching the convention that omitted keys are left alone. PUT and POST send the full body.

Parameters:

Name Type Description Default
openapi str or dict or OpenAPI

The OpenAPI document, as a URL, raw dict or parsed model.

required
base_url str

The base URL requests are issued against.

required
path str

The templated path of the record, e.g. /pets/{petId}.

required
method str

The method used to read the record.

'get'
update_method str

The method used to save. Auto-detected when omitted.

None
headers dict

Static headers sent with every request.

None
show_lookup bool

Whether to render the lookup form. Set False when driving the editor with :meth:load or :meth:populate.

True
**params Any

Remaining parameters, notably confirm to have the Save button open a dialog listing the pending changes before sending them.

{}

Examples:

Point it at a path and let it find the update operation:

>>> editor = OpenAPIRecordEditor(
...     spec, base_url="https://petstore3.swagger.io/api/v3", path="/pet/{petId}"
... )

Or drive it without the lookup UI:

>>> editor = OpenAPIRecordEditor(spec, base_url=..., path=..., show_lookup=False)
>>> await editor.load(petId=7)

base_url = param.String(default='', doc='Base URL requests are issued against.') class-attribute instance-attribute

confirm = param.Boolean(default=False, doc='Whether the Save button opens a dialog showing the pending changes first.') class-attribute instance-attribute

editor = None instance-attribute

loaded property

Whether a record has been loaded.

lookup = OpenAPIForm(self._openapi, base_url=(self.base_url), path=(self.path), method=(self.method), headers=(self._headers)) instance-attribute

method = param.Selector(default='get', objects=['get', 'post', 'put', 'patch', 'delete'], doc='Method used to read the record.') class-attribute instance-attribute

path = param.String(default='', doc='Templated path of the record.') class-attribute instance-attribute

record = param.Dict(default=None, allow_None=True, doc='The record last loaded or saved, and the baseline a PATCH diffs against.') class-attribute instance-attribute

update_method = candidates[0] if candidates else None class-attribute instance-attribute

diff()

Return the edits pending against the loaded record.

Returns:

Type Description
dict

Field name to (old, new), covering every editable location, not just the body. Some APIs take updates as query parameters, e.g. the Swagger Petstore's POST /pet/{petId}.

load(**lookup) async

Fetch a record and populate the edit form.

Parameters:

Name Type Description Default
**lookup Any

Values for the read operation's inputs, e.g. petId=7. Widgets keep their current value when not given, which is what the Load button relies on.

{}

Returns:

Type Description
dict or None

The fetched record, or None if the request failed or did not return a JSON object.

populate(record)

Populate the edit form from a record without fetching it.

Parameters:

Name Type Description Default
record dict

The record to edit. Becomes the baseline a PATCH diffs against.

required

save() async

Send the edits and adopt the response as the new record.

Bypasses the confirmation dialog, which is only wired to the Save button, so calling this always saves.

Returns:

Type Description
dict or None

The saved record as the server returned it, or None if the save failed or returned no JSON object.

collect_fields(openapi, operation, skip_read_only=False)

Flatten an operation's parameters and JSON body into fields.

Parameters:

Name Type Description Default
openapi OpenAPI

The document the operation belongs to.

required
operation Operation

The operation to introspect.

required
skip_read_only bool

Whether to drop body properties marked readOnly entirely. When False they are still returned, flagged via Field.read_only so callers can show them without sending them.

False

Returns:

Type Description
list of Field

Ordered descriptors for every path, query, header and body field.

create_app()

Create the demo OpenAPI form.

Returns:

Type Description
OpenAPIForm

A form for the POST /anything httpbin endpoint.

find_update_operations(openapi, path)

Return the methods on path that could update the record it returns.

Only the path is used as evidence, since request and response schemas routinely differ for the same record: the Swagger Petstore reuses Pet for both, while FastAPI typically responds with a model carrying server-assigned fields that the request model omits.

Parameters:

Name Type Description Default
openapi OpenAPI

The document to inspect.

required
path str

The templated path whose operations are considered.

required

Returns:

Type Description
list of str

Matching methods, most likely first (patch, then put, then post). Empty if the path defines none of them.

get_operation(openapi, path, method)

Return the :class:Operation for a path and HTTP method.

Parameters:

Name Type Description Default
openapi OpenAPI

The document to look the operation up in.

required
path str

The templated path, e.g. /pets/{petId}.

required
method str

The HTTP method, case-insensitive.

required

Returns:

Type Description
Operation

The matching operation, with any parameters declared on the path item merged into its own.

Raises:

Type Description
KeyError

If the path is unknown or the method is not defined for it.

load_openapi(source)

Load and validate an OpenAPI document.

Parameters:

Name Type Description Default
source str or dict or OpenAPI

Either an already parsed :class:~openapi_pydantic.OpenAPI model, a URL pointing at an openapi.json document, or the raw specification as a dictionary.

required

Returns:

Type Description
OpenAPI

The validated OpenAPI model.

response_schema(openapi, operation)

Return the JSON schema of an operation's success response.

The lowest 2xx response that declares a JSON body wins, falling back to a default response. This is the schema of the record a GET returns, which :class:~panel_openapi.editor.OpenAPIRecordEditor populates a form from.

Parameters:

Name Type Description Default
openapi OpenAPI

The document the operation belongs to.

required
operation Operation

The operation to inspect.

required

Returns:

Type Description
Schema or None

The response schema, or None if the operation declares no JSON success response.

schema_to_widget(name, schema, required=False)

Return a panel-material-ui widget for editing a schema value.

Parameters:

Name Type Description Default
name str

The field name, used as the widget label when no title is set.

required
schema Schema

The resolved JSON schema describing the value.

required
required bool

Whether the field is required. Recorded on the widget's tags so the form layer can validate and render it accordingly.

False

Returns:

Type Description
Widget

The widget best matching the schema. Values of type object or of an unknown type fall back to a JSON text area.

editor

Look up a record from an OpenAPI operation and edit it.

:class:OpenAPIRecordEditor pairs a read operation with an update operation on the same path: it fetches a record, populates a form from the response, and sends the edits back.

OpenAPIRecordEditor

Bases: Viewer

Fetch a record from an operation and edit it via another.

The editor composes two :class:~panel_openapi.form.OpenAPIForm instances: a lookup form for the read operation, and an edit form for the update operation. Loading a record populates the edit form, and saving sends the edits back to the same resource.

The update operation is discovered on the same path, preferring PATCH over PUT over POST, unless update_method names one. Because POST on a path means "update this" in some APIs and "create a subresource" in others, the resolved operation is always displayed.

A PATCH save sends only the fields that differ from the loaded record, matching the convention that omitted keys are left alone. PUT and POST send the full body.

Parameters:

Name Type Description Default
openapi str or dict or OpenAPI

The OpenAPI document, as a URL, raw dict or parsed model.

required
base_url str

The base URL requests are issued against.

required
path str

The templated path of the record, e.g. /pets/{petId}.

required
method str

The method used to read the record.

'get'
update_method str

The method used to save. Auto-detected when omitted.

None
headers dict

Static headers sent with every request.

None
show_lookup bool

Whether to render the lookup form. Set False when driving the editor with :meth:load or :meth:populate.

True
**params Any

Remaining parameters, notably confirm to have the Save button open a dialog listing the pending changes before sending them.

{}

Examples:

Point it at a path and let it find the update operation:

>>> editor = OpenAPIRecordEditor(
...     spec, base_url="https://petstore3.swagger.io/api/v3", path="/pet/{petId}"
... )

Or drive it without the lookup UI:

>>> editor = OpenAPIRecordEditor(spec, base_url=..., path=..., show_lookup=False)
>>> await editor.load(petId=7)
base_url = param.String(default='', doc='Base URL requests are issued against.') class-attribute instance-attribute
confirm = param.Boolean(default=False, doc='Whether the Save button opens a dialog showing the pending changes first.') class-attribute instance-attribute
editor = None instance-attribute
loaded property

Whether a record has been loaded.

lookup = OpenAPIForm(self._openapi, base_url=(self.base_url), path=(self.path), method=(self.method), headers=(self._headers)) instance-attribute
method = param.Selector(default='get', objects=['get', 'post', 'put', 'patch', 'delete'], doc='Method used to read the record.') class-attribute instance-attribute
path = param.String(default='', doc='Templated path of the record.') class-attribute instance-attribute
record = param.Dict(default=None, allow_None=True, doc='The record last loaded or saved, and the baseline a PATCH diffs against.') class-attribute instance-attribute
update_method = candidates[0] if candidates else None class-attribute instance-attribute
diff()

Return the edits pending against the loaded record.

Returns:

Type Description
dict

Field name to (old, new), covering every editable location, not just the body. Some APIs take updates as query parameters, e.g. the Swagger Petstore's POST /pet/{petId}.

load(**lookup) async

Fetch a record and populate the edit form.

Parameters:

Name Type Description Default
**lookup Any

Values for the read operation's inputs, e.g. petId=7. Widgets keep their current value when not given, which is what the Load button relies on.

{}

Returns:

Type Description
dict or None

The fetched record, or None if the request failed or did not return a JSON object.

populate(record)

Populate the edit form from a record without fetching it.

Parameters:

Name Type Description Default
record dict

The record to edit. Becomes the baseline a PATCH diffs against.

required
save() async

Send the edits and adopt the response as the new record.

Bypasses the confirmation dialog, which is only wired to the Save button, so calling this always saves.

Returns:

Type Description
dict or None

The saved record as the server returned it, or None if the save failed or returned no JSON object.

form

A Panel form that drives a single OpenAPI operation.

:class:OpenAPIForm introspects one path + method of an OpenAPI document, renders a panel-material-ui widget per parameter and JSON body property, and on submit issues the HTTP request and displays the response.

OpenAPIForm

Bases: Viewer

Auto-generated form for a single OpenAPI operation.

Setting :attr:path or :attr:method rebuilds the widgets for the newly referenced operation in place, and setting :attr:base_url redirects subsequent requests, so one form can be pointed at any operation in the document it was constructed with. To change both at once use form.param.update(path=..., method=...), which rebuilds only once and avoids a transient pair the document does not define.

Parameters:

Name Type Description Default
openapi str or dict or OpenAPI

The OpenAPI document, as a URL, raw dict or parsed model.

required
base_url str

The base URL requests are issued against, e.g. https://api.example.com.

required
path str

The templated operation path, e.g. /pets/{petId}.

required
method str

The HTTP method for the operation.

'get'
headers dict

Static headers (e.g. authentication) sent with every request. The mapping is read on each submit, so mutating it swaps credentials at runtime.

None

Attributes:

Name Type Description
form Column

The widgets and submit button. Rebuilt in place when the operation changes, so the container may be laid out once and kept.

response Column

The status and body of the most recent response, empty until submit.

base_url = param.String(default='', doc='Base URL requests are issued against.') class-attribute instance-attribute
fields property

Descriptors for the inputs of the current operation.

form = pmui.Column(sizing_mode='stretch_width') instance-attribute
method = param.Selector(default='get', objects=['get', 'post', 'put', 'patch', 'delete'], doc='HTTP method of the operation.') class-attribute instance-attribute
operation property

The operation the form currently targets.

path = param.String(default='', doc='Templated path of the operation.') class-attribute instance-attribute
response = pmui.Column(sizing_mode='stretch_width') instance-attribute
skip_read_only = param.Boolean(default=False, constant=True, doc='Whether to omit body properties marked readOnly entirely. When False they are shown as disabled widgets. Either way they are never sent, since the server does not accept them.') class-attribute instance-attribute
title = param.String(default='', doc='Human-readable title, derived from the operation unless set explicitly.') class-attribute instance-attribute
values property

The values that would be sent, keyed by field name.

widgets property

The current widgets, keyed by field name.

get_values(location=None)

Return the values that would be sent, keyed by field name.

JSON text areas are returned parsed. Fields left empty and fields marked readOnly are omitted, mirroring the request.

Parameters:

Name Type Description Default
location str

Restrict the result to one of path, query, header or body. All locations are included when omitted.

None

Returns:

Type Description
dict

Field name to value.

populate(record)

Set widget values from a record, ignoring what does not fit.

Population is deliberately tolerant: a record fetched from a live API routinely carries keys the request body does not accept, and values a widget cannot represent. Rather than raising, both are skipped and reported, so a partially populated form is still usable.

Parameters:

Name Type Description Default
record dict

Field name to value, e.g. the parsed body of a GET response.

required

Returns:

Type Description
list of str

Names of keys that could not be applied, either because no widget matched or because the value was rejected.

submit(extra=None) async

Issue the request for the current values and render the response.

Parameters:

Name Type Description Default
extra dict

Additional body properties merged into the payload, overriding the widget values. Used to send a subset or superset of the form, e.g. a PATCH diff.

None

Returns:

Type Description
Response or None

The response, or None if validation failed or the request could not be made. In both cases the reason is shown in :attr:response.

main

Demo entry point for panel-openapi.

Running panel serve src/panel_openapi/main.py builds an :class:OpenAPIForm for a small inline OpenAPI spec targeting httpbin.org <https://httpbin.org>_, so the generated form can be submitted against a live endpoint.

DEMO_SPEC = {'openapi': '3.0.0', 'info': {'title': 'httpbin demo', 'version': '1.0.0'}, 'paths': {'/anything': {'post': {'summary': 'Echo a payload', 'description': 'Send a JSON payload to httpbin and see it echoed back.', 'requestBody': {'required': True, 'content': {'application/json': {'schema': {'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string', 'title': 'Name'}, 'role': {'type': 'string', 'enum': ['admin', 'user', 'guest'], 'title': 'Role'}, 'age': {'type': 'integer', 'minimum': 0, 'maximum': 120, 'title': 'Age'}, 'subscribed': {'type': 'boolean', 'title': 'Subscribed'}}}}}}, 'responses': {'200': {'description': 'The echoed request.'}}}}}} module-attribute

create_app()

Create the demo OpenAPI form.

Returns:

Type Description
OpenAPIForm

A form for the POST /anything httpbin endpoint.

schema

Load and introspect OpenAPI documents.

This module wraps :mod:openapi_pydantic to load an OpenAPI schema from a URL or dictionary, resolve $ref references, locate a specific operation and flatten its parameters and JSON request body into a list of field descriptors that the widget layer can turn into inputs.

FieldLocation = Literal['path', 'query', 'header', 'body'] module-attribute

Field dataclass

A single input derived from an operation's parameters or request body.

Parameters:

Name Type Description Default
name str

The parameter or property name used when assembling the request.

required
location FieldLocation

Where the value belongs in the request (path, query, header or body).

required
schema Schema

The resolved JSON schema describing the value.

required
required bool

Whether the field must be provided.

False
read_only bool

Whether the schema marks the value readOnly. Such fields are returned by the server but never sent in a request.

False
location instance-attribute
name instance-attribute
read_only = False class-attribute instance-attribute
required = False class-attribute instance-attribute
schema instance-attribute

collect_fields(openapi, operation, skip_read_only=False)

Flatten an operation's parameters and JSON body into fields.

Parameters:

Name Type Description Default
openapi OpenAPI

The document the operation belongs to.

required
operation Operation

The operation to introspect.

required
skip_read_only bool

Whether to drop body properties marked readOnly entirely. When False they are still returned, flagged via Field.read_only so callers can show them without sending them.

False

Returns:

Type Description
list of Field

Ordered descriptors for every path, query, header and body field.

find_update_operations(openapi, path)

Return the methods on path that could update the record it returns.

Only the path is used as evidence, since request and response schemas routinely differ for the same record: the Swagger Petstore reuses Pet for both, while FastAPI typically responds with a model carrying server-assigned fields that the request model omits.

Parameters:

Name Type Description Default
openapi OpenAPI

The document to inspect.

required
path str

The templated path whose operations are considered.

required

Returns:

Type Description
list of str

Matching methods, most likely first (patch, then put, then post). Empty if the path defines none of them.

get_operation(openapi, path, method)

Return the :class:Operation for a path and HTTP method.

Parameters:

Name Type Description Default
openapi OpenAPI

The document to look the operation up in.

required
path str

The templated path, e.g. /pets/{petId}.

required
method str

The HTTP method, case-insensitive.

required

Returns:

Type Description
Operation

The matching operation, with any parameters declared on the path item merged into its own.

Raises:

Type Description
KeyError

If the path is unknown or the method is not defined for it.

load_openapi(source)

Load and validate an OpenAPI document.

Parameters:

Name Type Description Default
source str or dict or OpenAPI

Either an already parsed :class:~openapi_pydantic.OpenAPI model, a URL pointing at an openapi.json document, or the raw specification as a dictionary.

required

Returns:

Type Description
OpenAPI

The validated OpenAPI model.

resolve_ref(openapi, obj)

Resolve a $ref against the document's components.

Parameters:

Name Type Description Default
openapi OpenAPI

The document the reference is resolved against.

required
obj Reference or Schema or Parameter or None

The object to resolve. Non-reference objects are returned unchanged.

required

Returns:

Type Description
Any

The referenced component, or obj if it was not a reference.

response_schema(openapi, operation)

Return the JSON schema of an operation's success response.

The lowest 2xx response that declares a JSON body wins, falling back to a default response. This is the schema of the record a GET returns, which :class:~panel_openapi.editor.OpenAPIRecordEditor populates a form from.

Parameters:

Name Type Description Default
openapi OpenAPI

The document the operation belongs to.

required
operation Operation

The operation to inspect.

required

Returns:

Type Description
Schema or None

The response schema, or None if the operation declares no JSON success response.

widgets

Map OpenAPI/JSON schemas to panel-material-ui widgets.

The single public entry point is :func:schema_to_widget, which inspects a resolved :class:~openapi_pydantic.Schema and returns the most appropriate panel-material-ui widget for editing that value.

schema_to_widget(name, schema, required=False)

Return a panel-material-ui widget for editing a schema value.

Parameters:

Name Type Description Default
name str

The field name, used as the widget label when no title is set.

required
schema Schema

The resolved JSON schema describing the value.

required
required bool

Whether the field is required. Recorded on the widget's tags so the form layer can validate and render it accordingly.

False

Returns:

Type Description
Widget

The widget best matching the schema. Values of type object or of an unknown type fall back to a JSON text area.

unwrap_nullable(schema)

Collapse a nullable union to the single schema that carries the type.

anyOf/oneOf with exactly one non-null branch is how an optional value is expressed in OpenAPI 3.0 and by pydantic for T | None, which covers most fields of a PATCH request model. Unwrapping it means such fields get a real widget rather than a JSON text area. Genuine unions of two or more types are left alone.

Parameters:

Name Type Description Default
schema Schema

The schema to unwrap.

required

Returns:

Type Description
Schema

The sole non-null branch with the outer title and description preserved, or schema unchanged if it is not a nullable union.