TL;DR
- Python製のOpenAPIライブラリであるopenapi-coreを用いて分割されたファイルを利用できるのかを確認した。
- openapi-core==0.14.2ではjsonschema.exceptions.RefResolutionErrorが発生し、依存ファイルを読み込めない。
- Github Issueに同様の問題が報告されている1が、まだ修正はされていない。
Abstract
openapi-coreで分割されたファイルを利用できるのかを確認したところできないことがわかった。
目的
OpenAPIのドキュメントを記述するとファイルサイズが大きくなる。そのため ファイルを分割するための仕組みがOpenAPIには定義されている。
openapi-coreはPython製のOpenAPIライブラリである。今回はopenapi-coreで 分割されたファイルを利用できるのかを確認した。
ファイル構成
.
├── example.py
├── index.org
└── spec
├── index.yaml
└── paths.yaml
1 directory, 4 files
example.py
OpenAPIのドキュメントを読み込むための簡易なスクリプト。
import yaml
from openapi_core import create_spec
with open("./spec/index.yaml") as fp:
data = yaml.safe_load(fp)
spec = create_spec(data)
print(spec)spec/index.yaml
OpenAPIのドキュメントのroot。
openapi: '3.0.3'
info:
title: Example
version: '1'
paths:
$ref: "file://spec/paths.yaml"spec/paths.yaml
spec/index.yaml から読み込まれるドキュメント。
/:
get:
responses:
'200':
description: example使用したライブラリとそのバージョン
openapi-core==0.14.2 openapi-schema-validator==0.1.5 openapi-spec-validator==0.3.1
実行
$ python3 example.py
結果
>>> Traceback (most recent call last):
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/jsonschema/validators.py", line 774, in resolve_from_url
document = self.store[url]
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/jsonschema/_utils.py", line 22, in __getitem__
return self.store[self.normalize(uri)]
KeyError: './paths.yaml'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/jsonschema/validators.py", line 777, in resolve_from_url
document = self.resolve_remote(url)
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/jsonschema/validators.py", line 863, in resolve_remote
with urlopen(uri) as url:
File "/usr/local/Cellar/[email protected]/3.9.5/Frameworks/Python.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 214, in urlopen
return opener.open(url, data, timeout)
File "/usr/local/Cellar/[email protected]/3.9.5/Frameworks/Python.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 501, in open
req = Request(fullurl, data)
File "/usr/local/Cellar/[email protected]/3.9.5/Frameworks/Python.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 320, in __init__
self.full_url = url
File "/usr/local/Cellar/[email protected]/3.9.5/Frameworks/Python.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 346, in full_url
self._parse()
File "/usr/local/Cellar/[email protected]/3.9.5/Frameworks/Python.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 375, in _parse
raise ValueError("unknown url type: %r" % self.full_url)
ValueError: unknown url type: './paths.yaml'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/opt/ng/symdon/pages/posts/1626478280/example.py", line 8, in <module>
print(create_spec(data))
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/openapi_core/spec/shortcuts.py", line 17, in create_spec
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/openapi_spec_validator/validators.py", line 49, in validate
for err in self.iter_errors(spec, spec_url=spec_url):
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/openapi_spec_validator/decorators.py", line 59, in wrapper
for err in errors:
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/openapi_spec_validator/validators.py", line 58, in iter_errors
for err in validator.iter_errors(spec):
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/jsonschema/validators.py", line 328, in iter_errors
for error in errors:
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/openapi_spec_validator/decorators.py", line 23, in wrapped
for res in func(validator, schema_element, instance, schema):
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/jsonschema/_validators.py", line 282, in properties
for error in validator.descend(
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/jsonschema/validators.py", line 344, in descend
for error in self.iter_errors(instance, schema):
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/jsonschema/validators.py", line 328, in iter_errors
for error in errors:
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/openapi_spec_validator/decorators.py", line 35, in wrapped
with self.instance_resolver.resolving(ref) as target:
File "/usr/local/Cellar/[email protected]/3.9.5/Frameworks/Python.framework/Versions/3.9/lib/python3.9/contextlib.py", line 117, in __enter__
return next(self.gen)
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/jsonschema/validators.py", line 754, in resolving
url, resolved = self.resolve(ref)
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/jsonschema/validators.py", line 766, in resolve
return url, self._remote_cache(url)
File "/Users/xxx/.venv/py39/lib/python3.9/site-packages/jsonschema/validators.py", line 779, in resolve_from_url
raise exceptions.RefResolutionError(exc)
jsonschema.exceptions.RefResolutionError: unknown url type: './paths.yaml'
>>>
$refに読み込みができるパスを設定するために別の形式の値を指定する
上記のエラーで unknown url type というエラーメッセージが出力された。
そのためschemaを指定するなど、値を変更しつつ読み込み可能なものが無いか
を試した。=file://絶対パス= を指定した場合、読み込むことができた。ただ
しこれらの挙動はOpenAPIの仕様2とは一致しない。
エラーが発生しない例
file://絶対パス を指定した場合、読み込むことができた。
paths:
$ref: "file:///opt/ng/symdon/pages/posts/1626478280/spec/paths.yaml"エラーが発生する例
例1
paths:
$ref: "file://paths.yaml"発生するエラー
jsonschema.exceptions.RefResolutionError: [Errno 2] No such file or directory: '//paths.yaml'
例2
paths:
$ref: "file://./paths.yaml"発生するエラー
jsonschema.exceptions.RefResolutionError: [Errno 2] No such file or directory: '/paths.yaml'
例3
paths:
$ref: "file://spec/paths.yaml"発生するエラー
jsonschema.exceptions.RefResolutionError: [Errno 2] No such file or directory: '/paths.yaml'
同様の問題を報告しているissue
Githubに同様の問題が報告されていないか、Pull Requestがないかを確認した。 Pull Requestはなかったが、Issueはポストされてい た1。RefResolverの不適切な扱いについて報告さ れている。ここまでわかっていればすぐに修正ができそうである。
結論
できない。