Skip to content

Headless (embedded) activity API

Stian Håklev edited this page Nov 15, 2018 · 8 revisions

The idea of headless activities is to expose individual FROG activities to other systems, and enable a deep integration. The current implementation is a prototype, and will probably change (feedback is welcome).

API introduction

Currently there is no support for API keys or secrets, and no usage limitations etc. This will be introduced later. All APIs use POST requests, with payload formatted as application/x-www-form-urlencoded (the result of filling out an invisible form, and submitting it). This is similar to how LTI requests are made, in the future it would be interesting to explore if LTI extensions could cover the use cases below.

All the URLs, other than api/activityTypes (which returns JSON) should be loaded in an iFrame with a POST request. This can be done in pure javascript, otherwise there are libraries such as react-post which exports PostIFrame. See also the implementation in the frogapi-test (described at the bottom).

List of activity types

<FROGURL>/api/activityTypes generates a JSON list of activity types installed, and some metadata (description etc). This can be used to generate a menu of activity types. Example:

{
  id: "ac-webrtc",
  type: "react-component",
  name: "WebRTC",
  description: "Video Conference",
  longDescription: "Video conference using WebRTC peer to peer configuration",
  runner_url: "/api/activityType/ac-webrtc",
  config_url: "/api/config/ac-webrtc"
}

Configuring an activity type

Using FROG activity chooser remotely

If you want to embed the FROG activity chooser in an iFrame, you can use the URL <FROGURL>/api/chooseActivity. This will use iFrame messages to signal when an activity has been chosen. Currently this embed does not support previews.

The following data can be sent as POST payload:

Settings:

  • showValidator (boolean): show the validator circle (green for valid, red for invalid)
  • showLibrary (boolean): show the activity library (pre-configured activities from the cloud)
  • showDelete (boolean): shows a delete button when configuring a specific activity, which throws away the config, and goes back to the activity chooser
  • whiteList Array<string>: only offer the activity types listed here (for example ['ac-chat', 'ac-brainstorm']

When an activity is chosen, a config message is issued, which is described in the next section.

Starting with an activity type

If you already know which activity type should be configured, either as a result of using the embedded activity chooser, or querying the API and displaying a native selection menu, you can request the configuration for that specific activity with <FROGURL>/api/config/<AC-NAME>.

The currently selected config, as well as whether it is valid or not, is constantly sent to the parent app. It is the parent apps responsibility to store this information - no state is retained by FROG. An activity should never be launched if the config was not marked as valid.

The following data can be sent as the POST payload:

Data:

  • config (object): An existing config object to initialize the form with

Settings:

  • showValidator (boolean): show the validator circle (green for valid, red for invalid)
  • showDelete (boolean): shows a delete button when configuring a specific activity, which throws away the config, and goes back to the activity chooser
  • whiteList Array<string>: only offer the activity types listed here (for example ['ac-chat', 'ac-brainstorm']
  • showLibrary (boolean): show the activity library (pre-configured activities from the cloud) (if going back to the activity chooser)

Initially when the config loads (including from the activityChooser above), and at every change in the config, a new message is issues, which looks like this:

{
      type: 'frog-config',
      activityType: 'ac-single-li',
      config: {},
      errors: [],
      valid: true
}

Here is another example, which both contains a config in progress, as well as some errors.

{
  type: 'frog-config',
  activityType: 'ac-quiz',
  config: { shuffle: 'none', guidelines: '<p>These are my guidelines</p>' },
  errors: [
    {
      err: 'You must have at least one question',
      id: '1',
      nodeType: 'activity',
      type: 'configValidateFn',
      severity: 'error'
    }
  ],
  valid: false
}

You can either allow showValid, which will show a visual indicator of errors, and allow the user to see the error messages when hovering over, or you should somehow indicate to the user when the config is faulty. You should never call an activity with a faulty config (one that has at least one error), this will normally lead to a crash.

Running an activity

An activity is launched by a POST request to the following URL: <FROGURL>/api/activityType/<AC-NAME>.

The POST request should be formatted as a form (application/x-www-form-urlencoded), for example using the react-post library. The following fields are supported:

Identifying activity:

  • clientId: API user
  • activityId: optional, important if you have multiple activities of the same type, which should not share data/config

Identifying user (all optional):

  • userId: optional, just used for log messages
  • userName: optional, used for log messages, dashboards, etc.

Configuring activity:

  • config: config object which should be the output of configuring the activity. This, together with the AC-TYPE in the URL, describes the activity to be launched

Specifying group:

  • instanceId: optional, but should usually be supplied, see below

Supplying data:

  • activityData: supplying activityData to be merged into activity
  • rawData: supplying rawData to be used for the activity

Settings:

  • readOnly: no changes can be made to the data - useful for example for teacher viewing student contributions

Concept of instance and life-cycle

All FROG activities are back by reactive data structures (powered by ShareDB). All the students in the same instance will see and edit the same data.

The actual (full) instanceId is concatenated from clientId, activityType, activityId, and instanceId. This means that you can have an instance (group1) in two different quizzes, with different data, as long as you supply unique activityIds for the two quizzes etc.

Reactive document initialisation is only done once for each full instanceId. The following fields should therefore be identical for all the launches of a single full instanceId (if you first initialise an instance with a certain reactive data, and then launch again with another configuration, the activity might crash).

  • config
  • activityData
  • rawData

activityData is a data structure that is merged into the activity using a the activity type's merge function. rawData is a snapshot of the underlying data, which is written directly to the ShareDB. If you are listening to the frog-data over postMessage, this is where you would send the data.

If you use both readOnly and rawData, it will simply use the activity type to display that data without loading any shareDB document etc. In that case, you still require config, but none of the other parameters are required or have any impact.

Logs

While an activity is running, it emits log messages using iFrame communications. Currently these are in the internal FROG format, but in the future, we will probably use xAPI. These have the type frog-log.

While activities are running, they also constantly update the state of the activity through iFrame messaging. Raw data is always sent, this has the type frog-data. Some activities are also able to generate more meaningful state messages, which typically uses information from the config. These activities also emit frog-data-transformed messages. And example is the ac-quiz activity, the internal data format is meaningless without access to the config:

 {
  "justification": "",
  "form": {"0": 0},
  "coordinates": {"x": 0, "y": 0, "valid": false}
}

Therefore, the dataTransformed can be useful, it looks like this:

 {
  "questions": ["Laquelle de ces expressions est fausse?"],
  "answers": [
    "Pour une variable discrète, le nombre de valeurs possibles est dénombrable."
  ],
  "answersIndex": [0],
  "maxCorrect": 1,
  "coordinates": {"x": 0, "y": 0, "valid": false}
}

Dashboard

Dashboards are unique to activities identified by clientId and activityId, but span all the user/instances.

To display the dashboards for an activity, use the following URL:

<FROGURL>/api/dashboard/<AC-NAME>.

POST parameters:

  • clientId: API user
  • activityId: optional, important if you have multiple activities of the same type, which should not share data/config
  • config: Required for some dashboards, such as ac-quiz Counts

Reference implementation

In frogapi-test, there is a demo application using create-react-app, which has no dependencies on FROG libraries. This implements both showing pre-configured FROG activities in an iFrame, and capturing log messages/activity state, but also configuring activities within the app.