API(應用程序編程接口)是一組規則,用於定義應用程序或設備如何相互連接和通信。REST(REpresentational State Transfer)API是一種符合特定設計原則的API。REST API 也可以稱為 RESTful API。下圖添加了更多詳細信息:
Brightcove 擁有眾多平台 RESTful API,允許您以編程方式訪問 Video Cloud/Brightcove Player 平台的幾乎所有方面。一般而言,API 可用來建立 CMS 或其他系統之間的整合,或是建置自訂應用程式以滿足使用者的特定需求。
本文檔的第一個示例使用Analytics API檢索並在 Brightcove 播放器控制欄中顯示播放器中當前視頻的觀看次數。第二個範例稍微複雜一些,使用 Brightcove Player 目錄結合使用,從帳戶Analytics API中擷取最受歡迎的影片,並將它們顯示在播放清單中。本文件中的程式碼討論將集中於從正確的 REST API 擷取所需的資料。
高階視圖
要使用 Brightcove REST API,您需要準備好幾個部分。簡單地說,他們是:
- 用戶端代碼:客戶端代碼要求特定的數據,然後根據應用程序要求顯示它。客戶端代碼將在一定的長度在本文件中討論,因為它是您需要最頻繁地編寫的內容。
- 代理伺服器:出於安全原因,REST API 不會直接接受來自客戶端的數據請求,因為這會鼓勵從客戶端發送機密信息,如客戶端憑據。這意味著代理將作為客戶端和 REST API 之間的中介。在示例中使用的代理是用 PHP 編寫的,並在本文件後面討論。代理必須在您控制的服務器上設置,並且可以用您選擇的語言編寫。代理的建議配置使其能夠被寫入一次並由任何 API 使用。
- 其餘 API :布萊特灣提供一套全方位的 API 來自訂、擴充和與布萊特灣平台整合。請參閱概觀:視訊雲端 API 文件以取得詳細資訊。
下圖顯示過程的三個核心實體之間的互動,以從 Brightcove 的 REST API 中檢索數據:
用戶端功能概觀
客戶端代碼根據您請求數據的 API 顯著變化。如上所述,代理是寫一次,不修改一段代碼,並且 API 由 Brightcove 維護。這就是為什麼文檔中的重點將是學習如何改變客戶端代碼從其中一個 API 中檢索所需的數據。
下圖著重於客戶端代碼的關鍵部分,那些是:
- 使到代理
HTTPRequest
的功能。為了避免模糊,函數被命名為makeRequest()
。如下圖所示的右側。 - 收集要求所需資訊的程式碼。圖表的左上角如圖所示。這段代碼通常非常簡單,並使用了眾所周知的概念,甚至開始程序員。
- 執行前面提到的
makeRequest()
函數的調用。圖表的左下角如圖所示。調用將函數makeRequest()
作為參數傳遞給。然後在makeRequest()
該函數中被調用。這是一個匿名定義的回調函數的例子。
您可以在圖表中看到標示為非同步活動的兩個區段。雖然在圖表中表示在兩個不同的地方,但這實際上是相同的異步活動,並表示它需要的未知時間:
- 客戶端發送請求到代理。
- 從 API 請求數據的代理。
- 用於構建結果集並將其返回到代理的 API。
- 代理將數據返回給客戶端。
請注意,調用makeRequest()
(左下方框)的框中的邏輯流箭頭似乎表明代碼在兩個不同的時間執行,這正是如此。對函數進行調用,但回調函數不會執行,makeRequest()
直到完成其工作並執行回調函數,該函數將請求的數據返回給函數調用代碼。
範例程式碼逐步解說
而不是將代碼視為一塊,它將在章節中呈現和討論。部分區段將與上圖相關。
標準播放程式碼
此程式碼區段包含基本的 Brightcove 播放程式內嵌程式碼。
- 第一至二十一號線:標準布萊特灣玩家代碼,加入一個
id
屬性。
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Untitled Document</title>
</head>
<body>
<video-js id="myPlayerID"
data-video-id="3851380732001"
data-account="1752604059001"
data-player="HkAzSmB0l"
data-embed="default"
data-application-id
controls
width="640"
height="360"></video-js>
<script src="https://players.brightcove.net/1752604059001/HkAzSmB0l_default/index.min.js"></script>
準備撥打電話
此代碼部分初始化變量,並準備進行調用makeRequest()
。一般來說,對於讀取請求,您需要提供以下資訊:
- 例如,您將使用的代理的 URL(當然,這需要在您的控制下):
https://solutions.brightcove.com/bcls/bcls-proxy/doc-samples-proxy-v2.php
- 實際請求所需的 URL,通常動態構建:
https://analytics.api.brightcove.com/v1/alltime/accounts/1752604059001/videos/4825279519001
- 例如,HTTP 方法
GET
。
範例如下:
- 第 1 行:標準代碼等待播放器準備好與之互動。
- 第 2-4 行:為稍後在代碼中需要的變量創建/設置值。
- 第 7-12 行:等待
loadstart
事件,以便填入mediainfo
物件。指派變數以保留Analytics API端點所需的值。 - 第 13 行:設定呼叫的 HTTP 方法。
videojs.getPlayer('myPlayerID').ready(function() {
var myPlayer = this,
accountId = myPlayer.bcinfo.accountId,
options = {};
// +++ Wait for loadstart event so can use mediainfo object +++
myPlayer.on('loadstart', function() {
var videoId = myPlayer.mediainfo.id,
baseURL = 'https://analytics.api.brightcove.com/v1/alltime/accounts/',
endPoint = accountId + '/videos/' + videoId;
options.proxyURL = "https://solutions.brightcove.com/bcls/bcls-proxy/doc-samples-proxy-v2.php";
options.url = baseURL + endPoint;
options.requestType = "GET";
呼叫makeRequest()
此代碼部分使調用makeRequest()
函數。請注意,傳遞兩個參數。第一個是保存端點信息的選項對象,第二個是回調函數。請記住,這是一個異步調用,因此匿名定義的回調函數將不會被調用,直到 REST API 返回數據給該makeRequest()
函數。
- 第 1 行:調用該
makeRequest()
函數,傳遞options
對象中調用所需的值。在此情況下,物件包含下列項目: - 第 3-13 行:回調函數被定義為匿名函數(以黃色突出顯示)。請記住,這個函數是一個參數,不是在這裡調用,但稍後在代碼中調用。
- 第 6 行,8,10:顯示的
console.log()
語句:- API 呼叫所傳回的原始 JSON 字串。
- 由從字符串轉換為對象的
JSON.parse()
方法生成的 JSON 對象。 - 實際的視圖計數,通過使用簡單的
object.property
符號從對象中提取。
- 第十二行:調用顯示在控制欄中的視圖數量的功能。
從控制台下面的屏幕截圖顯示從console.log
語句實際顯示的數據:
// +++ Make the request to the Analytics API +++
// Extract views from data returned by Analytics API
makeRequest(options, function(viewsRaw) {
var viewsCount;
// Remove console.log command for production code
console.log('viewsRaw', viewsRaw);
viewsObject = JSON.parse(viewsRaw);
console.log('viewsObject', viewsObject);
viewsCount = viewsObject.alltime_video_views;
console.log('views', viewsCount);
// Call function to place data in controlbar
placeCountInControlbar(viewsCount);
});
實際makeRequest()
函數
文件的這個區段會檢查實際定義makeRequest()
函數的程式碼。定義函數的代碼寫在這樣一種方式,它不需要被修改,但按原樣重複使用。您可能會發現邊緣情況並非如此,但對於絕大多數使用,此代碼不需要修改。
對代碼的逐行討論如下:
- 第 1-6 行:函數定義和變量創建。關鍵點是創建一個新的
XMLHttpRequest
對象。 - 第八條線,二十六號線:定義
readyState
變更的事件處理常式函數。 - 第九、二十三、二十五號線請求
try-catch
在高級別失敗的情況下使用. - 第十條第十條,第十一線:使用
if
語句來確保請求完成(readyState
為 4)並成功完成,狀態在 200 範圍內。下列顯示事件處理常式定義中的readyState
和status
值的主控台記錄: - 第 18 行:回調函數被執行。這會將傳回的資料從 API 傳回回回呼函式,如上述呼叫 MakeRequest () 一節所述。
- 第 33 行:設置事件的事件處理程序。
XMLHttpRequest.onreadystatechange
- 第三十五行:初始化代理的請求。
- 第 38 行:發送請求,這是異步的。
function makeRequest(options, callback) {
var httpRequest = new XMLHttpRequest(),
response,
requestParams,
dataString,
proxyURL = options.proxyURL,
// response handler
getResponse = function() {
try {
if (httpRequest.readyState === 4) {
if (httpRequest.status >= 200 && httpRequest.status < 300) {
response = httpRequest.responseText;
// some API requests return '{null}' for empty responses - breaks JSON.parse
if (response === '{null}') {
response = null;
}
// return the response
callback(response);
} else {
alert('There was a problem with the request. Request returned ' + httpRequest.status);
}
}
} catch (e) {
alert('Caught Exception: ' + e);
}
};
/**
* set up request data
* the proxy used here takes the following request body:
* JSON.stringify(options)
*/
// set response handler
httpRequest.onreadystatechange = getResponse;
// open the request
httpRequest.open('POST', proxyURL);
// set headers if there is a set header line, remove it
// open and send request
httpRequest.send(JSON.stringify(options));
}
顯示傳回的資料
此代碼顯示了如何將返回的數據放入控制欄。這個函數在回調函數的末尾調用,如上面的調用 MakeCequest()一節所示。
- 第五行,第十六行:定義函數。
- 第 6 行:為控制欄中的
spacer
元素創建一個變量。 - 第 7 行:動態建立
div
元素。 - 第 9 行:在新建立的
div
元素中放置標示和視圖值。 - 第 11 行:使用 JavaScript 的
document.getElementsByClassName()
方法來獲取控制欄的spacer
元素。 - 第 13 行:樣式
spacer
以從頂部向右對齊和向下顯示總視圖的 10pxspacer
。 - 第 15 行:添加新創建的,填充和樣式的元素到
spacer
.
/**
* Dynamically build a div that is then
* placed in the controlbar's spacer element
*/
function placeCountInControlbar(viewsCount) {
var spacer,
newElement = document.createElement('div');
//Place data in div
newElement.innerHTML = "Total Views: " + viewsCount;
//Get the spacer in the controlbar
spacer = document.getElementsByClassName('vjs-spacer')[0];
//Right justify content in the spacer and add top margin
spacer.setAttribute('style', 'justify-content: flex-end; margin-top: 10px');
//Add the dynamically built div to the spacer in the controlbar
spacer.appendChild(newElement);
}
完整的程式碼清單
完整的,正在運行的代碼位於這個 GitHub 存儲庫中: display-views-in-controlbar.html 。
簡單除錯
正如您所看到的,使用 REST API 時涉及許多部分。當應用程式無法正常運作時,這可能會造成挑戰。你從哪裡開始調試?
在本節中提出了幾個簡單的建議,是開始調試冒險的好地方。以下兩節提供了一種方法來查看您需要的最基本信息,通過進行通話時傳入的內容,以及返回的內容。
檢查通話選項
本文件中討論的客戶端代碼基本上是關於提供與代理一起使用的正確選項,以及實際的 API。因此,知道選項是正確的,對於代碼的正確運行至關重要。一個簡單的方法是在將options
對象傳遞到使用它們的makeRequest
函數之前登錄到控制台:
選項對象包含的內容將根據您想要做的事情而有所不同,但是一些基礎知識將始終存在,那些是:
- 帳號 ID。這可以是個別的屬性,也可以是 API 端點 URL 的一部分。
- 代理的 URL,這將取決於您存儲代理的位置。
- HTTP 方法類型,例如
GET
,POST
或PATCH
。 - 代理用於從 API 發出實際請求的 API 端點 URL。例如:
https://players.api.brightcove.com/v2/accounts/57838016001/players https://edge.api.brightcove.com/playback/v1/accounts/1752604059001/videos/5842800655001 https://analytics.api.brightcove.com/v1/alltime/accounts/1752604059001/videos/4093643993001
視 API 要求而定,在選項物件中可能需要其他屬性。以下是您在記錄選項對象時在控制台中看到的示例,以便為特定帳戶中的所有玩家提出請求:
以下是更新玩家時使用更複雜的記錄選項對象:
檢視傳回的資料
返回的內容將根據您請求的數據以及是否返回錯誤而有所不同。但是,無論返回什麼,您很可能想要查看返回哪些數據。一個簡單的方法是將原始日誌記錄到控制台response
調用後的數據makeRequest
功能:
將返回的內容幾乎有無限的可能性,但以下是幾個例子。第一個顯示在詢問帳號中的所有玩家時響應的開始:
以下是使用PATCH
HTTP 方法更新玩家後的響應:
這是第一個響應中數據的更好格式化的視圖:
{
"id": "1OHQdsTAr",
"preview_url": "http://preview-players.brightcove.net/v2/accounts/.../master/index.html",
"preview_embed_in_page": "http://preview-players.brightcove.net/v2/accounts/.../master/in_page.embed",
"preview_embed_code": "<iframe src='//preview-players.brightcove.net/v2/accounts/.../master/index.html' ...></iframe>"
}
最後,這是一個非常有價值的回應,從發生錯誤時。在這種情況下,帳戶正在使用沒有適當的認證:
其他疑難排解秘訣
如果您遇到問題,以下是其他一些需要尋找的事項。
- 沒有回應
- 有幾件事情可以檢查你是否得到一個空的響應:
- 檢查 API 引用以確保請求返回響應。有些只返回沒有內容的 201 或 204 響應(特別是,但不僅僅是 DELETE 請求)。您將需要調整您的代碼來處理這種情況。
- 檢查瀏覽器中開發人員工具的「網絡」部分,以確保您看到成功通話代理(該服務器可能暫時無法使用):
- 我看到一個響應,但是當我嘗試
JSON.parse()
它時,我得到一個例外。 - 這裡有些可能性:
- 看到上一個項目-試圖解析一個空的刺將拋出一個 JSON 異常
-
查看響應並確保它是一個 JSON 字符串(以
{
或 a 開頭[
)。在少數情況下,請求可能不會返回 JSON- Analytics API調用,例如,如果將format
參數設置為csv
或xlxs
。再次,如果您正在提出這些請求,則需要調整代碼以處理非 JSON 響應。 - 在大多數情況下,API 返回的錯誤也是 JSON 格式,但也有一些例外情況,其中錯誤以純文本或 HTML 形式返回。
代理代理代碼
如前所述,代理可以用您選擇的語言編寫。布賴特灣 API 文檔示例使用 PHP 編寫的代理。由於代理的實現是如此依賴於語言,下面的 PHP 代碼將不會在本文件中詳細分析。
代理伺服器提供的基本功能必須包括:
- 接受用戶端要求。
- 從 O Auth API 獲取身份驗證令牌。
- 將身份驗證令牌和數據請求(端點)發送到預期的 API。
- 從 API 接收數據。
- 將資料傳回給用戶端。
<?php
/**
* proxy for Brightcove RESTful APIs
* gets an access token, makes the request, and returns the response
* Accessing:
* (note you should **always** access the proxy via HTTPS)
* Method: POST
* request body (accessed via php://input) is a JSON object with the following properties
*
* {string} url - the URL for the API request
* {string} [requestType=GET] - HTTP method for the request
* {string} [requestBody] - JSON data to be sent with write requests
* {string} [client_id] - OAuth2 client id with sufficient permissions for the request
* {string} [client_secret] - OAuth2 client secret with sufficient permissions for the request
*
* Example:
* {
* "url": "https://cms.api.brightcove.com/v1/accounts/57838016001/video",
* "requestType": "PATCH",
* "client_id": "0072bebf-0616-442c-84de-7215bb176061",
* "client_secret": "7M0vMete8vP_Dmb9oIRdUN1S5lrqTvgtVvdfsasd",
* "requestBody": "{\"description\":\"Updated video description\"}"
* }
*
* if client_id and client_secret are not included in the request, default values will be used
*
* @returns {string} $response - JSON response received from the API
*/
// security checks
// if you want to do some basic security checks, such as checking the origin of the
// the request against some white list, this would be a good place to do it
// CORS enablement and other headers
header("Access-Control-Allow-Origin: *");
header("Content-type: application/json");
header("X-Content-Type-Options: nosniff");
header("X-XSS-Protection");
// default account values
// if you work on one Brightcove account, put in the values below
// if you do not provide defaults, the client id, and client secret must
// be sent in the request body for each request
$default_client_id = 'YOUR_CLIENT_ID';
$default_client_secret = 'YOUR_CLIENT_SECRET';
// get request body
$requestData = json_decode(file_get_contents('php://input'));
// set up access token request
// check to see if client id and secret were passed with the request
// and if so, use them instead of defaults
if (isset($requestData->client_id)) {
$client_id = $requestData->client_id;
}
if (isset($requestData->client_secret)) {
$client_secret = $requestData->client_secret;
}
$auth_string = "{$client_id}:{$client_secret}";
// make the request to get an access token
$request = "https://oauth.brightcove.com/v4/access_token?grant_type=client_credentials";
$curl = curl_init($request);
curl_setopt($curl, CURLOPT_USERPWD, $auth_string);
curl_setopt($curl, CURLOPT_POST, TRUE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'Content-type: application/x-www-form-urlencoded',
));
$response = curl_exec($curl);
$curl_info = curl_getinfo($curl);
$php_log = array(
"php_error_info" => $curl_info
);
$curl_error = curl_error($curl);
curl_close($curl);
// Check for errors
// it's useful to log as much info as possible for debugging
if ($response === FALSE) {
log_error($php_log, $curl_error);
}
// Decode the response and get access token
$responseData = json_decode($response, TRUE);
$access_token = $responseData["access_token"];
// get request type or default to GET
$method = "GET";
if ($requestData->requestType) {
$method = $requestData->requestType;
}
// get the URL and authorization info from the form data
$request = $requestData->url;
// check for a request body sent with the request
if (isset($requestData->requestBody)) {
$data = $requestData->requestBody;
}
$curl = curl_init($request);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
"Authorization: Bearer {$access_token}"
));
switch ($method)
{
case "POST":
curl_setopt($curl, CURLOPT_POST, TRUE);
if ($requestData->requestBody) {
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
break;
case "PUT":
// don't use CURLOPT_PUT; it is not reliable
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
if ($requestData->requestBody) {
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
break;
case "PATCH":
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
if ($requestData->requestBody) {
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
break;
case "DELETE":
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
if ($requestData->requestBody) {
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
break;
default:
// GET request, nothing to do;
}
$response = curl_exec($curl);
$curl_info = curl_getinfo($curl);
$php_log = array(
"php_error_info" => $curl_info
);
$curl_error = curl_error($curl);
curl_close($curl);
// Check for errors and log them if any
// note that logging will fail unless
// the file log.txt exists in the same
// directory as the proxy and is writable
if ($response === FALSE) {
log_error($php_log, $curl_error);
}
function log_error($php_log, $curl_error) {
$logEntry = "\nError:\n". "\n".date("Y-m-d H:i:s"). " UTC \n" .$curl_error. "\n".json_encode($php_log, JSON_PRETTY_PRINT);
$logFileLocation = "log.txt";
$fileHandle = fopen($logFileLocation, 'a') or die("-1");
fwrite($fileHandle, $logEntry);
fclose($fileHandle);
echo "Error: there was a problem with your API call"+
die(json_encode($php_log, JSON_PRETTY_PRINT));
}
// return the response to the AJAX caller
echo $response;
?>
雖然上面顯示了代理服務器的完整代碼,但它也位於 GitHub 存儲庫中:示例代理應用程序在裡面PHP文件夾。
範例 2
這第二個例子比前面詳述的更複雜。此範例會顯示播放清單中帳戶中最受歡迎的 10 部影片。代碼的主要步驟是:
- 從帳戶中具有最多觀看次數的 10 視頻請求。Analytics API這一步涉及使用回調函數的異步調用。
- 從傳回的Analytics API資料中,只擷取視訊 ID 並將它們放置在陣列中。一個輔助函數被寫入做從返回的數據提取 ID。
- 請求陣列中 ID 清單中每個視訊的完整視訊物件。這個步驟涉及在陣列上循環,並使用請求視訊物件
player.catalog.getVideo()
。當然,這涉及多個使用catalog
.一個輔助函數被寫入檢索基於 ID 的視頻對象,並將對象放入一個數組。 - 將視訊物件陣列放入播放清單啟用播放清單的播放清單中。
由於您現在已熟悉許多關於如何呼叫 API 的概念和特定程式碼,因此只有呼叫makeRequest()
函式的程式碼會詳細說明。
- 第 2 行:呼叫
makeRequest()
函數作為引數傳遞成功 REST API 呼叫所需的選項,以及匿名定義的回呼函數 (以黃色突出顯示)。這聽起來應該從上面看起來很熟悉。非常重要的是,調用的makeRequest()
函數是前面的例子中使用的完全相同的函數。你可以在你的代碼中做同樣的事情。該makeRequest()
函數被寫入為在任何對布賴特灣 REST API 的調用中重複使用。 - 第 3 行:創建一個變量來保存 JSON 解析返回的數據。
- 第 5 行:解析返回的數據,如果從字符串轉換為對象。
- 第 7 行:使用輔助函數從返回的數據中提取視頻 ID。不幸的是,Analytics API不會返回完整的視頻對象,因此需要 ID 來訪問完整對象。
- 第 9-12 行:調用使用回調
getVideoData
函videoObjects
數根據傳遞的 ID 填充數組的輔助函數。 - 第 11 行:使用視訊物件陣列填入播放清單。
// +++ Make the CMS API request to get matching video IDs +++
makeRequest(options, function(mostWatchedVideos) {
var JSONmostWatchedVideos;
// Convert response string into JSON
JSONmostWatchedVideos = JSON.parse(mostWatchedVideos);
// Extract the needed video IDs into an array
videoData = extractVideoData(JSONmostWatchedVideos);
// Get video objects based on array of video IDs
getVideoData(videoData, function(videoObjects) {
// Add the most watched videos list to the player as a playlist
myPlayer.playlist(videoObjects);
});
});
完整的程式碼清單
完整、運作的範例位於這個 CodePen:播放清單中最多觀看的影片。