essentials-openapi
essentials-openapi copied to clipboard
Cannot generate Markdown file from valid API definition in YAML
I cannot generate Markdown file from properly validated API definition file:
$ oad --verbose gen-docs -s docs/api/swagger.yaml -d api.md
[08/07/23 12:35:24] DEBUG Running in --verbose mode main.py:27
DEBUG Reading from file docs/api/swagger.yaml source.py:77
Traceback (most recent call last):
File "<redacted_path>/.venv/bin/oad", line 8, in <module>
sys.exit(main())
^^^^^^
File "<redacted_path>/.venv/lib/python3.11/site-packages/click/core.py", line 1157, in __call__
return self.main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<redacted_path>/.venv/lib/python3.11/site-packages/click/core.py", line 1078, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "<redacted_path>/.venv/lib/python3.11/site-packages/click/core.py", line 1688, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<redacted_path>/.venv/lib/python3.11/site-packages/click/core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<redacted_path>/.venv/lib/python3.11/site-packages/click/core.py", line 783, in invoke
return __callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<redacted_path>/.venv/lib/python3.11/site-packages/openapidocs/commands/docs.py", line 51, in generate_documents_command
generate_document(source, destination, style)
File "<redacted_path>/.venv/lib/python3.11/site-packages/openapidocs/mk/generate.py", line 14, in generate_document
html = handler.write()
^^^^^^^^^^^^^^^
File "<redacted_path>/.venv/lib/python3.11/site-packages/openapidocs/mk/v3/__init__.py", line 427, in write
operations=self.get_operations(),
^^^^^^^^^^^^^^^^^^^^^
File "<redacted_path>/.venv/lib/python3.11/site-packages/openapidocs/mk/v3/__init__.py", line 181, in get_operations
tag = self.get_tag(path_item) or ""
^^^^^^^^^^^^^^^^^^^^^^^
File "<redacted_path>/.venv/lib/python3.11/site-packages/openapidocs/mk/v3/__init__.py", line 219, in get_tag
tags = operation.get("tags")
^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
API definition file swagger.yaml (validated with https://github.com/OpenAPITools/openapi-generator):
openapi: 3.0.3
info:
title: My API
description: My API
version: 1.0.0
servers:
- url: 'http://localhost:8080/'
paths:
/client:
description: Client onboarding operations
post:
description: Onboard a new client
responses:
201:
description: Client onboarded successfully
content:
application/json:
schema:
$ref: '#/components/schemas/OnboardedClientDetails'
400:
description: Missing attribute in the payload
403:
description: Not authorized
422:
description: Payload formatted incorrectly
500:
description: Internal server error
requestBody:
description: Payload to be sent
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/OnboardClientRequest'
x-amazon-apigateway-integration:
type: "aws_proxy"
httpMethod: "POST"
uri:
Fn::Sub: "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:integration-layer-client-management/invocations"
responses:
default:
statusCode: "201"
passthroughBehavior: "when_no_match"
contentHandling: "CONVERT_TO_TEXT"
security:
- Authorize: [ ]
/client/{clientId}:
description: Operations on a specific client
delete:
description: Delete a given client
parameters:
- in: path
name: clientId
required: true
schema:
type: string
responses:
204:
description: Client deleted successfully
404:
description: Not available or user not authorized to see this client
500:
description: Internal server error
x-amazon-apigateway-integration:
httpMethod: "POST"
uri:
Fn::Sub: "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:integration-layer-client-management/invocations"
responses:
default:
statusCode: "204"
passthroughBehavior: "when_no_match"
contentHandling: "CONVERT_TO_TEXT"
type: "aws_proxy"
security:
- Authorize: [ ]
/otp:
description: OTP API key generation
parameters:
- in: query
name: systemId
required: true
schema:
type: string
description: Client identifier
example: '3907f492-3af3-4c0d-a09f-81c6ec0e4b3d'
- in: query
name: customerId
required: true
schema:
type: string
description: Customer Id
example: '121032'
post:
description: Generate OTP API key
responses:
200:
description: OTP API key generated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/OTPResponse'
400:
description: Missing attribute in the payload
409:
description: System already registered with different customerId
500:
description: Internal server error
x-amazon-apigateway-integration:
type: "aws_proxy"
httpMethod: "POST"
uri:
Fn::Sub: "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:otp/invocations"
responses:
default:
statusCode: "200"
passthroughBehavior: "when_no_match"
contentHandling: "CONVERT_TO_TEXT"
security:
- Authorize-otp: [ ]
components:
schemas:
OnboardClientRequest:
type: object
required:
- publicKey
properties:
publicKey:
type: string
description: Public key in PEM format
example: '-----BEGIN PUBLIC KEY-----\nPUBLIC\nKEY\nLINES\nSEPARATED\nWITH\n-----END PUBLIC KEY-----'
OnboardedClientDetails:
type: object
properties:
client_name:
type: string
description: Name of the client (equal to systemId with added timestamp)
example: '3907f492-3af3-4c0d-a09f-81c6ec0e4b3d_1685686753'
clientId:
type: string
description: Unique identifier of the client
example: '33333333334444444445555555555555444555555'
x5c:
type: string
description: x5c (X.509 certificate chain) indicates a chain of one or more PKIX certificates
example: "<redacted>"
OTPResponse:
type: object
properties:
otp:
type: string
description: OTP API key
example: '<redacted>'
In my virtual environment (venv) the following PyPi dependencies are used:
mkdocs-material==9.1.21
mkdocs-mermaid2-plugin==1.0.6
python-markdown-comments==1.1.0
essentials-openapi[full]==1.0.8
neoteroi-mkdocs==1.0.4
pymdown-extensions==10.1
My environment:
- OS: macOS Ventura 13.5
- Python: 3.11.4 (HomeBrew)
Am I missing something?
Same problem.
I have the suspect that is a problem with list structures in get_tag
Same problem. I have the suspect that is a problem with list structures in
get_tag
As @alexmarco mentions, the issue is in get_tag.
This code assumes that path items only contain operation items (which would return a python object that has the get() method). Based on the OpenAPI spec we see that the $ref, summary, and description field can be included, as well as, lists of server objects (servers) or parameter to reference mappings (parameters).
In the example above, for instance, the description field is being used and not finding a .get() method on the Python string.
paths:
/client:
description: Client onboarding operations
To address this, at the very least we will need to add a check if the path item is indeed an operation and otherwise skip handling it.
The more correct but involved solution is to add handlers for all the different path items.
Update: Also in my case, I have a list of parameters in the definition which gives me AttributeError: 'list' object has no attribute 'get' warning instead of a 'str'.