View Source Using the Castor EDC API
# ## Fix for the free tier of Fly.io livebook
# ## Allocate 2GB swap
# System.cmd("fallocate", ["-l", "2G", "/swap"])
# System.cmd("chmod", ["400", "/swap"])
# System.cmd("mkswap", ["/swap"])
# System.cmd("swapon", ["/swap"])
Mix.install([
{:ex_castor_edc, "~> 0.4.0"},
{:kino, "~> 0.6.1"}
])
introduction
Introduction
This notebook serves as an introduction on how to use the API wrapper. It's not meant to be an exhaustive guide.
authentication
Authentication
Before we can start making requests to the API we need to have a client_id
and a client_secret
. You can get this information from the account settings page.
Enter your client_id
and client_secret
in the form below after evaluating the code-block.
endpoints = [
{"https://data.castoredc.com/", "NL"},
{"https://uk.castoredc.com/", "UK"},
{"https://us.castoredc.com/", "US"},
{"https://au.castoredc.com/", "AU"}
]
endpoint = Kino.Input.select("Region", endpoints) |> Kino.render()
client_id = Kino.Input.text("Client Id") |> Kino.render()
client_secret = Kino.Input.password("Client Secret") |> Kino.render()
Kino.nothing()
Next we need to exchange your client_id
and client_secret
for an access token. The access token can then be used to make other requests to the API.
client =
CastorEDC.Client.new(
%{
client_id: Kino.Input.read(client_id),
client_secret: Kino.Input.read(client_secret)
},
endpoint: Kino.Input.read(endpoint)
)
{:ok, client} =
client
|> CastorEDC.authenticate()
client
performing-authenticated-api-requests
Performing authenticated API requests
Let's start at the beginning and fetch all of the studies that you have access to with your account.
All function calls return a 3 element tuple. The first element is the http status code, the second element is the decoded response from the API, and the last element is the raw response that came back from the server.
We'll make extensive use of pattern-matching to collect that the data that we're interested in, while ignoring the rest.
Most API calls support pagination but we'll mostly focus on the first page of the results. If you want to fetch the second page it's possible to pass the page number as a keyword option e.g. page: 2
{200, %{"_embedded" => %{"study" => studies}}, _} = CastorEDC.Common.Studies.list(client)
studies
Now that we have a list of all the studies we'll need to pick one to dig deeper into with further API requests.
studies =
studies
|> Enum.map(&{&1["study_id"], &1["name"]})
|> Enum.sort(fn {_, a}, {_, b} -> a <= b end)
study_id = Kino.Input.select("Select a study", studies)
Let's read the chosen study into an easily accessible variable that we can reuse with other requests.
study_id = Kino.Input.read(study_id)
sites
Sites
With a study id in our hands we can start digging, let's start with finding out which sites the study is being conducted at!
You'll get the option to also run write calls against the API. Make sure that you've chosen a test site as to not put data where it doesn't belong.
{200, %{"_embedded" => %{"sites" => sites}}, _} = CastorEDC.Common.Sites.list(client, study_id)
sites =
sites
|> Enum.filter(&(&1["deleted"] == false))
|> Enum.map(&{&1["id"], &1["name"]})
site_id = Kino.Input.select("Choose your test site", sites)
site_id = Kino.Input.read(site_id)
participants
Participants
The CastorEDC.Participants
module is our gateway into fetching information about our participants. We can either fetch entire lists or fetch specific ones. With the create
function we can even directly create new ones in our study.
Let's start with fetching the first 10.
{200, %{"_embedded" => %{"participants" => participants}}, _} =
CastorEDC.DataCollection.Participants.list(client, study_id, page_size: 10)
participants
As you can see we now have a list of all the participants enrolled in the the study. Let's take the first one from the list and find out more about it.
[%{"id" => participant_id} | _] = participants
{200, participant, _} =
CastorEDC.DataCollection.Participants.find(client, study_id, participant_id)
participant
It's also possible to create new Participants via the API allowing for the enrollment of participants through external systems.
Before you evaluate the code-block below double-check the selected site, you also need participant creation permission for the given site.
{201, new_participant, _} =
CastorEDC.DataCollection.Participants.create(client, study_id, %{site_id: site_id})
new_participant
study-structure
Study Structure
It's also possible to fetch the elements
{200, %{"_embedded" => %{"visits" => visits}}, _} =
CastorEDC.StudyProtocol.Visits.list(client, study_id)
visits
|> Enum.sort(&(&1["phase_order"] <= &2["phase_order"]))
{200, %{"_embedded" => %{"forms" => forms}}, _} =
CastorEDC.StudyProtocol.Forms.list(client, study_id)
forms
|> Enum.sort(&(&1["step_order"] <= &2["step_order"]))
{200, %{"_embedded" => %{"fields" => fields}}, _} =
CastorEDC.StudyProtocol.Fields.list(client, study_id)
fields
collected-data
Collected Data
study-data
Study Data
Fetching your study data is easy. Remember that this API call is paginated, so you'll need to make multiple API calls to actually get everything.
As an example we'll only fetch the first 10 data points on page 1.
{200, %{"_embedded" => %{"items" => study_data_points}}, _} =
CastorEDC.DataCollection.DataPoints.StudyDataPointCollection.list(client, study_id,
page: 1,
page_size: 10
)
study_data_points
wrapping-up
Wrapping up
I hope that this notebook has given you a taste of how the library works. The documentation lists all of the available endpoints that you can use.