Files
pygeoapi/pygeoapi/models/config.py
T
Mathieu Tachon 39e6ea2223 Refactor code base to make it work with pydantic v2 (#1353)
* Refactor code base to make it work with pydantic v2

* Add typing-extensions to requirements.txt
2023-09-21 00:21:54 +02:00

104 lines
4.2 KiB
Python

# ****************************** -*-
# flake8: noqa
# =================================================================
#
# Authors: Sander Schaminee <sander.schaminee@geocat.net>
#
# Copyright (c) 2023 Sander Schaminee
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# =================================================================
from pydantic import BaseModel, Field
class APIRules(BaseModel):
""" Pydantic model for API design rules that must be adhered to. """
api_version: str = Field(pattern=r'^\d+\.\d+\..+$',
description="Semantic API version number.")
url_prefix: str = Field(
"",
description="If set, pygeoapi routes will be prepended with the "
"given URL path prefix (e.g. '/v1'). "
"Defaults to an empty string (no prefix)."
)
version_header: str = Field(
"",
description="If set, pygeoapi will set a response header with this "
"name and its value will hold the API version. "
"Defaults to an empty string (i.e. no header). "
"Often 'API-Version' or 'X-API-Version' are used here."
)
strict_slashes: bool = Field(
False,
description="If False (default), URL trailing slashes are allowed. "
"If True, pygeoapi will return a 404."
)
@staticmethod
def create(**rules_config) -> 'APIRules':
""" Returns a new APIRules instance for the current API version
and configured rules. """
obj = {
k: v for k, v in rules_config.items() if k in APIRules.model_fields
}
# Validation will fail if required `api_version` is missing
# or if `api_version` is not a semantic version number
return APIRules.model_validate(obj)
@property
def response_headers(self) -> dict:
""" Gets a dictionary of additional response headers for the current
API rules. Returns an empty dict if no rules apply. """
headers = {}
if self.version_header:
headers[self.version_header] = self.api_version
return headers
def get_url_prefix(self, style: str = None) -> str:
"""
Returns an API URL prefix to use in all paths.
May include a (partial) API version. See docs for syntax.
:param style: Set to 'django', 'flask' or 'starlette' to return a
specific prefix formatted for those frameworks.
If not set, only the prefix itself will be returned.
"""
if not self.url_prefix:
return ""
major, minor, build = self.api_version.split('.')
prefix = self.url_prefix.format(
api_version=self.api_version,
api_major=major,
api_minor=minor,
api_build=build
).strip('/')
style = (style or '').lower()
if style == 'django':
# Django requires the slash at the end
return rf"^{prefix}/"
elif style in ('flask', 'starlette'):
# Flask and Starlette need the slash in front
return f"/{prefix}"
# If no format is specified, return only the bare prefix
return prefix