Skip to content

Commit

Permalink
updated Contributing docs.
Browse files Browse the repository at this point in the history
  • Loading branch information
AnalogJ committed Sep 20, 2023
1 parent cb76aa8 commit 8c817ec
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 109 deletions.
203 changes: 95 additions & 108 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
>
Expand All @@ -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
Expand Down Expand Up @@ -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

Expand Down
6 changes: 5 additions & 1 deletion Makefile
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
Binary file added screenshots/callback-patient.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/callback-raw-request.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/callback.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/connect-custom.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/connect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 8c817ec

Please sign in to comment.