Uploading Media

This page will help you understand how media (video, images, or audio) are uploaded into OttoLearn media library.

This guide will provide a walk through of creating and uploading a file to a new media item. All media items are part of a media library. By default there should be at least one media library in your organization. When a media item is created it will not contain any files. To upload a file to a media item a request to upload media needs to be made to return the security policy fields and URL for media upload. Once the upload security policy is created for the media item a multipart/form-data POST request can be made that includes the security policy fields and file data.

List Media Libraries

To list the media libraries of your organization send a GET request to the endpoint https://api.ottolearn.io/v1/rest/mediaLibrary

const sessionToken = '123456789abcdefgh';

fetch(
  'https://api.ottolearn.io/v1/rest/mediaLibrary',
  {
    method: 'GET',
    headers:{
      'Authorization': sessionToken
    }
  }
)
    .then((response) => {
      switch (response.status) {
        case 403:
          throw new Error(`
            Access Denied.
            Invalid session token
          `);
        case 200:
          // Query was completed successfully
          return response.json();
        default:
          throw new Error(`
						Unexpected response from API.
						Please try again later
					`);
      }
    })
    .then((body) => {
      /**
       * SAMPLE BODY
       * [
       *   {
       *     "id": 1,
       *     "createdAt": "2020-04-30T14:49:52.675Z",
       *     "updatedAt": "2020-04-30T14:49:52.675Z",
       *     "name": "default"
       *   }
       * ]
       */
      console.log('BODY', body);

      const mediaLibraryId = body[0].id;

      return mediaLibraryId;
    });

Create Media Item

To create a media item send a POST request to the endpoint https://api.ottolearn.io/v1/rest/mediaItem with the mediaLibraryId, name, and type. The type field can be video, audio, or image.

For example to create a media item for an image with name "Dog":

const mediaLibraryId = 1;
const mediaItem = {
  "name": "Dog",
  "mediaLibraryId": mediaLibraryId,
  "type": "image"
};

const sessionToken = '123456789abcdefgh';

fetch(
  'https://api.ottolearn.io/v1/rest/mediaItem',
  {
    method: 'POST',
    body: JSON.stringify(mediaItem),
    headers:{
      'Authorization': sessionToken,
      'Content-Type': 'application/json'
    }
  }
)
    .then((response) => {
      switch (response.status) {
        case 403:
          throw new Error(`
            Access Denied.
            Invalid session token
          `);
        case 200:
          // Query was completed successfully
          return response.json();
        default:
          throw new Error(`
						Unexpected response from API.
						Please try again later
					`);
      }
    })
    .then((body) => {
      /**
       * SAMPLE BODY
       *  {
       *      "id": 1,
       *      "createdAt": "2020-05-12T20:50:25.583Z",
       *      "updatedAt": "2020-05-12T20:50:25.583Z",
       *      "name": "Dog",
       *      "label": null,
       *      "type": "image",
       *      "mediaLibraryId": 1
       *  }
       */
      console.log('BODY', body);

      const mediaLibraryId = body.id;

      return mediaLibraryId;
    });

Request Media Item Upload

To request a media item upload send a POST request to the endpoint https://api.ottolearn.io/v1/rest/mediaItem(${mediaItemId})/Media.RequestMediaItemUpload, where ${mediaItemId} is equal to the id of the media item. The request takes filename, filesize and chunked. Uploads must be chunked and sent in multiple requests if they are larger than 5mb.

For example to send a upload request for file with name "dog.jpg" and size of 1000bytes to media item with id 1.

const mediaRequest = {
  "filename": "dog.jpg",
  "filesize": 1000,
  "chunked": false
};

const sessionToken = '123456789abcdefgh';

fetch(
  'https://api.ottolearn.io/v1/rest/mediaItem(1)/Media.RequestMediaItemUpload',
  {
    method: 'POST',
    body: JSON.stringify(mediaRequest),
    headers:{
      'Authorization': sessionToken,
      'Content-Type': 'application/json'
    }
  }
)
    .then((response) => {
      switch (response.status) {
        case 403:
          throw new Error(`
            Access Denied.
            Invalid session token
          `);
        case 200:
          // Query was completed successfully
          return response.json();
        default:
          throw new Error(`
						Unexpected response from API.
						Please try again later
					`);
      }
    })
    .then((body) => {
      /**
       * SAMPLE BODY
       *  {
       *      "url": "https://upload.media.ottolearn.io/",
       *      "fields": {
       *          "acl": "private",
       *          "success_action_status": "201",
       *          "X-Amz-Algorithm": "AWS4-HMAC-SHA256",
       *          "X-Amz-Credential": "sampleCredential",
       *          "X-Amz-Date": "20200513T161222Z",
       *          "X-Amz-Security-Token": "sampleSecurityToken=",
       *          "Policy": "samplePolicy==",
       *          "X-Amz-Signature": "1234567abcde"
       *      },
       *      "path": "uploads/1234/"
       *  }
       */
      console.log('BODY', body);
  
      return body;
    });

