|
1 | 1 | import logging |
2 | | -import urllib |
3 | | -from typing import Optional, Iterable |
4 | | - |
5 | | -import requests |
6 | | -from .models.bundle import Bundle |
7 | | - |
8 | 2 | from .server import FHIRServer, FHIRUnauthorizedException, FHIRNotFoundException |
9 | 3 |
|
10 | 4 | __version__ = '4.3.0' |
@@ -244,119 +238,3 @@ def from_state(self, state): |
244 | 238 |
|
245 | 239 | def save_state (self): |
246 | 240 | self._save_func(self.state) |
247 | | - |
248 | | - # MARK: Pagination |
249 | | - def _fetch_next_page(self, bundle: Bundle) -> Optional[Bundle]: |
250 | | - """ |
251 | | - Fetch the next page of results using the `next` link provided in the bundle. |
252 | | -
|
253 | | - Args: |
254 | | - bundle (Bundle): The FHIR Bundle containing the `next` link. |
255 | | -
|
256 | | - Returns: |
257 | | - Optional[Bundle]: The next page of results as a FHIR Bundle, or None if no "next" link is found. |
258 | | - """ |
259 | | - next_link = self._get_next_link(bundle) |
260 | | - if next_link: |
261 | | - sanitized_next_link = self._sanitize_next_link(next_link) |
262 | | - return self._execute_pagination_request(sanitized_next_link) |
263 | | - return None |
264 | | - |
265 | | - def _get_next_link(self, bundle: Bundle) -> Optional[str]: |
266 | | - """ |
267 | | - Extract the `next` link from the Bundle's links. |
268 | | -
|
269 | | - Args: |
270 | | - bundle (Bundle): The FHIR Bundle containing pagination links. |
271 | | -
|
272 | | - Returns: |
273 | | - Optional[str]: The URL of the next page if available, None otherwise. |
274 | | - """ |
275 | | - if not bundle.link: |
276 | | - return None |
277 | | - |
278 | | - for link in bundle.link: |
279 | | - if link.relation == "next": |
280 | | - return link.url |
281 | | - return None |
282 | | - |
283 | | - def _sanitize_next_link(self, next_link: str) -> str: |
284 | | - """ |
285 | | - Sanitize the `next` link to ensure it is safe to use. |
286 | | -
|
287 | | - Args: |
288 | | - next_link (str): The raw `next` link URL. |
289 | | -
|
290 | | - Returns: |
291 | | - str: The sanitized URL. |
292 | | -
|
293 | | - Raises: |
294 | | - ValueError: If the URL scheme or domain is invalid. |
295 | | - """ |
296 | | - parsed_url = urllib.parse.urlparse(next_link) |
297 | | - |
298 | | - # Validate scheme and netloc (domain) |
299 | | - if parsed_url.scheme not in ["http", "https"]: |
300 | | - raise ValueError("Invalid URL scheme in `next` link.") |
301 | | - if not parsed_url.netloc: |
302 | | - raise ValueError("Invalid URL domain in `next` link.") |
303 | | - |
304 | | - # Additional sanitization if necessary, e.g., removing dangerous query parameters |
305 | | - query_params = urllib.parse.parse_qs(parsed_url.query) |
306 | | - sanitized_query = {k: v for k, v in query_params.items()} |
307 | | - |
308 | | - # Rebuild the sanitized URL |
309 | | - sanitized_url = urllib.parse.urlunparse( |
310 | | - ( |
311 | | - parsed_url.scheme, |
312 | | - parsed_url.netloc, |
313 | | - parsed_url.path, |
314 | | - parsed_url.params, |
315 | | - urllib.parse.urlencode(sanitized_query, doseq=True), |
316 | | - parsed_url.fragment, |
317 | | - ) |
318 | | - ) |
319 | | - |
320 | | - return sanitized_url |
321 | | - |
322 | | - def _execute_pagination_request(self, sanitized_url: str) -> Optional[Bundle]: |
323 | | - """ |
324 | | - Execute the request to retrieve the next page using the sanitized URL. |
325 | | -
|
326 | | - Args: |
327 | | - sanitized_url (str): The sanitized URL to fetch the next page. |
328 | | -
|
329 | | - Returns: |
330 | | - Optional[Bundle]: The next page of results as a FHIR Bundle, or None. |
331 | | -
|
332 | | - Raises: |
333 | | - HTTPError: If the request fails due to network issues or server errors. |
334 | | - """ |
335 | | - try: |
336 | | - # Use requests.get directly to make the HTTP request |
337 | | - response = requests.get(sanitized_url) |
338 | | - response.raise_for_status() |
339 | | - next_bundle_data = response.json() |
340 | | - next_bundle = Bundle(next_bundle_data) |
341 | | - |
342 | | - return next_bundle |
343 | | - |
344 | | - except requests.exceptions.HTTPError as e: |
345 | | - # Handle specific HTTP errors as needed, possibly including retry logic |
346 | | - raise e |
347 | | - |
348 | | - def iter_pages(self, first_bundle: Bundle) -> Iterable[Bundle]: |
349 | | - """ |
350 | | - Iterator that yields each page of results as a FHIR Bundle. |
351 | | -
|
352 | | - Args: |
353 | | - first_bundle (Bundle): The first Bundle to start pagination. |
354 | | -
|
355 | | - Yields: |
356 | | - Bundle: Each page of results as a FHIR Bundle. |
357 | | - """ |
358 | | - bundle = first_bundle |
359 | | - while bundle: |
360 | | - yield bundle |
361 | | - bundle = self._fetch_next_page(bundle) |
362 | | - |
0 commit comments