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の不適切な扱いについて報告さ れている。ここまでわかっていればすぐに修正ができそうである。
結論
できない。