Introduction

In this guide, we will walk through the general Guru API workflow: authenticating your requests, uploading a video, and fetching the results. You can clone an example Express.js app that implements this workflow here and read the code walkthrough below:

Requirements

Code Walkthrough

Authentication

Authentication with the Guru API occurs using OAuth tokens. You must include your authentication token as a header on each HTTP request you make like this:

Authorization: <token>

Your service will obtain its authentication token using an OAuth Client-Credential Flow:

  1. Exchange your client ID and secret with https://customer-console-prod.auth.us-west-2.amazoncognito.com for an access token. The value of the expires_in field in the response is the number of seconds until this token expires.

  2. Store the token along with its expiration date in persistent storage so that it can be re-used on each call. It is important to not request new tokens on each call as your application will be rate limited.

  3. Before making a call to the Guru API, check if the token is expired and, if so, refresh it.

  4. Make the call to the Guru API using the access token.

Here’s is working code that performs the credential exchange:

  const client_id = process.env.GURU_CLIENT_ID;
  const client_secret = process.env.GURU_CLIENT_SECRET;

  const options = {
    method: "POST",
    url: "https://customer-console-prod.auth.us-west-2.amazoncognito.com/oauth2/token",
    headers: { "content-type": "application/x-www-form-urlencoded" },
    data: `grant_type=client_credentials&client_id=${client_id}&client_secret=${client_secret}&scope=https://api.getguru.fitness/default`,
  };

  const response = await axios(options);
  const tokenData = {
    token: response.data.access_token,
    expiry: Date.now() + response.data.expires_in * 1000,
  };
  fs.writeFileSync("token.json", JSON.stringify(tokenData));
  return tokenData.token;
};

Analyzing Videos

Uploading a video for analysis is a three-step process:

  1. Call the Create API to specify the video’s metadata. This will tell Guru some basic information about the video such as its size and what schema should be applied to the video. This information helps deliver more accurate analysis results. The API will return a URL that specifies where the video should be uploaded to.

  2. Upload the video content to the URL returned in step 1. The video will be encoded as multipart/form-data in the request.

  3. Poll the Analysis API until the video is ready. It will typically take 30 seconds for analysis to complete, though longer wait times may be experienced for larger videos. See below for details on each individual API call.

Here is the code block in our Express.js app that handles uploading a video.

Uploading video

// Function to upload a video
const uploadVideo = async (authToken) => {
  const videoPath = "./videos/test.mp4";
  const videoStream = fs.createReadStream(videoPath);
  const videoSizeInBytes = fs.statSync(videoPath).size;
  const videoData = {
    filename: "test_squat.mp4",
    size: videoSizeInBytes,
    schemaId: "1569597a-3b59-45bf-9048-7287be905f48",
    source: "guru-api-test",
  };

  const createVideoResponse = await axios({
    method: "post",
    url: "https://api.getguru.fitness/videos",
    headers: { Authorization: authToken },
    data: videoData,
  });

  const formData = new FormData();
  Object.keys(createVideoResponse.data.fields).forEach((key) => {
    formData.append(key, createVideoResponse.data.fields[key]);
  });
  formData.append("file", videoStream, "test_squat.mp4");

  await axios.post(createVideoResponse.data.url, formData, {
    headers: { ...formData.getHeaders() },
  });

  return createVideoResponse.data.id;
};

And here is the code block that fetches the video analysis

Fetching Analysis

// Function to get video analysis
const getAnalysis = async (videoId, authToken) => {
  const endTime = Date.now() + 5 * 60 * 1000; // 5 minutes from now

  while (Date.now() < endTime) {
    try {
      const response = await axios({
        url: `https://api.getguru.fitness/videos/${videoId}/analysis`,
        headers: { Authorization: authToken },
      });

      if (response.data.status && response.data.status === "Pending") {
        console.log("Polling for video analysis...");
        await new Promise((resolve) => setTimeout(resolve, 5000)); // Poll every 5 seconds
      } else {
        return response.data;
      }
    } catch (error) {
      console.error("Error during polling for video analysis:", error.message);
    }
  }

  throw new Error("Video analysis did not complete in the expected time.");
};

The general workflow Guru API workflow— authentiating, uploading, and analyzing videos—is now complete. Next steps: