Skip to content

How to use SAFE Upload API?

When to use SAFE Application API?

SAFE Application API keeps a copy of your uploaded roster data in the SAFE web app so that you can return to it at any time and analyze the results visually. You should use this API if you want the roster data to be preserved in the SAFE web app.

How to work with the API?

This code snippet is written in C# and it is used to upload roster data to the FRMSC SAFE Application API and get results from the API. The program uses the following libraries:

  • IdentityModel.Client
  • Newtonsoft.Json
  • Safe_API_Demo_Client.Models
  • System.Text

Here are the steps to follow.

Step 1: Generate a token

Generate a Bearer token to use with this endpoint. Follow the instructions given in How to generate a Bearer token? tutorial to generate a bearer token.

Step 2: Upload the roster data

Follow the instructions below to upload the roster data. This code sends HTTP POST request to a web API endpoint.

Step 1: Set the variable values

Set the values of apiKey, accessToken, rosterCSV, and clientId variables.

var apiKey = "[Your_APIKey]";
var apiUrl = "https://web-eu.frmsc.com";
var accessToken = "[Your_Accesstoken]";
var rosterCsv = File.ReadAllText("SampleRosters\\ExampleRosterUpload.csv");
var clientId = "[Your_ClientId]";

You can get apiKey and clientId from the web app, and you can get the accessToken from the previous step.

The rosterCSV variable is set to read the roster data from a CSV file. Set the parameter value of the File.ReadAllText() function to the location of the CSV file with the roster data.

Step 2: Initiate request

Create an HTTP client and set the base address to the API URL. Then, create an HTTP request message with the HTTP method set to POST and the endpoint set to /api/UploadRoster. The request message should also include the authorization header with the access token.

HttpClient client = new HttpClient();
client.BaseAddress = new Uri(apiUrl);

var request = new HttpRequestMessage(HttpMethod.Post, "/api/UploadRoster");

request.Version = new Version(2, 0);
request.Headers.Add("authorization", $"Bearer {accessToken}");

Step 3: Prepare request body

Create an instance of the UploadRequest class and sets its properties.

var uploadRequest = new UploadRequest
{
    RosterName = "Sample SAFE Application API post",
    RosterData = rosterCsv,
    Username = clientId,
    Key = apiKey,
    Overwrite = false
};

The UploadRequest class has four properties.

  • RosterName
  • RosterData
  • Username
  • Key

Provide a name for the roster through the RosterName property. In the following code example, the RosterName property is set to Sample SAFE Application API post.

Set the RosterData property to refer to rosterCsv and the Username property to clientId variables. The Key property must refer to apiKey.

Leave the Overwrite property as false, if you want to create a new roster. To overwrite an existing roster with the same name, set the value of the Overwrite property to true.

Step 4: Make the request

Serialize the UploadRequest object to JSON and set the request message content to the serialized JSON. Send the request message to the API and wait for it to return a roster token.

request.Content = new StringContent(JsonConvert.SerializeObject(uploadRequest), Encoding.UTF8, "application/json");                  

var response = await client.SendAsync(request);
return await response.Content.ReadAsStringAsync();

Step 3: Generate result

Follow the instructions below to upload the roster data. This code sends HTTP GET request to a web API endpoint.

Step 1: Set the variable values

Set the values of rosterToken and dataKey variables.

var rosterToken = "<roster_token_generated_by_UploadRoster_endpoint>";
var dataKey = "status";

You can get rosterToken from Step 4: Make the request. The dataKey variable is set to status initially to ensure that the roster data you uploaded previously was completed successfully. See Step 4: Retry with different dataKey

Step 2: Initiate request

Create a query string using the variables set in Step 1: Set the variable values, including the apiKey variable. Then, create an HTTP request message with the HTTP method set to GET and the endpoint set to /api/GetResults. The request message should also include the authorization header with the access token.

Set the Version property of the HttpRequestMessage object is set to 2.0 to indicate that the request should use HTTP/2.0.

