Skip to content

How to use SAFE Swift API?

When to use SAFE Swift API?

As the name suggests, the SAFE Swift API produces the result quickly. Unlike the SAFE Application API, it doesn't keep a copy of your uploaded roster data in the SAFE web app. So, you won't be able to view the uploaded roster in the future. This API, however, delivers fatigue score and fatigue risk score as response from the same the endpoints you use to send the roster data. Use this API to quickly generate fatigue score and fatigue risk score from the roster data.

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 Swift API and get results from the API. The program uses the following libraries:

  • IdentityModel.Client
  • Safe_API_Demo_Client.Models
  • System
  • System.Collections.Generic
  • System.Linq
  • System.Net.Http.Json
  • System.Text
  • System..Threading.Tasks

Here are the steps to follow.

Get Fatigue Score

Follow the instructions below to get fatigue score. This code sends HTTP POST request to a web API endpoint.

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: Set the variable values

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

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

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 3: Initiate request

Create an HTTP client and set the base address to the API URL. We recommend that you also set the HTTP client to timeout after 1000 seconds. Then, create an HTTP request message with the HTTP method set to POST and the endpoint set to /api/Processor/ProcessFatigue. The request message should also include the authorization header with the access token.

HttpClient client = new HttpClient();
client.Timeout = TimeSpan.FromSeconds(1000);
client.BaseAddress = new Uri(apiUrl);

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

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

Step 4: Prepare request body

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

var payload = new 
{    
    RosterData = rosterCsv,
    SleepData = new List<SleepData>(),
    PreferredScale = "SP",
    DateFormat = "dmy",
    GenerateSleeps = true,
    SleepSettings = new List<SleepSetting>()
};

The FatigueProcessorPayload class has six properties.

  • Set the RosterData property to refer to rosterCsv.

  • The PreferredScale property has been set to SP in the example. This value can be changed to indicate a different scale, which you want the result to be in. See Step 5: Retry with different PrefferedScale for different values you can assign to PreferredScale property.

  • The SleepData property takes an array of the following properties:

    • ScheduleName, which indicates the schedule name
    • SleepStart, which indicates the date and time (Zulu format) when the sleep started
    • SleepEnd, which indicates the date and time (Zulu format) when the sleep ended
  • Leave the SleepData and SleepSettings properties empty by assiging empty lists to them.

  • The DateFormat property is set to dmy, which indicates DD/MM/YYYY date format has been used in roster data. You could change this value to mdyto indicate MM/DD/YYYY date format.

  • The GenerateSleeps property has been set to true to indicate that SAFE must predict sleeps automatically. You can provide SleepData and still set the GenerateSleeps property to true to indicate SAFE must disregard the provided SleepData and predict sleeps automatically.

Step 5: Make the request

Create a JSON object using the request body and send the request message to the API and wait for it to return the result.

request.Content = JsonContent.Create(payload);
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine("Result: " + result);
return result;

Step 6: Retry with different PrefferedScale

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 an error, read the response to locate the cause of the error.

How to read the error?

Each error contains 3 pieces of information separated by a | symbol.

  • The first part shows you the row within the csv where the error occured.
  • The second part shows the schedule, which the error is for, and
  • The third part shows the error message.

Example response error

{
  "errors":["6|Pilot1|The 'Off duty date' (1/2/2015 2:00 PM) cannot be more than 30 hours after the 'On duty date' (1/1/2015 1:53 AM)."]
}

Resolve any error in the roster data file and retry sending the request.

If you receive the result for the scale you had set in PreferredScale property, you can send the request again within a different value assigned to the PreferredScale property. The following values are supported for the PreferredScale property. Send only one value at a time.

  • SP for Samn-Perelli scale
  • KSS for Karolinska Sleepiness Scale
  • KP for Karolinska Probability scale
  • VS for Vigilance Degradation scale
  • CRD for Complex Reaction Degradation scale
  • PMR for Percentage Missed Responses scale

Get Fatigue Risk Score

Follow the instructions below to get fatigue score together with risk score. This code sends HTTP POST request to a web API endpoint.

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: Set the variable values

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

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

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 3: Initiate request

Create an HTTP client and set the base address to the API URL. We recommend that you also set the HTTP client to timeout after 1000 seconds. Then, create an HTTP request message with the HTTP method set to POST and the endpoint set to /api/Processor/ProcessFatigueRisk. The request message should also include the authorization header with the access token.

HttpClient client = new HttpClient();
client.Timeout = TimeSpan.FromSeconds(1000);
client.BaseAddress = new Uri(apiUrl);

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

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

Step 4: Prepare request body

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

