001/*-
002 * #%L
003 * Smile CDR - CDR
004 * %%
005 * Copyright (C) 2016 - 2026 Smile CDR, Inc.
006 * %%
007 * All rights reserved.
008 * #L%
009 */
010package ca.cdr.api.fhir.client;
011
012import ca.cdr.api.model.json.oauth.SmartConfigurationJson;
013import ca.uhn.fhir.jpa.bulk.export.model.BulkExportResponseJson;
014import ca.uhn.fhir.rest.api.server.bulk.BulkExportJobParameters;
015import ca.uhn.fhir.rest.client.api.IGenericClient;
016import jakarta.annotation.Nonnull;
017
018import java.time.Duration;
019
020/**
021 * An {@link IGenericClient} with the FHIR endpoint operations it does not model yet.
022 * <p>
023 * Each method here is a candidate for upstreaming into HAPI FHIR's {@link IGenericClient}. Once one
024 * is, it moves there and is removed from this interface.
025 * </p>
026 */
027public interface IExtendedGenericClient extends IGenericClient {
028
029        /**
030         * Fetches the endpoint's SMART App Launch discovery document from
031         * {@code [base]/.well-known/smart-configuration}.
032         *
033         * @return the discovery document. Every member is optional: a server with SMART disabled
034         *         returns an empty document, and one without the {@code sso-openid-connect} capability
035         *         omits {@code issuer} and {@code jwks_uri}.
036         * @throws AssertionError if the server does not answer {@code 200 OK}
037         * @see <a href="https://hl7.org/fhir/smart-app-launch/conformance.html">SMART App Launch: Conformance</a>
038         */
039        @Nonnull
040        SmartConfigurationJson getSmartConfiguration();
041
042        /**
043         * Kicks off an asynchronous Bulk Data export by {@code POST}ing the parameters as a FHIR
044         * {@code Parameters} resource with {@code Prefer: respond-async} and {@code Cache-Control: no-cache}.
045         * The latter makes the server start a new export job rather than reuse a recent one with the same
046         * parameters.
047         * <p>
048         * The export style picks the endpoint: {@code SYSTEM} (or none) uses {@code [base]/$export},
049         * {@code PATIENT} uses {@code [base]/Patient/$export}, and {@code GROUP} uses
050         * {@code [base]/Group/[groupId]/$export}. The output format defaults to
051         * {@code application/fhir+ndjson} when the parameters name none.
052         * </p>
053         *
054         * @param theParameters what to export: style, resource types, {@code _since}/{@code _until},
055         *                      type filters, patients, group and MDM expansion
056         * @return the status polling URL from the response's {@code Content-Location} header, to pass
057         *         to {@link #awaitBulkExport(String)}
058         * @throws IllegalArgumentException if a {@code GROUP} export has no group ID
059         * @throws AssertionError if the server does not answer {@code 202 Accepted} with a
060         *                        {@code Content-Location}
061         * @see <a href="https://hl7.org/fhir/uv/bulkdata/export.html">FHIR Bulk Data Access: Export</a>
062         */
063        @Nonnull
064        String startBulkExport(@Nonnull BulkExportJobParameters theParameters);
065
066        /**
067         * Polls a Bulk Data export's status URL until the export completes, for up to five minutes,
068         * once a second.
069         *
070         * @param thePollUrl the polling URL returned by {@link #startBulkExport(BulkExportJobParameters)}
071         * @return the completion manifest, listing the output files
072         * @throws AssertionError if the export fails, or is still running after five minutes
073         * @see #awaitBulkExport(String, Duration, Duration)
074         */
075        @Nonnull
076        BulkExportResponseJson awaitBulkExport(@Nonnull String thePollUrl);
077
078        /**
079         * Polls a Bulk Data export's status URL until the export completes.
080         * <p>
081         * A {@code 202 Accepted} means the export is still running, so polling continues. A
082         * {@code 200 OK} carries the completion manifest. Any other status means the export failed.
083         * </p>
084         *
085         * @param thePollUrl      the polling URL returned by {@link #startBulkExport(BulkExportJobParameters)}
086         * @param theTimeout      how long to keep polling before giving up
087         * @param thePollInterval how long to wait between polls
088         * @return the completion manifest, listing the output files
089         * @throws AssertionError if the server answers anything but {@code 200} or {@code 202}, giving
090         *                        the status and body, or if the export is still running when
091         *                        {@code theTimeout} passes, giving its last {@code X-Progress}
092         * @throws IllegalStateException if the thread is interrupted while waiting between polls
093         */
094        @Nonnull
095        BulkExportResponseJson awaitBulkExport(
096                        @Nonnull String thePollUrl, @Nonnull Duration theTimeout, @Nonnull Duration thePollInterval);
097}