var queryString = string.Format("?token={0}&key={1}&dataKey={2}", rosterToken, apiKey, dataKey);
var request = new HttpRequestMessage(HttpMethod.Get, "/api/GetResults" + queryString);
request.Version = new Version(2, 0);
request.Headers.Add("authorization", $"Bearer {accessToken}");

Step 3: Make the request

Use the SendAsync method of the HttpClient object to send the request, and the ReadAsStringAsync method of the HttpContent object to read the response content as a string.

var response = await client.SendAsync(request);
return await response.Content.ReadAsStringAsync();

Step 4: Retry with different dataKey

There are two workflows for this step depending on the response you receive from the previous step.

If the response from the previous step is not completedsuccessfully, set the value of dataKey parameter to feedback in Step 1: Set the variable values and retry sending the request to learn more about the problem.

Resolve any error in the roster data file. Then, return to Step 2: Upload the roster data. Keep the RosterName same and set the value of Overwrite field to true to resubmit the roster data.

If the status is completedsuccessfully, set the value of dataKey parameter to the type of result you want to receive and submit. The following values are supported for the dataKey parameter. Send only one value at a time.

  • status
  • feedback
  • hundredpointalertness
  • samnperellialertness
  • karolinskaalertness
  • karolinskaprobability
  • vigilancedegradation
  • complexreactiondegradation
  • percentagemissedresponses
  • sleepperiods
  • schedule
  • timeabovethreshold
  • tableofscheduledetailsids

Complete Code

using IdentityModel.Client;
using Newtonsoft.Json;
using Safe_API_Demo_Client.Models;
using System.Text;

namespace Safe_API_Demo_Client
{
    public static class UploadApi
    {
        public static async void Run()
        {
            var identityUrl = "https://identity-eu.frmsc.com";
            var apiUrl = @"https://web-eu.frmsc.com";
            var apiKey = "[Your_ApKey]";
            var clientId = "[Your_ClientId]";
            var clientSecret = "[your_ClientSecret]";

            var rosterCsv = File.ReadAllText("SampleRosters\\ExampleRosterUpload.csv");

            var accessToken = await Authenticate(identityUrl, clientId, clientSecret, "frmsc_safe_upload_api");

            if (accessToken == null) { return; }

            var rosterToken = await Upload(apiUrl, apiKey, accessToken, rosterCsv, clientId);

            Console.WriteLine("Acquired token: " + rosterToken);

            while (await GetResults(apiUrl, apiKey, accessToken, rosterToken, "Status") == "processing")
            {                
                Console.WriteLine("Roster still being processed....");
                Thread.Sleep(2000);                
            }

            var feedback = await GetResults(apiUrl, apiKey, accessToken, rosterToken, "Feedback");
            Console.WriteLine("Feedback: {0}", feedback);

            var schedules = await GetResults(apiUrl, apiKey, accessToken, rosterToken, "TableOfScheduleDetailsIds");
            Console.WriteLine("Schedules: {0}", schedules);

            Console.WriteLine("Downloading 100pt scale alertness data");
            var hundredPointAlertness = await GetResults(apiUrl, apiKey, accessToken, rosterToken, "HundredPointAlertness");
            File.WriteAllText("Output\\hundredPointAlertnessData.csv", hundredPointAlertness);

            Console.WriteLine("Downloading Samn Perelli scale alertness data");
            var samnPerelliAlertness = await GetResults(apiUrl, apiKey, accessToken, rosterToken, "SamnPerelliAlertness");
            File.WriteAllText("Output\\samnPerelliAlertnessData.csv", samnPerelliAlertness);

            Console.WriteLine("Downloading Karolinska Alertness scale alertness data");
            var karolinskaAlertness = await GetResults(apiUrl, apiKey, accessToken, rosterToken, "KarolinskaAlertness");
            File.WriteAllText("Output\\karolinskaAlertnessData.csv", karolinskaAlertness);

            Console.WriteLine("Downloading Karolinska Probability scale alertness data");
            var karolinskaProbability = await GetResults(apiUrl, apiKey, accessToken, rosterToken, "KarolinskaProbability");
            File.WriteAllText("Output\\karolinskaProbabilityAlertnessData.csv", karolinskaProbability);

            Console.WriteLine("Downloading Vigilance Degradation scale alertness data");
            var vigilanceDegradation = await GetResults(apiUrl, apiKey, accessToken, rosterToken, "VigilanceDegradation");
            File.WriteAllText("Output\\vigilanceDegradationAlertnessData.csv", vigilanceDegradation);

            Console.WriteLine("Downloading Complex Reaction Degradation scale alertness data");
            var complexReactionDegradation = await GetResults(apiUrl, apiKey, accessToken, rosterToken, "ComplexReactionDegradation");
            File.WriteAllText("Output\\complexReactionDegradationAlertnessData.csv", complexReactionDegradation);

            Console.WriteLine("Downloading Percentage Missed Responses scale alertness data");
            var percentageMissedResponses = await GetResults(apiUrl, apiKey, accessToken, rosterToken, "PercentageMissedResponses");
            File.WriteAllText("Output\\percentageMissedResponses.csv", percentageMissedResponses);

            Console.WriteLine("Downloading sleep periods data");
            var sleepPeriods = await GetResults(apiUrl, apiKey, accessToken, rosterToken, "SleepPeriods");
            File.WriteAllText("Output\\sleepPeriodData.csv", sleepPeriods);

            Console.WriteLine("Downloading schedule data");
            var schedule = await GetResults(apiUrl, apiKey, accessToken, rosterToken, "Schedule");
            File.WriteAllText("Output\\scheduleData.csv", schedule);

            Console.WriteLine("Downloading time above threshold data");
            var timeAboveThreshold = await GetResults(apiUrl, apiKey, accessToken, rosterToken, "TimeAboveThreshold");
            File.WriteAllText("Output\\timeAboveThresholdData.csv", timeAboveThreshold);
        }

