Preamble
The following environment variables must be set to make requests to
the CSIAPPS REST API:
-
CSIAPPS_ACCESS_TOKEN: The access token for authenticating API requests. This token should have the necessary permissions to access the desired endpoints.
Overview
csiapps includes a generic make_request()
function to make requests to the CSIAPPS REST API. Please
refer to the CSIAPPS Swagger documentation for full details on
available endpoints, parameters, and response formats.
Below are some common use cases for interacting with the API
endpoints using csiapps.
Note: By default,
csiappsruns in sandbox mode, so the warehousemake_request()calls below are routed to a local, in-memory warehouse rather than the production API. This lets you develop and test safely without touching production data. Not every endpoint is emulated, though — the registration and auth endpoints are not, and requiresandbox = FALSE; see Whichmake_request()calls work in sandbox at the end of this article. This article documents the production REST API semantics; for the full local workflow — registering orgs and athletes, schemas, ingestion, and retrieval against the emulated warehouse — see the dedicated Sandbox Mode article.
Authorization Status
The most basic endpoint is the /api/csiauth/me/
endpoint, which can be used to check the status of the user making the
request. This endpoint requires authentication, so if the request is
successful, it indicates that your access token is valid and has the
necessary permissions to access the REST API. You may need to specify
your institute before authenticating.
set_institute("csiontario") # or "csipacific" (the default)
result <- make_request(
endpoint = "api/csiauth/me/",
sandbox = FALSE # /me is not emulated; it needs the real API
)Sandbox note:
/api/csiauth/me/is not emulated by the sandbox, so a consolemake_request("api/csiauth/me/")in the default sandbox mode raises a 501. Passsandbox = FALSEto reach the real endpoint. Inside a wrapped Shiny app,/meis loaded for you by the login simulation (see the Sandbox Mode article) — you don’t call it directly.
Registration API
The registration API provides access to profiles and organisations
via fetch_org_options(), fetch_profiles(), and
fetch_profile(). The examples below pass
sandbox = FALSE to contact the real
registration API. In sandbox mode (the default) these same helpers read
from a local dummy registry — see the Sandbox
Mode article for that workflow.
Organisations
fetch_org_options() returns all organisations your token
can see, formatted as label/value pairs ready
for a Shiny selectInput():
set_institute("csiontario")
orgs <- fetch_org_options(sandbox = FALSE)
# list(list(label = "CSI Ontario", value = 1L), ...)Doing this with make_request()
fetch_org_options() is a thin wrapper over a
GET to the api/registration/organization/
endpoint. You can make the same call directly:
resp <- make_request(
endpoint = "api/registration/organization/",
query = list(limit = 1000),
sandbox = FALSE # registration is NOT emulated in sandbox
)
orgs <- resp$results # each element has $id and $nameSandbox note: unlike the warehouse examples further down, the registration endpoints have no sandbox emulation.
make_request("api/registration/...")in the default sandbox mode raises a 501 — you must passsandbox = FALSE. In sandbox, reach forfetch_org_options()instead: it reads the local dummy registry directly (see the Sandbox Mode article).
Profiles
fetch_profiles() returns all profiles accessible to your
token, with automatic pagination. Filter by organisation using
sport_org_id:
profiles <- fetch_profiles(sandbox = FALSE)
# Filter to a specific organisation
profiles <- fetch_profiles(
filters = list(sport_org_id = 42L),
sandbox = FALSE
)A common pattern across dashboards is converting the profile list into a data frame for display or matching:
profile_df <- do.call(rbind, lapply(profiles, function(p) {
data.frame(
id = p$id,
first_name = p$person$first_name %||% NA_character_,
last_name = p$person$last_name %||% NA_character_,
email = p$person$email %||% NA_character_
)
}))fetch_profile() retrieves a single profile by ID:
profile <- fetch_profile(profile_id = 123L, sandbox = FALSE)
profile$person$first_nameDoing this with make_request()
Both helpers wrap the api/registration/profile/
endpoint. fetch_profiles() paginates and returns one flat
list; make_request(paginate = TRUE) returns a list
of pages, so flatten the results yourself:
pages <- make_request(
endpoint = "api/registration/profile/",
query = list(sport_org_id = 42L), # omit to fetch all
paginate = TRUE,
sandbox = FALSE # registration is NOT emulated in sandbox
)
profiles <- do.call(c, lapply(pages, function(p) p$results))A single profile is the same endpoint with the ID appended — the
direct equivalent of fetch_profile():
profile <- make_request(
endpoint = "api/registration/profile/123",
sandbox = FALSE
)Sandbox note: as with organisations, these calls have no sandbox emulation and raise a 501 unless
sandbox = FALSE. Usefetch_profiles()/fetch_profile()in sandbox — they read the local dummy registry directly.
Data Warehouse Ingestion
To ingest data records into the warehouse, we make a POST request to
the /api/warehouse/ingestion/primary/ endpoint. Users
supply the source (uuid) of the target data
source, a list of records to be ingested, and
(optionally) the subject_field by which each record can be
uniquely assigned to a user. The records must comply with the schema
defined for the target data source.
Note: The
sourceuuid is provisioned by the CSIAPPS team when they set up the remote data warehouse for your app, and supplied through theSOURCE_UUIDenvironment variable — the app developer does not choose or hard-code it. Read it asSys.getenv("SOURCE_UUID")(as below) so the same code runs in development and production. See the Sandbox Mode article for how this works during local development.
JSON Schema Definition
Consider the following JSON Schema:
{
"title": "A registration form",
"description": "A simple form example.",
"type": "object",
"required": [
"id",
"firstName",
"lastName"
],
"properties": {
"id": {
"type": "string",
"title": "ID"
},
"firstName": {
"type": "string",
"title": "First name",
"default": "Chuck"
},
"lastName": {
"type": "string",
"title": "Last name",
"default": "Norris"
},
"age": {
"type": "integer",
"title": "Age"
},
"telephone": {
"type": "string",
"title": "Telephone",
"minLength": 10
}
}
}Here, id is the required field that serves as the unique
user assignment for each record.
To create records that comply with this schema, we create the following records:
records <- list(
list(id = "xxxx", firstName = "John", lastName = "Doe", age = 30, telephone = "1234567890"),
list(id = "yyyy", firstName = "Jane", lastName = "Smith", age = 25, telephone = "0987654321")
)To retrieve the JSON schema definition from the data warehouse, we
can make a request to the
/api/warehouse/data-sources/{uuid}/ endpoint, where
uuid is the uuid of the target data source. The schema
definition is located in the head_primary_definition$schema
field of the response.
data_source <- make_request(
endpoint = paste0("api/warehouse/data-sources/", Sys.getenv("SOURCE_UUID"))
)
schema <- data_source$head_primary_definition$schemaData Record Validation
We can validate data records using the jsonlite and
jsonvalidate packages. Be sure to set
auto_unbox = TRUE when converting the JSON objects to
strings.
json_schema <- jsonvalidate::json_schema$new(jsonlite::toJSON(schema, auto_unbox = T))
validate_record <- function(record) {
json_schema$validate(jsonlite::toJSON(record, auto_unbox = T))
}
validation_results <- sapply(records, validate_record)
stopifnot(all(validation_results))Finally, we can make the API request to ingest these records into the warehouse:
result <- make_request(
endpoint = "api/warehouse/ingestion/primary/",
method = "POST",
body = list(
source = Sys.getenv("SOURCE_UUID"),
records = records,
subject_field = "id"
)
)Data Record Retrieval
To retrieve data records from the warehouse, we make an API request
to the /api/warehouse/data-records/ endpoint. The only
required parameter is the source_uuid of the requested
table, but there are several optional parameters for additional
filtering. Note that we can set the paginate = TRUE to
retrieve all records matching the query parameters.
records <- make_request(
endpoint = "api/warehouse/data-records",
query = list(source_uuid = Sys.getenv("SOURCE_UUID")),
paginate = TRUE
)Sandbox Mode
make_request() runs against a local
sandbox by default, so pipelines can be developed and tested
with no network access, no authentication, and no risk of writing test
data to the production warehouse. Sandbox mode is enabled by default and
is turned off only at deployment.
Not every endpoint is emulated, though — and this is the one gotcha
worth internalising. The sandbox emulates the warehouse
endpoints but not the registration or auth endpoints.
Calls it does not emulate raise a 501 unless you pass
sandbox = FALSE:
Endpoint (make_request) |
Default sandbox | sandbox = FALSE |
Sandbox alternative |
|---|---|---|---|
api/csiauth/me/ |
✗ 501 | ✓ | login simulation (Shiny) |
api/registration/organization/ |
✗ 501 | ✓ | fetch_org_options() |
api/registration/profile/ |
✗ 501 | ✓ |
fetch_profiles() / fetch_profile()
|
api/warehouse/data-sources/{uuid} |
✓ emulated | ✓ | — |
api/warehouse/ingestion/primary/ |
✓ emulated | ✓ | — |
api/warehouse/data-records |
✓ emulated | ✓ | — |
In short: the warehouse make_request()
examples in this article work in both modes, while the
registration/auth make_request() examples
work only against the real API (sandbox = FALSE). For
registration data in sandbox, use the fetch_* helpers,
which read the local dummy registry directly instead of going through
make_request().
The full sandbox workflow — enabling/disabling it, registering sport orgs and athletes, registering schemas, validating, ingesting, and retrieving records against the emulated warehouse, and inspecting or resetting sandbox state — is documented in its own article:
See also ?"csiapps-sandbox" for the reference-level
overview.
