Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvement/98402 add public api key #1189

Merged
merged 2 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 0 additions & 21 deletions .github/workflows/mirror-to-azure-devops.yml

This file was deleted.

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Zakensysteem voor toezichthouders en handhavers van de Gemeente Amsterdam voor d
- [Prerequisites](#prerequisites)
- [Getting up and running (Local development only)](#getting-up-and-running-local-development-only)
- [Running tests](#running-tests)
- [Accessing the API documentation](#accessing-the-api-documentation)
- [API documentation (Swagger)](#api-documentation-swagger)
- [Generating an access token](#generating-an-access-token)
- [Enabling local development environment variables](#enabling-local-development-environment-variables)
- [Enabling Keycloak authentication for a locally run zaken-frontend](#enabling-keycloak-authentication-for-a-locally-run-zaken-frontend)
Expand Down Expand Up @@ -88,7 +88,7 @@ To run tests for a specific module, add a path:
docker compose run --rm zaak-gateway python manage.py test apps/cases
```

## Accessing the API documentation
## API documentation (Swagger)

You can access the documentation at:
http://localhost:8080/api/v1/swagger/
Expand Down
34 changes: 21 additions & 13 deletions app/apps/fines/api_queries_belastingen.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,32 @@
logger = logging.getLogger(__name__)


@retry(stop=stop_after_attempt(3), after=after_log(logger, logging.ERROR))
def get_fines(id):
def get_fines(id, use_retry=True):
"""
Search the Belasting API for fines with case_id identification
"""
parameter = {"identificatienummer": id}
header = {"authorization": f"Bearer {settings.BELASTING_API_ACCESS_TOKEN}"}

response = requests.get(
url=settings.BELASTING_API_URL,
headers=header,
params=parameter,
verify="/usr/local/share/ca-certificates/adp_rootca.crt",
timeout=6,
)
response.raise_for_status()
def _get_fines_internal():
parameter = {"identificatienummer": id}
header = {"authorization": f"Bearer {settings.BELASTING_API_ACCESS_TOKEN}"}

return response.json()
response = requests.get(
url=settings.BELASTING_API_URL,
headers=header,
params=parameter,
verify="/usr/local/share/ca-certificates/adp_rootca.crt",
timeout=6,
)
response.raise_for_status()

return response.json()

if use_retry:
_get_fines_internal = retry(
stop=stop_after_attempt(3), after=after_log(logger, logging.ERROR)
)(_get_fines_internal)

return _get_fines_internal()


def get_mock_fines(case_id):
Expand Down
115 changes: 73 additions & 42 deletions app/apps/health/health_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
from django.conf import settings
from health_check.backends import BaseHealthCheckBackend
from health_check.exceptions import ServiceUnavailable
from requests.exceptions import HTTPError
from requests.exceptions import HTTPError, SSLError, Timeout
from utils.api_queries_bag import do_bag_search_nummeraanduiding_id_by_bag_id
from utils.api_queries_toeristische_verhuur import (
get_bag_vakantieverhuur_registrations,
get_bsn_vakantieverhuur_registrations,
Expand All @@ -15,7 +16,7 @@
)

logger = logging.getLogger(__name__)
timeout_in_sec = 6
timeout_in_sec = 10


class APIServiceCheckBackend(BaseHealthCheckBackend):
Expand All @@ -31,19 +32,14 @@ def get_api_url(self):
return self.api_url

def check_status(self):
"""Check service by opening and closing a broker channel."""
logger.info("Checking status of API url...")
api_url = self.get_api_url()
assert api_url, "The given api_url should be set"
if api_url is None:
self.add_error(ServiceUnavailable("API URL is not set."))
return

try:
response = requests.get(api_url, timeout=timeout_in_sec)
response.raise_for_status()
except AssertionError as e:
logger.error(e)
self.add_error(
ServiceUnavailable("The given API endpoint has not been set"),
e,
)
except ConnectionRefusedError as e:
logger.error(e)
self.add_error(
Expand All @@ -53,10 +49,13 @@ def check_status(self):
except HTTPError as e:
logger.error(e)
self.add_error(ServiceUnavailable(f"Service not found. {api_url}"))
except requests.exceptions.Timeout:
except Timeout:
self.add_error(
ServiceUnavailable(f"Exceeded timeout of {timeout_in_sec} seconds")
ServiceUnavailable(f"Exceeded timeout of {timeout_in_sec} seconds.")
)
except SSLError as e:
logger.error(e)
self.add_error(ServiceUnavailable("SSL error."))
except BaseException as e:
logger.error(e)
self.add_error(ServiceUnavailable("Unknown error"), e)
Expand All @@ -80,16 +79,6 @@ class BAGAtlasServiceCheck(APIServiceCheckBackend):
verbose_name = "BAG Atlas"


class BAGNummeraanduidingenServiceCheck(APIServiceCheckBackend):
"""
Endpoint for checking the BAG Nummeraanduidingen Service API
"""

critical_service = True
api_url = settings.BAG_API_NUMMERAANDUIDING_SEARCH_URL
verbose_name = "BAG Nummeraanduidingen"


class BAGVerblijfsobjectServiceCheck(APIServiceCheckBackend):
"""
Endpoint for checking the BAG Verblijfsobject Service API Endpoint
Expand All @@ -110,6 +99,33 @@ class BRPServiceCheck(APIServiceCheckBackend):
verbose_name = "BRP"


class BAGNummeraanduidingenServiceCheck(BaseHealthCheckBackend):
"""
Endpoint for checking the BAG Nummeraanduidingen API
"""

critical_service = True
verbose_name = "BAG Nummeraanduidingen"

def check_status(self):
try:
response = do_bag_search_nummeraanduiding_id_by_bag_id(
settings.BAG_ID_AMSTEL_1
)
message = response.get("message")
if message:
self.add_error(ServiceUnavailable(f"{message}"), message)
except HTTPError as e:
logger.error(e)
self.add_error(ServiceUnavailable(f"HTTPError {e.response.status_code}."))
except Exception as e:
logger.error(e)
self.add_error(ServiceUnavailable(f"Failed {e}"), e)

def identifier(self):
return self.verbose_name


class CeleryExecuteTask(BaseHealthCheckBackend):
def check_status(self):
result = debug_task.apply_async(ignore_result=False)
Expand All @@ -126,9 +142,12 @@ def check_status(self):

try:
# The id doesn't matter, as long an authenticated request is succesful.
get_fines("foo-id")
get_fines("foo-id", use_retry=False)
except SSLError as e:
logger.error(e)
self.add_error(ServiceUnavailable("SSL error."))
except Exception as e:
self.add_error(ServiceUnavailable("Failed"), e)
self.add_error(ServiceUnavailable(f"Failed {e}"), e)


class DecosJoinCheck(BaseHealthCheckBackend):
Expand All @@ -143,9 +162,9 @@ def check_status(self):
# The address doesn't matter, as long an authenticated request is succesful. Amstel 1 ;)
path = "items/90642DCCC2DB46469657C3D0DF0B1ED7/COBJECTS?filter=PHONE3 eq '0363010012143319'"
response = DecosJoinRequest().get(path)
assert response, "Could not reach Decos Join"
assert response, "Could not reach Decos Join."
except Exception as e:
self.add_error(ServiceUnavailable("Failed"), e)
self.add_error(ServiceUnavailable(f"{e}"), e)


class KeycloakCheck(APIServiceCheckBackend):
Expand All @@ -170,8 +189,11 @@ def get_api_url(self):
from zgw_consumers.constants import APITypes
from zgw_consumers.models import Service

zaken_service = Service.objects.filter(api_type=APITypes.zrc).get()
return zaken_service.api_root
try:
zaken_service = Service.objects.filter(api_type=APITypes.zrc).get()
return zaken_service.api_root
except Service.DoesNotExist:
return None


class OpenZaakZakenCatalogus(APIServiceCheckBackend):
Expand All @@ -186,8 +208,11 @@ def get_api_url(self):
from zgw_consumers.constants import APITypes
from zgw_consumers.models import Service

catalogi_service = Service.objects.filter(api_type=APITypes.ztc).get()
return catalogi_service.api_root
try:
catalogi_service = Service.objects.filter(api_type=APITypes.ztc).get()
return catalogi_service.api_root
except Service.DoesNotExist:
return None


class OpenZaakZakenAlfresco(APIServiceCheckBackend):
Expand All @@ -202,8 +227,11 @@ def get_api_url(self):
from zgw_consumers.constants import APITypes
from zgw_consumers.models import Service

documenten_service = Service.objects.filter(api_type=APITypes.drc).get()
return documenten_service.api_root
try:
documenten_service = Service.objects.filter(api_type=APITypes.drc).get()
return documenten_service.api_root
except Service.DoesNotExist:
return None


class VakantieVerhuurRegistratieCheck(BaseHealthCheckBackend):
Expand Down Expand Up @@ -262,15 +290,17 @@ def check_status(self):
}

try:
response = get_vakantieverhuur_meldingen(
get_vakantieverhuur_meldingen(
settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_HEALTH_CHECK_BAG_ID,
query_params=params,
use_retry=False,
)
assert response, "Could not reach Toeristischeverhuur.nl"

except HTTPError as e:
logger.error(e)
self.add_error(ServiceUnavailable(f"HTTPError {e.response.status_code}."))
except Exception as e:
logger.error(e)
self.add_error(ServiceUnavailable("Failed"), e)
self.add_error(ServiceUnavailable(f"Failed {e}"), e)
else:
logger.info(
"Connection established. Toeristischeverhuur.nl API connection is healthy."
Expand All @@ -284,9 +314,10 @@ class PowerBrowser(BaseHealthCheckBackend):

def check_status(self):
try:
response = PowerbrowserRequest().get_vergunningen_with_bag_id(
settings.BAG_ID_AMSTEL_1
)
assert response, "Could not reach PowerBrowser"
PowerbrowserRequest().get_vergunningen_with_bag_id(settings.BAG_ID_AMSTEL_1)
except HTTPError as e:
logger.error(e)
self.add_error(ServiceUnavailable(f"HTTPError {e.response.status_code}."))
except Exception as e:
self.add_error(ServiceUnavailable("Failed"), e)
logger.error(e)
self.add_error(ServiceUnavailable(f"Failed {e}"), e)
6 changes: 6 additions & 0 deletions app/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,12 @@
"BAG_API_VERBLIJFSOBJECT_URL",
"https://api.data.amsterdam.nl/bag/v1.1/verblijfsobject/",
)
# API key for the public Amsterdam API (api.data.amsterdam.nl).
# This key is NOT used for authorization, but to identify who is using the API for communication purposes.
BAG_API_PUBLIC_KEY = os.getenv(
"BAG_API_PUBLIC_KEY",
"eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJzdWIiOjMxNjQ2NDI4NzA1MzQ4NzI1NTEsImV4cCI6MTczODA3MDQ4N30.sGNs0EIRcdyUv76X1J1q46Y4kAIHSqHR1fca-srQlIQnV0aWduQn5xTlGQM1lvZCDk_F5qWf0__8u1jcYDMlDg",
)
# Bag_id of Amstel 1 for testing purposes.
BAG_ID_AMSTEL_1 = os.getenv(
"BAG_ID_AMSTEL_1",
Expand Down
4 changes: 4 additions & 0 deletions app/utils/api_queries_bag.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

logger = logging.getLogger(__name__)

headers = {"x-api-key": settings.BAG_API_PUBLIC_KEY}


@retry(stop=stop_after_attempt(3), after=after_log(logger, logging.ERROR))
def do_bag_search_nummeraanduiding_id_by_bag_id(bag_id):
Expand All @@ -15,6 +17,7 @@ def do_bag_search_nummeraanduiding_id_by_bag_id(bag_id):
address_search = requests.get(
settings.BAG_API_NUMMERAANDUIDING_SEARCH_URL,
params={"adresseertVerblijfsobject.identificatie": bag_id},
headers=headers,
timeout=30,
)
return address_search.json()
Expand All @@ -34,6 +37,7 @@ def do_bag_search_nummeraanduiding_id_by_address(address):
address_search = requests.get(
settings.BAG_API_NUMMERAANDUIDING_SEARCH_URL,
params=params,
headers=headers,
timeout=30,
)
return address_search.json()
Expand Down
38 changes: 24 additions & 14 deletions app/utils/api_queries_toeristische_verhuur.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,36 @@
logger = logging.getLogger(__name__)


@retry(stop=stop_after_attempt(3), after=after_log(logger, logging.ERROR))
def get_vakantieverhuur_meldingen(bag_id, query_params):
def get_vakantieverhuur_meldingen(bag_id, query_params, use_retry=True):
"""
Get the Vakantieverhuur meldingen from the Toeristische Verhuur register
"""
header = {
"x-api-key": settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_ACCESS_TOKEN
}
url = f"{settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_URL}meldingen/{bag_id}"

response = requests.get(
url=url,
params=query_params,
headers=header,
timeout=30,
)
def _get_vakantieverhuur_meldingen_internal():
header = {
"x-api-key": settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_ACCESS_TOKEN
}
url = (
f"{settings.VAKANTIEVERHUUR_TOERISTISCHE_VERHUUR_API_URL}meldingen/{bag_id}"
)

response.raise_for_status()
response = requests.get(
url=url,
params=query_params,
headers=header,
timeout=30,
)

response.raise_for_status()

return response.json(), response.status_code

if use_retry:
_get_vakantieverhuur_meldingen_internal = retry(
stop=stop_after_attempt(3), after=after_log(logger, logging.ERROR)
)(_get_vakantieverhuur_meldingen_internal)

return response.json(), response.status_code
return _get_vakantieverhuur_meldingen_internal()


@retry(stop=stop_after_attempt(3), after=after_log(logger, logging.ERROR))
Expand Down
Loading