var payload = new 
{    
    RosterData = rosterCsv,
    SleepData = new List<SleepData>(),
    PreferredScale = "SP",
    DateFormat = "dmy",
    GenerateSleeps = true,
    SleepSettings = new List<SleepSetting>()
};

The FatigueProcessorPayload class has six properties.

  • Set the RosterData property to refer to rosterCsv.

  • The PreferredScale property has been set to SP in the example. This value can be changed to indicate a different scale, which you want the result to be in. See Step 5: Retry with different PrefferedScale for different values you can assign to PreferredScale property.

  • The SleepData property takes an array of the following properties:

    • ScheduleName, which indicates the schedule name
    • SleepStart, which indicates the date and time (Zulu format) when the sleep started
    • SleepEnd, which indicates the date and time (Zulu format) when the sleep ended
  • Leave the SleepData and SleepSettings properties empty by assiging empty lists to them.

  • The DateFormat property is set to dmy, which indicates DD/MM/YYYY date format has been used in roster data. You could change this value to mdyto indicate MM/DD/YYYY date format.

  • The GenerateSleeps property has been set to true to indicate that SAFE must predict sleeps automatically. You can provide SleepData and still set the GenerateSleeps property to true to indicate SAFE must disregard the provided SleepData and predict sleeps automatically.

Step 5: Make the request

Create a JSON object using the request body and send the request message to the API and wait for it to return the result.

request.Content = JsonContent.Create(payload);
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine("Result: " + result);
return result;

Step 6: Retry with different PrefferedScale

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 blank, use the Fatigue endpoint to find the error.
Resolve any error in the roster data file. Then, return to Get Fatigue Risk Score.

If you receive the result for the scale you had set in PreferredScale property, you can send the request again within a different value assigned to the PreferredScale property. The following values are supported for the PreferredScale property. Send only one value at a time.

  • SP for Samn-Perelli scale
  • KSS for Karolinska Sleepiness Scale
  • KP for Karolinska Probability scale
  • VS for Vigilance Degradation scale
  • CRD for Complex Reaction Degradation scale
  • PMR for Percentage Missed Responses scale

Complete Code

using IdentityModel.Client;
using Safe_API_Demo_Client.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Json;
using System.Text;
using System.Threading.Tasks;

namespace Safe_API_Demo_Client
{
    public static class FastApi
    {
        public static async void Run()
        {
            var identityUrl = "https://identity-eu.frmsc.com";            
            var apiUrl = @"https://api-eu.frmsc.com";

            var clientId = "[Your_ClientId]";
            var clientSecret = "[your_ClientSecret]";

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

            var accessToken = await Authenticate(identityUrl, clientId, clientSecret, "frmsc_fast_safe_api");
            await ProcessFatigue(apiUrl, accessToken, rosterCsv);

            var accessToken = await Authenticate(identityUrl, clientId, clientSecret, "frmsc_fast_safe_risk_api");
            await ProcessFatigueRisk(apiUrl, accessToken, rosterCsv);
        }

        static async Task<string> ProcessFatigue(string apiUrl, string accessToken, string rosterData)
        {
            try
            {
                HttpClient client = new HttpClient();
                client.Timeout = TimeSpan.FromSeconds(1000);
                client.BaseAddress = new Uri(apiUrl);

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

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

                var payload = new FatigueProcessorPayload
                {
                    RosterData = rosterData,
                    SleepData = new List<SleepData>(),
                    PreferredScale = "SP",
                    DateFormat = "dmy",
                    GenerateSleeps = true,
                    SleepSettings = new List<SleepSetting>()
                };

                request.Content = JsonContent.Create(payload);

                var response = await client.SendAsync(request);
                var result = await response.Content.ReadAsStringAsync();
                Console.WriteLine("Result: " + result);
                return result;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: " + ex.Message);
                throw;
            }
        }

        static async Task<string> ProcessFatigueRisk(string apiUrl, string accessToken, string rosterData)
        {
            try
            {
                HttpClient client = new HttpClient();
                client.Timeout = TimeSpan.FromSeconds(1000);
                client.BaseAddress = new Uri(apiUrl);

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

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

                var payload = new FatigueProcessorPayload
                {
                    RosterData = rosterData,
                    SleepData = new List<SleepData>(),
                    PreferredScale = "SP",
                    DateFormat = "dmy",
                    GenerateSleeps = true,
                    SleepSettings = new List<SleepSetting>()
                };

                request.Content = JsonContent.Create(payload);

                var response = await client.SendAsync(request);
                var result = await response.Content.ReadAsStringAsync();
                Console.WriteLine("Result: " + result);
                return result;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: " + ex.Message);
                throw;
            }
        }

        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");
            }
        }
    }
}