Upload media <5mb (non chunked)

To upload media a POST request must be made to the URL returned from the request media upload item.

The body of the request must by multipart/form-data. It must include all properties found in fields property from the response of request media item upload API. As well as key, which is equal to the request media upload path and the file name concatenated together, and file which has the file data.

For example to upload a file with name dog.jpg using the response of request media item upload API from above:

// Policy is returend by request media item upload API
const policy =  {
  "url": "https://upload.media.ottolearn.io/",
  "fields": {
    "acl": "private",
    "success_action_status": "201",
    "X-Amz-Algorithm": "AWS4-HMAC-SHA256",
    "X-Amz-Credential": "sampleCredential",
    "X-Amz-Date": "20200513T161222Z",
    "X-Amz-Security-Token": "sampleSecurityToken=",
    "Policy": "samplePolicy==",
    "X-Amz-Signature": "1234567abcde"
  },
  "path": "uploads/1234/"
};

// File data comes from form input file field or NodeJS Buffer
const fileData  = new Blob('someFileData');
const fileName = 'dog.jpg';

const uploadURL = policy.url;
const policyFields = policy.fields;
const policyPath = policy.path;
// Key is the policy path concated with the file name
const key = `${policyPath}${fileName}`;

const formData = new FormData();

// Add each policy filed to multipart/form-data request
for (const policyField in policyFields) {
  const name = policyField;
  const value = policyFields[policyField];

  formData.append(name, value);
}

// Add key to multipart/form-data request
formData.append('key', key);
// Add file data to multipart/form-data request
formData.append('file', fileData);


const sessionToken = '123456789abcdefgh';

fetch(
  uploadURL,
  {
    method: 'POST',
    body: formData,
    // Do not include Authorization header for this request
    headers:{}
  }
)
    .then((response) => {
      switch (response.status) {
        case 200:
          // Query was completed successfully
          return;
        default:
          throw new Error(`
						Unexpected response from API.
						Please try again later
					`);
      }
    })
    .then(() => {
   		// Response body can be ignored
      return true;
    });

Upload media >5mb (chunked)

Media uploads larger than 5mb must be chunked and sent in multiple requests. The max chunk size is 5243000bytes. Chunked upload request are the same as chunked requests above expect the property key in the multipart/form-data body has the chunk number appended to the end except on the last request.

For example if a media file with name big_dog.jpg has a size of 15mb it would need 3 chunks/requests to upload it. The following keys would be used if path is uploads/1234/

Request 1

  • Key: uploads/1234/big_dog.jpg.0
  • File Byte Range: 0 - 5243000

Request 2

  • Key: uploads/1234/big_dog.jpg.1
  • File Byte Range: 5243000 - 10486000

Request 3

  • Key: uploads/1234/big_dog.jpg
  • File Byte Range: 10486000 - 15000000

Get Media Item

After the upload has completed the media will be transcoded and attached to the media item. To check if the upload has completed call the get media item API and inspect the files array in the response. This should take less than one minute depending on file size of media.

For example to get media item with id 1:

const sessionToken = '123456789abcdefgh';

fetch(
  'https://api.ottolearn.io/v1/rest/mediaItem(1)',
  {
    method: 'GET',
    headers:{
      'Authorization': sessionToken
    }
  }
)
    .then((response) => {
      switch (response.status) {
        case 403:
          throw new Error(`
            Access Denied.
            Invalid session token
          `);
        case 200:
          // Query was completed successfully
          return response.json();
        default:
          throw new Error(`
						Unexpected response from API.
						Please try again later
					`);
      }
    })
    .then((body) => {
      /**
       * SAMPLE BODY
       *  {
       *      "id": 12345,
       *      "createdAt": "2020-04-26T19:24:04.585Z",
       *      "updatedAt": "2020-04-26T19:24:46.259Z",
       *      "name": "Dog",
       *      "filename": "dog.jpg",
       *      "label": null,
       *      "type": "image",
       *      "basePath": "https://media.ottolearn.io/o/1/library/1/item/1234",
       *      "mediaLibraryId": 1,
       *      "files": [
       *          {
       *              "id": 12,
       *              "createdAt": "2020-04-26T19:24:46.404Z",
       *              "updatedAt": "2020-04-26T19:24:46.404Z",
       *              "file": "abc123.png",
       *              "filesize": 1000,
       *              "metadata": {
       *                  "width": 800,
       *                  "height": 533
       *              },
       *              "status": "active",
       *              "mediaLibraryItemId": 12345
       *          }
       *      ]
       *  }
       */
      console.log('BODY', body);

      const mediaLibraryId = body.id;

      return mediaLibraryId;
    });