        static async Task<string> Upload(string apiUrl, string apiKey, string accessToken, string rosterCsv,  string clientId)
        {
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri(apiUrl);

            var request = new HttpRequestMessage(HttpMethod.Post, "/api/UploadRoster");

            request.Version = new Version(2, 0);
            request.Headers.Add("authorization", $"Bearer {accessToken}");

            var uploadRequest = new UploadRequest
            {
                RosterName = "Sample roster API post",
                RosterData = rosterCsv,
                Username = clientId,
                Key = apiKey,
                Overwrite = false
            };

            request.Content = new StringContent(JsonConvert.SerializeObject(uploadRequest), Encoding.UTF8, "application/json");                  

            var response = await client.SendAsync(request);
            return await response.Content.ReadAsStringAsync();
        }

        static async Task<string> Authenticate(string identityUrl, string clientId, string clientSecret, string scope)
        {
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri(identityUrl);

            var openIdDiscoveryDocument = client.GetDiscoveryDocumentAsync(identityUrl).GetAwaiter().GetResult();

            var request = new ClientCredentialsTokenRequest
            {
                Address = openIdDiscoveryDocument.TokenEndpoint,

                ClientId = clientId,
                ClientSecret = clientSecret,
                Scope = scope
            };

            var tokenResponse = await client.RequestClientCredentialsTokenAsync(request);
            if (tokenResponse != null)
            {
                return tokenResponse.AccessToken;
            }
            else
            {
                Console.WriteLine("Authentication failed");
                throw new Exception("Authentication failed");
            }
        }

        static async Task<string> GetResults(string apiUrl, string apiKey, string accessToken, string rosterToken, string dataKey) {
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri(apiUrl);

            var queryString = string.Format("?token={0}&key={1}&dataKey={2}", rosterToken, apiKey, dataKey);

            var request = new HttpRequestMessage(HttpMethod.Get, "/api/GetResults" + queryString);

            request.Version = new Version(2, 0);
            request.Headers.Add("authorization", $"Bearer {accessToken}");

            var response = await client.SendAsync(request);
            return await response.Content.ReadAsStringAsync();
        }
    }
}