-
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
100 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,17 +3,106 @@ | |
> In the meantime, please consider looking at the extensive docs in the [Fasten Docs Repository](https://github.com/fastenhealth/docs/tree/main/technical) | ||
|
||
The Fasten Sources is a library that defines medical provider metadata (`definitions` - OpenID Metadata documents) | ||
and http clients (OAuth2/Smart-on-FHIR clients) which can be used to retrieve data from various Medical | ||
Providers (`clients`). | ||
The Fasten Sources is a library that defines healthcare institution API metadata (`definitions` - OpenID Metadata documents) | ||
and http clients (OAuth2/Smart-on-FHIR clients) which can be used to retrieve data from various healthcare institutions (`clients`). | ||
|
||
Development in this repositry is complicated for a couple of reasons: | ||
> In general Healthcare Institutions don't develop their own API's, instead they run a supported EHR Platform (Epic, Cerner, etc) with a custom domain. | ||
> This allows Fasten to write a single client for each Platform, and then use that client for all institutions running that Platform. | ||
Development in this repository is complicated for a couple of reasons: | ||
|
||
- writing a new OAuth client requires a client application registration & `client-id` (and sometimes a `client-secret`). | ||
- this registration can differ significantly between EHR systems. Some EHR's make the registration process easy, while others are incredibly convoluted. | ||
- as a developer intending to contribute your medical provider's OAuth2 client, you should document the registration process, and include it in your PR. | ||
- most files in this repository are generated classes - created via automation in `fasten-sources-gen` | ||
- This library can take a long time to build (the first time), as there are thousand's of generated go files. | ||
```bash | ||
go clean -cache | ||
time go build ./... | ||
# 1079.77s user 9.87s system 205% cpu 8:50.45 total | ||
``` | ||
|
||
However, it is still possible to develop & test OAuth2 clients. | ||
|
||
# Getting Started | ||
|
||
Before developing in this repository, you will need the following tools installed: | ||
|
||
- go 1.18+ | ||
- make | ||
- git | ||
|
||
Next, you can run the following commands: | ||
|
||
```bash | ||
# clone the repository | ||
git clone https://github.com/fastenhealth/fasten-sources.git` | ||
|
||
# change into the directory | ||
cd fasten-sources | ||
|
||
# start the "backend" server | ||
make serve-backend | ||
``` | ||
|
||
`make serve-backend` should automatically start a webserver and open a browser to [http://localhost:9999](http://localhost:9999) | ||
|
||
# Testing Connections | ||
|
||
Once the backend server is running, you can test connections to various EHR systems by selecting the "Sandbox" or "Production" radio button, and selecting the EHR you'd like to test. | ||
|
||
> When using "Sandbox", you will need to login using test account credentials. See [BETA.md](https://github.com/fastenhealth/docs/blob/main/BETA.md#sandbox-flavor) for credentials. | ||
> | ||
> When using "Production", you will need to login using your own personal credentials. | ||
![](./screenshots/connect.png) | ||
|
||
After completing the OAuth flow with your selected EHR, you will be redirected to the Callback URL, which will display the Authorization Code, Access Token Exchange Response and Patient ID. | ||
|
||
![](./screenshots/callback.png) | ||
|
||
|
||
# Provider Development | ||
|
||
When developing a new provider, the first step is to find the developer documentation for the provider. | ||
Usually this is done by searching `<EHR NAME> developer documentation` or `<EHR NAME> FHIR API` in your favorite search engine. | ||
|
||
However, Fasten may have already done this for you, as we keep track of EHR integration status in the [PLATFORM_LIST.md](./PLATFORM_LIST.md) file. | ||
|
||
## Registering a Client Application | ||
|
||
Once you've found the developer documentation for your EHR, you should follow their instructions for registering a client application. | ||
|
||
> During development, use your personal email & information for registering the client application. Once you've finished testing & development, | ||
> a Fasten maintainer will create another client application registration using the Fasten email & information, and then request production access. | ||
- **Scopes** - if you are required to request scopes during application registration, try to request the following `openid fhirUser profile patient/*.read offline_access` | ||
- **Confidential** - if given the option to register a public vs confidential client, choose **public** | ||
- **PKCE** - if given the option to register a client with or without PKCE, choose with **PKCE** | ||
- **Offline Access** - if given the option to register a client with or without offline access, choose with **offline access** | ||
|
||
## Testing new Client Application | ||
|
||
Once you've registered a client application, you should be able to test the OAuth2 flow using the backend server. | ||
|
||
- Open [http://localhost:9999](http://localhost:9999) in your browser | ||
- Scroll down to the "Define Custom Source" section and click it | ||
|
||
![](./screenshots/connect-custom.png) | ||
|
||
Use the information you received during client application registration to fill out the form. | ||
|
||
- **Source Type** - this should be a url-friendly short name for your EHR. For example, if you're developing a client for Kaiser Permanente, you might use `kaiser` or `kaiser_permanente` | ||
- **Authorization Endpoint** - this is the OAuth2 Authorization URL for your EHR. It should be listed in the developer documentation. | ||
- **Response Mode** - this is the OAuth2 Response Mode for your EHR. When supported use "fragment", otherwise use "query" (which should be supported by all EHR's) | ||
- **Client ID** - this is the OAuth2 Client ID for newly registered EHR application. | ||
- **Scopes** - these are the OAuth2 Scopes for your EHR. They should be listed in the developer documentation. | ||
- If you're unsure, use `openid fhirUser profile patient/*.read offline_access` | ||
- **Confidential** - this should be `true` if your EHR requires a `client-secret` for the OAuth2 flow. For Public apps, this should be `false` | ||
- If your app is Confidential, you will need to contact a Fasten maintainer to add the `client-secret` to the Lighthouse server for testing. `[email protected]` | ||
|
||
# Architecture | ||
|
||
> In general, Fasten Sources follow an inheritance model. Base and FHIR version specific classes/structs | ||
> define most complicated logic, while Platform logic is mostly related to required Headers or API overrides | ||
> | ||
|
@@ -28,11 +117,11 @@ classDiagram | |
SourceClientFHIR401 <|-- SourceClientCerner | ||
SourceClientFHIR401 <|-- SourceClientEpic | ||
note for SourceClientEpic "platform specific logic" | ||
note for SourceClientEpic "EHR/platform specific logic" | ||
SourceClientEpic <|-- SourceClientUcsfHealth | ||
SourceClientEpic <|-- SourceClientTuftsMedicine | ||
note for SourceClientUcsfHealth "no custom logic" | ||
note for SourceClientUcsfHealth "institution - no custom logic" | ||
SourceClientCerner <|-- SourceClientTheDermatologyClinic | ||
SourceClientCerner <|-- SourceClientStephenVileMD | ||
|
@@ -61,108 +150,6 @@ classDiagram | |
} | ||
``` | ||
|
||
# Setup Testing Environment | ||
|
||
``` | ||
git clone https://github.com/fastenhealth/fasten-sources.git | ||
cd fasten-sources | ||
go mod tidy | ||
go mod vendor | ||
go test ./... | ||
``` | ||
|
||
|
||
|
||
## Writing Tests or Creating Recordings for Existing Client | ||
|
||
|
||
If we're testing or making changes to an existing client, we can do the following: | ||
|
||
1. Determine the Platform source we'd like to modify (Institution sources are sparse and contain no custom logic). | ||
2. Open browser tool to which will allow us to generate a access-token for our source. | ||
```bash | ||
|
||
make serve-backend | ||
|
||
# this should start a simple webserver and open a browser to http://localhost:9999 | ||
``` | ||
|
||
3. Select "Sandbox" radio button | ||
4. Select Platform you'd like to generate an Access Token for. | ||
5. Login with Sandbox credentials for the platform - https://github.com/fastenhealth/docs/blob/main/BETA.md#sandbox-flavor | ||
6. Continue through all prompts, until redirected back to Fasten Lighthouse and localhost. | ||
7. Wait for OAuth handshake to complete, note **Access Token** and **Patient ID**. | ||
8. Find the [test file](./clients/internal/platform) for the source you'd like to change. | ||
9. Create a new test function. **Make sure to specify Patient ID and Access Token you noted earlier** | ||
|
||
> Make sure `fakeSourceCredential.EXPECT().GetPatientId().AnyTimes().Return(<<PATIENT_ID>>)` is populated | ||
> | ||
> Make sure `httpClient := base.OAuthVcrSetup(t, true, <<ACCESS_TOKEN>>)` is populated, and 2nd parameter is `true` | ||
```go | ||
|
||
func TestGetSourceClientCerner_SyncAll(t *testing.T) { | ||
t.Parallel() | ||
//setup | ||
testLogger := logrus.WithFields(logrus.Fields{ | ||
"type": "test", | ||
}) | ||
mockCtrl := gomock.NewController(t) | ||
defer mockCtrl.Finish() | ||
fakeDatabase := mock_models.NewMockDatabaseRepository(mockCtrl) | ||
fakeDatabase.EXPECT().UpsertRawResource(gomock.Any(), gomock.Any(), gomock.Any()).Times(694).Return(true, nil) | ||
|
||
fakeSourceCredential := mock_models.NewMockSourceCredential(mockCtrl) | ||
fakeSourceCredential.EXPECT().GetPatientId().AnyTimes().Return(<<PATIENT_ID>>) | ||
fakeSourceCredential.EXPECT().GetSourceType().AnyTimes().Return(pkg.SourceTypeCerner) | ||
fakeSourceCredential.EXPECT().GetApiEndpointBaseUrl().AnyTimes().Return("https://fhir-myrecord.cerner.com/r4/ec2458f2-1e24-41c8-b71b-0e701af7583d") | ||
|
||
httpClient := base.OAuthVcrSetup(t, true, <<ACCESS_TOKEN>>) | ||
client, _, err := GetSourceClientCerner(pkg.FastenLighthouseEnvSandbox, context.Background(), testLogger, fakeSourceCredential, httpClient) | ||
|
||
//test | ||
resp, err := client.SyncAll(fakeDatabase) | ||
require.NoError(t, err) | ||
|
||
//assert | ||
require.NoError(t, err) | ||
require.Equal(t, 931, resp.TotalResources) | ||
require.Equal(t, 694, len(resp.UpdatedResources)) | ||
} | ||
``` | ||
|
||
10. Run your new test (and generate a recording) by running the following command `go test ./...` | ||
11. Disable recording mode | ||
```go | ||
httpClient := base.OAuthVcrSetup(t, true, <<ACCESS_TOKEN>>) | ||
|
||
//should become | ||
httpClient := base.OAuthVcrSetup(t, false) | ||
|
||
``` | ||
12. Make sure your new recording is added to git | ||
```bash | ||
git add clients/internal/platform/testdata | ||
``` | ||
|
||
13. Once you're satisfied with your changes to the Platform client, open a pull request. A maintainer will verify your changes & recordings, apply your changes to the `fasten-sources-gen` repository, regenerate the class and verify using your recordings. :partying_face: | ||
|
||
|
||
--- | ||
|
||
## Notes | ||
|
||
This library can take a long time to build, as there are thousand's of generated go files. | ||
|
||
https://github.com/golang/go/issues/45474 | ||
https://groups.google.com/g/golang-nuts/c/NJj9nP2Xc0I | ||
|
||
```bash | ||
go clean -cache | ||
time go build ./... | ||
# 129.83s user 5.78s system 204% cpu 1:06.23 total | ||
``` | ||
|
||
|
||
# Docker | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,7 @@ | ||
.PHONY: dep-backend | ||
dep-backend: | ||
go mod vendor | ||
|
||
.PHONY: serve-backend | ||
serve-backend: | ||
serve-backend: dep-backend | ||
cd testutils && go run oauth_cli.go |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.