fix: validate OpenAPI spec (#1528)

* init api check test

* Fix openAPI issues

Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
This commit is contained in:
Philipp Fischbeck 2022-08-07 02:54:29 +02:00 committed by GitHub
parent 505e594758
commit 34cd6eb687
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 113 additions and 12 deletions

View File

@ -16,12 +16,12 @@ const prefix = "/api";
const routes = { const routes = {
usersSelf: `${prefix}/users/self`, usersSelf: `${prefix}/users/self`,
passwordReset: `${prefix}/users/reset-password`, passwordReset: `${prefix}/users/reset-password`,
passwordChange: `${prefix}/users/password`,
users: `${prefix}/users`, users: `${prefix}/users`,
usersIdImage: (id: string) => `${prefix}/users/${id}/image`, usersIdImage: (id: string) => `${prefix}/users/${id}/image`,
usersIdResetPassword: (id: string) => `${prefix}/users/${id}/reset-password`, usersIdResetPassword: (id: string) => `${prefix}/users/${id}/reset-password`,
usersId: (id: string) => `${prefix}/users/${id}`, usersId: (id: string) => `${prefix}/users/${id}`,
usersIdPassword: (id: string) => `${prefix}/users/${id}/password`,
usersIdFavorites: (id: string) => `${prefix}/users/${id}/favorites`, usersIdFavorites: (id: string) => `${prefix}/users/${id}/favorites`,
usersIdFavoritesSlug: (id: string, slug: string) => `${prefix}/users/${id}/favorites/${slug}`, usersIdFavoritesSlug: (id: string, slug: string) => `${prefix}/users/${id}/favorites/${slug}`,
@ -45,8 +45,8 @@ export class UserApi extends BaseCRUDAPI<UserIn, UserOut, UserBase> {
return await this.requests.get<UserFavorites>(routes.usersIdFavorites(id)); return await this.requests.get<UserFavorites>(routes.usersIdFavorites(id));
} }
async changePassword(id: string, changePassword: ChangePassword) { async changePassword(changePassword: ChangePassword) {
return await this.requests.put(routes.usersIdPassword(id), changePassword); return await this.requests.put(routes.passwordChange, changePassword);
} }
async createAPIToken(tokenName: LongLiveTokenIn) { async createAPIToken(tokenName: LongLiveTokenIn) {

View File

@ -161,7 +161,7 @@ export default defineComponent({
if (!userCopy.value?.id) { if (!userCopy.value?.id) {
return; return;
} }
const { response } = await api.users.changePassword(userCopy.value.id, { const { response } = await api.users.changePassword({
currentPassword: password.current, currentPassword: password.current,
newPassword: password.newOne, newPassword: password.newOne,
}); });

View File

@ -10,6 +10,5 @@ router.include_router(all_recipe_routes.router, prefix=prefix, tags=["Recipe: Qu
router.include_router(recipe_crud_routes.router_exports) router.include_router(recipe_crud_routes.router_exports)
router.include_router(recipe_crud_routes.router) router.include_router(recipe_crud_routes.router)
router.include_router(comments.router, prefix=prefix, tags=["Recipe: Comments"]) router.include_router(comments.router, prefix=prefix, tags=["Recipe: Comments"])
router.include_router(bulk_actions.router, prefix=prefix)
router.include_router(bulk_actions.router, prefix=prefix, tags=["Recipe: Bulk Exports"]) router.include_router(bulk_actions.router, prefix=prefix, tags=["Recipe: Bulk Exports"])
router.include_router(shared_routes.router, prefix=prefix, tags=["Recipe: Shared"]) router.include_router(shared_routes.router, prefix=prefix, tags=["Recipe: Shared"])

View File

@ -85,7 +85,7 @@ class UserController(BaseUserController):
return SuccessResponse.respond("User updated") return SuccessResponse.respond("User updated")
@user_router.put("/{item_id}/password") @user_router.put("/password")
def update_password(self, password_change: ChangePassword): def update_password(self, password_change: ChangePassword):
"""Resets the User Password""" """Resets the User Password"""
if not verify_password(password_change.current_password, self.user.password): if not verify_password(password_change.current_password, self.user.password):

View File

@ -82,11 +82,13 @@ class UserBase(MealieModel):
} }
schema_extra = { schema_extra = {
"username": "ChangeMe", "example": {
"fullName": "Change Me", "username": "ChangeMe",
"email": "changeme@email.com", "fullName": "Change Me",
"group": settings.DEFAULT_GROUP, "email": "changeme@email.com",
"admin": "false", "group": settings.DEFAULT_GROUP,
"admin": "false",
}
} }

93
poetry.lock generated
View File

@ -581,6 +581,22 @@ MarkupSafe = ">=2.0"
[package.extras] [package.extras]
i18n = ["Babel (>=2.7)"] i18n = ["Babel (>=2.7)"]
[[package]]
name = "jsonschema"
version = "4.9.0"
description = "An implementation of JSON Schema validation for Python"
category = "dev"
optional = false
python-versions = ">=3.7"
[package.dependencies]
attrs = ">=17.4.0"
pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2"
[package.extras]
format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"]
format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"]
[[package]] [[package]]
name = "jstyleson" name = "jstyleson"
version = "0.0.2" version = "0.0.2"
@ -769,6 +785,38 @@ rsa = ["cryptography (>=3.0.0)"]
signals = ["blinker (>=1.4.0)"] signals = ["blinker (>=1.4.0)"]
signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"]
[[package]]
name = "openapi-schema-validator"
version = "0.2.3"
description = "OpenAPI schema validation for Python"
category = "dev"
optional = false
python-versions = ">=3.7.0,<4.0.0"
[package.dependencies]
jsonschema = ">=3.0.0,<5.0.0"
[package.extras]
isodate = ["isodate"]
strict-rfc3339 = ["strict-rfc3339"]
rfc3339-validator = ["rfc3339-validator"]
[[package]]
name = "openapi-spec-validator"
version = "0.4.0"
description = "OpenAPI 2.0 (aka Swagger) and OpenAPI 3.0 spec validator"
category = "dev"
optional = false
python-versions = ">=3.7.0,<4.0.0"
[package.dependencies]
jsonschema = ">=3.2.0,<5.0.0"
openapi-schema-validator = ">=0.2.0,<0.3.0"
PyYAML = ">=5.1"
[package.extras]
requests = ["requests"]
[[package]] [[package]]
name = "packaging" name = "packaging"
version = "21.3" version = "21.3"
@ -1027,6 +1075,14 @@ python-versions = "*"
html5lib = "*" html5lib = "*"
rdflib = "*" rdflib = "*"
[[package]]
name = "pyrsistent"
version = "0.18.1"
description = "Persistent/Functional/Immutable data structures"
category = "dev"
optional = false
python-versions = ">=3.7"
[[package]] [[package]]
name = "pytest" name = "pytest"
version = "6.2.5" version = "6.2.5"
@ -1563,7 +1619,7 @@ pgsql = ["psycopg2-binary"]
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.10" python-versions = "^3.10"
content-hash = "99607fe4da1369b768d0ed90300a32b1374a1f78e0eb06ac0c04bfb0cde0b7b9" content-hash = "8eeaaa2bd62d5448fc93d003c6c132056ab40c31f63a5b9fdd558bbaa2cab63e"
[metadata.files] [metadata.files]
aiofiles = [ aiofiles = [
@ -1842,6 +1898,10 @@ jinja2 = [
{file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"},
{file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"},
] ]
jsonschema = [
{file = "jsonschema-4.9.0-py3-none-any.whl", hash = "sha256:5d0be0cd1b670438b71c3d3145b2abba1f9d197e3e91adc4c4bae4c0e114e252"},
{file = "jsonschema-4.9.0.tar.gz", hash = "sha256:df10e65c8f3687a48e93d0d348ce0ce5f897b5a28e9bbcbbe8f7c7eaf019e850"},
]
jstyleson = [ jstyleson = [
{file = "jstyleson-0.0.2.tar.gz", hash = "sha256:680003f3b15a2959e4e6a351f3b858e3c07dd3e073a0d54954e34d8ea5e1308e"}, {file = "jstyleson-0.0.2.tar.gz", hash = "sha256:680003f3b15a2959e4e6a351f3b858e3c07dd3e073a0d54954e34d8ea5e1308e"},
] ]
@ -1986,6 +2046,14 @@ oauthlib = [
{file = "oauthlib-3.2.0-py3-none-any.whl", hash = "sha256:6db33440354787f9b7f3a6dbd4febf5d0f93758354060e802f6c06cb493022fe"}, {file = "oauthlib-3.2.0-py3-none-any.whl", hash = "sha256:6db33440354787f9b7f3a6dbd4febf5d0f93758354060e802f6c06cb493022fe"},
{file = "oauthlib-3.2.0.tar.gz", hash = "sha256:23a8208d75b902797ea29fd31fa80a15ed9dc2c6c16fe73f5d346f83f6fa27a2"}, {file = "oauthlib-3.2.0.tar.gz", hash = "sha256:23a8208d75b902797ea29fd31fa80a15ed9dc2c6c16fe73f5d346f83f6fa27a2"},
] ]
openapi-schema-validator = [
{file = "openapi-schema-validator-0.2.3.tar.gz", hash = "sha256:2c64907728c3ef78e23711c8840a423f0b241588c9ed929855e4b2d1bb0cf5f2"},
{file = "openapi_schema_validator-0.2.3-py3-none-any.whl", hash = "sha256:9bae709212a19222892cabcc60cafd903cbf4b220223f48583afa3c0e3cc6fc4"},
]
openapi-spec-validator = [
{file = "openapi-spec-validator-0.4.0.tar.gz", hash = "sha256:97f258850afc97b048f7c2653855e0f88fa66ac103c2be5077c7960aca2ad49a"},
{file = "openapi_spec_validator-0.4.0-py3-none-any.whl", hash = "sha256:06900ac4d546a1df3642a779da0055be58869c598e3042a2fef067cfd99d04d0"},
]
packaging = [ packaging = [
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
@ -2218,6 +2286,29 @@ pyrdfa3 = [
{file = "pyRdfa3-3.5.3-py3-none-any.whl", hash = "sha256:4da7ed49e8f524b573ed67e4f7bc7f403bff3be00546d7438fe263c924a91ccf"}, {file = "pyRdfa3-3.5.3-py3-none-any.whl", hash = "sha256:4da7ed49e8f524b573ed67e4f7bc7f403bff3be00546d7438fe263c924a91ccf"},
{file = "pyRdfa3-3.5.3.tar.gz", hash = "sha256:157663a92b87df345b6f69bde235dff5f797891608e12fe1e4fa8dad687131ae"}, {file = "pyRdfa3-3.5.3.tar.gz", hash = "sha256:157663a92b87df345b6f69bde235dff5f797891608e12fe1e4fa8dad687131ae"},
] ]
pyrsistent = [
{file = "pyrsistent-0.18.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:df46c854f490f81210870e509818b729db4488e1f30f2a1ce1698b2295a878d1"},
{file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d45866ececf4a5fff8742c25722da6d4c9e180daa7b405dc0a2a2790d668c26"},
{file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ed6784ceac462a7d6fcb7e9b663e93b9a6fb373b7f43594f9ff68875788e01e"},
{file = "pyrsistent-0.18.1-cp310-cp310-win32.whl", hash = "sha256:e4f3149fd5eb9b285d6bfb54d2e5173f6a116fe19172686797c056672689daf6"},
{file = "pyrsistent-0.18.1-cp310-cp310-win_amd64.whl", hash = "sha256:636ce2dc235046ccd3d8c56a7ad54e99d5c1cd0ef07d9ae847306c91d11b5fec"},
{file = "pyrsistent-0.18.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e92a52c166426efbe0d1ec1332ee9119b6d32fc1f0bbfd55d5c1088070e7fc1b"},
{file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7a096646eab884bf8bed965bad63ea327e0d0c38989fc83c5ea7b8a87037bfc"},
{file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cdfd2c361b8a8e5d9499b9082b501c452ade8bbf42aef97ea04854f4a3f43b22"},
{file = "pyrsistent-0.18.1-cp37-cp37m-win32.whl", hash = "sha256:7ec335fc998faa4febe75cc5268a9eac0478b3f681602c1f27befaf2a1abe1d8"},
{file = "pyrsistent-0.18.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6455fc599df93d1f60e1c5c4fe471499f08d190d57eca040c0ea182301321286"},
{file = "pyrsistent-0.18.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6"},
{file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bfe2388663fd18bd8ce7db2c91c7400bf3e1a9e8bd7d63bf7e77d39051b85ec"},
{file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e3e1fcc45199df76053026a51cc59ab2ea3fc7c094c6627e93b7b44cdae2c8c"},
{file = "pyrsistent-0.18.1-cp38-cp38-win32.whl", hash = "sha256:b568f35ad53a7b07ed9b1b2bae09eb15cdd671a5ba5d2c66caee40dbf91c68ca"},
{file = "pyrsistent-0.18.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1b96547410f76078eaf66d282ddca2e4baae8964364abb4f4dcdde855cd123a"},
{file = "pyrsistent-0.18.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5"},
{file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bc66318fb7ee012071b2792024564973ecc80e9522842eb4e17743604b5e045"},
{file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:914474c9f1d93080338ace89cb2acee74f4f666fb0424896fcfb8d86058bf17c"},
{file = "pyrsistent-0.18.1-cp39-cp39-win32.whl", hash = "sha256:1b34eedd6812bf4d33814fca1b66005805d3640ce53140ab8bbb1e2651b0d9bc"},
{file = "pyrsistent-0.18.1-cp39-cp39-win_amd64.whl", hash = "sha256:e24a828f57e0c337c8d8bb9f6b12f09dfdf0273da25fda9e314f0b684b415a07"},
{file = "pyrsistent-0.18.1.tar.gz", hash = "sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96"},
]
pytest = [ pytest = [
{file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
{file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},

View File

@ -59,6 +59,7 @@ types-requests = "^2.27.12"
types-urllib3 = "^1.26.11" types-urllib3 = "^1.26.11"
pre-commit = "^2.17.0" pre-commit = "^2.17.0"
types-python-dateutil = "^2.8.18" types-python-dateutil = "^2.8.18"
openapi-spec-validator = "^0.4.0"
[build-system] [build-system]

View File

@ -0,0 +1,8 @@
from openapi_spec_validator import validate_v3_spec
from mealie.app import app
def test_validate_open_api_spec():
open_api = app.openapi()
validate_v3_spec(open_api)