🚀 Mux Node API Library
このライブラリは、サーバーサイドのTypeScriptまたはJavaScriptからMux REST APIに簡単にアクセスできるようにするものです。
⚠️ 重要な注意
2024年2月にこのSDKはバージョン8.0に更新されました。8.xへのアップグレードについては、UPGRADE_8.x.mdを参照してください。
REST APIのドキュメントはdocs.mux.comで確認できます。このライブラリの完全なAPIはapi.mdに記載されています。
🚀 クイックスタート
このライブラリを使うことで、サーバーサイドのTypeScriptまたはJavaScriptからMux REST APIに簡単にアクセスできます。以下に、基本的な使い方を説明します。
📦 インストール
npm install @mux/mux-node
💻 使用例
基本的な使用法
import Mux from '@mux/mux-node';
const client = new Mux({
tokenId: process.env['MUX_TOKEN_ID'],
tokenSecret: process.env['MUX_TOKEN_SECRET'],
});
const asset = await client.video.assets.create({
inputs: [{ url: 'https://storage.googleapis.com/muxdemofiles/mux-video-intro.mp4' }],
playback_policies: ['public'],
});
console.log(asset.id);
高度な使用法
リクエストとレスポンスの型
このライブラリには、すべてのリクエストパラメータとレスポンスフィールドのTypeScript定義が含まれています。次のようにインポートして使用できます。
import Mux from '@mux/mux-node';
const client = new Mux({
tokenId: process.env['MUX_TOKEN_ID'],
tokenSecret: process.env['MUX_TOKEN_SECRET'],
});
const params: Mux.Video.AssetCreateParams = {
inputs: [{ url: 'https://storage.googleapis.com/muxdemofiles/mux-video-intro.mp4' }],
playback_policies: ['public'],
};
const asset: Mux.Video.Asset = await client.video.assets.create(params);
各メソッド、リクエストパラメータ、およびレスポンスフィールドのドキュメントはdocstringに記載されており、ほとんどの最新のエディタでホバーすると表示されます。
任意のJWT互換ライブラリを使用できますが、SDKにはいくつかの軽量なヘルパーが含まれており、すぐに使い始めるのが簡単になっています。
const token = mux.jwt.signPlaybackId('some-playback-id');
const thumbParams = { time: 14, width: 100 };
const thumbToken = mux.jwt.signPlaybackId('some-playback-id', {
type: 'thumbnail',
params: thumbParams,
});
const gifToken = mux.jwt.signPlaybackId('some-playback-id', { type: 'gif' });
const storyboardToken = mux.jwt.signPlaybackId('some-playback-id', {
type: 'storyboard',
});
const statsToken = mux.jwt.signViewerCounts('some-live-stream-id', {
type: 'live_stream',
});
複数のJWTを一度に署名する
Mux Playerを使用する場合など、複数のトークンが必要な場合、すぐに扱いにくくなることがあります。例えば、
const playbackToken = await mux.jwt.signPlaybackId(id, {
expiration: "1d",
type: "playback"
})
const thumbnailToken = await mux.jwt.signPlaybackId(id, {
expiration: "1d",
type: "thumbnail",
})
const storyboardToken = await mux.jwt.signPlaybackId(id, {
expiration: "1d",
type: "storyboard"
})
const drmToken = await mux.jwt.signPlaybackId(id, {
expiration: "1d",
type: "drm_license"
})
<mux-player
playback-token={playbackToken}
thumbanil-token={thumbnailToken}
storyboard-token={storyboardToken}
drm-token={drmToken}
playbackId={id}
></mux-player>
このユースケースを簡素化するために、signPlaybackId
に複数のタイプを指定して、複数のトークンを取得できます。これらのトークンは、Mux Playerがpropsとして受け取ることができる形式で提供されます。
const tokens = await mux.jwt.signPlaybackId(id, {
expiration: "1d",
type: ["playback", "thumbnail", "storyboard", "drm_license"]
})
<mux-player
{...tokens}
playbackId={id}
></mux-player>
単一のトークンにパラメータを指定する場合(例えば、サムネイルのtime
を指定する場合)、type
の代わりに[type, typeParams]
を指定できます。
const tokens = await mux.jwt.signPlaybackId(id, {
expiration: "1d",
type: ["playback", ["thumbnail", { time: 2 }], "storyboard", "drm_license"]
})
Webhookペイロードの解析
与えられたペイロードがMuxから送信されたものであることを検証し、Webhookペイロードをアプリケーションで使用するために解析するには、mux.webhooks.unwrap
ユーティリティメソッドを使用できます。
このメソッドは、生のbody
文字列とヘッダーのリストを受け取ります。ライブラリをインスタンス化する際にwebhookSecret
を適切な構成プロパティに設定している限り、すべてのWebhookは自動的に正当性が検証されます。
次の例は、Next.jsアプリディレクトリAPIルートを使用してWebhookを処理する方法を示しています。
import { revalidatePath } from 'next/cache';
import { headers } from 'next/headers';
import Mux from '@mux/mux-node';
const mux = new Mux({
webhookSecret: process.env.MUX_WEBHOOK_SECRET,
});
export async function POST(request: Request) {
const headersList = headers();
const body = await request.text();
const event = mux.webhooks.unwrap(body, headersList);
switch (event.type) {
case 'video.live_stream.active':
case 'video.live_stream.idle':
case 'video.live_stream.disabled':
if (event.data.id === 'MySpecialTVLiveStreamID') {
revalidatePath('/tv');
}
break;
default:
break;
}
return Response.json({ message: 'ok' });
}
Webhook署名の検証
Webhook署名の検証は_オプションですが、推奨されます_。詳細については、Webhookセキュリティガイドを参照してください。
mux.webhooks.verifySignature(body, headers, secret);
ペイロード(body)を渡す際には、生の解析されていないリクエストボディを渡す必要があり、解析されたJSONではないことに注意してください。expressを使用している場合の例を次に示します。
const Mux = require('@mux/mux-node');
const mux = new Mux();
const express = require('express');
const bodyParser = require('body-parser');
const webhookSecret = process.env.WEBHOOK_SECRET;
const app = express();
app.post('/webhooks', bodyParser.raw({ type: 'application/json' }), async (req, res) => {
try {
const isValidSignature = mux.webhooks.verifySignature(req.body, req.headers, webhookSecret);
console.log('Success:', isValidSignature);
const jsonFormattedBody = JSON.parse(req.body);
res.json({ received: true });
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`);
}
});
app.listen(3000, () => {
console.log('Example app listening on port 3000!');
});
エラーの処理
ライブラリがAPIに接続できない場合、またはAPIが成功しないステータスコード(つまり、4xxまたは5xxのレスポンス)を返す場合、APIError
のサブクラスがスローされます。
const liveStream = await client.video.liveStreams
.create({ playback_policies: ['public'] })
.catch(async (err) => {
if (err instanceof Mux.APIError) {
console.log(err.status);
console.log(err.name);
console.log(err.headers);
} else {
throw err;
}
});
エラーコードは次のとおりです。
ステータスコード |
エラータイプ |
400 |
BadRequestError |
401 |
AuthenticationError |
403 |
PermissionDeniedError |
404 |
NotFoundError |
422 |
UnprocessableEntityError |
429 |
RateLimitError |
>=500 |
InternalServerError |
N/A |
APIConnectionError |
リトライ
特定のエラーは、デフォルトで2回自動的にリトライされ、短い指数バックオフが適用されます。接続エラー(例えば、ネットワーク接続の問題による)、408 Request Timeout、409 Conflict、429 Rate Limit、および>=500 Internalエラーはすべて、デフォルトでリトライされます。
maxRetries
オプションを使用して、これを構成または無効にすることができます。
const client = new Mux({
maxRetries: 0,
});
await client.video.assets.retrieve('t02rm...', {
maxRetries: 5,
});
タイムアウト
リクエストはデフォルトで1分後にタイムアウトします。timeout
オプションでこれを構成できます。
const client = new Mux({
timeout: 20 * 1000,
});
await client.video.assets.retrieve('t02rm...', {
timeout: 5 * 1000,
});
タイムアウトすると、APIConnectionTimeoutError
がスローされます。
タイムアウトしたリクエストはデフォルトで2回リトライされます。
自動ページネーション
Mux APIのリストメソッドはページングされています。for await … of
構文を使用して、すべてのページのアイテムを反復処理できます。
async function fetchAllDeliveryReports(params) {
const allDeliveryReports = [];
for await (const deliveryReport of client.video.deliveryUsage.list()) {
allDeliveryReports.push(deliveryReport);
}
return allDeliveryReports;
}
あるいは、一度に1ページを要求することもできます。
let page = await client.video.deliveryUsage.list();
for (const deliveryReport of page.data) {
console.log(deliveryReport);
}
while (page.hasNextPage()) {
page = await page.getNextPage();
}
高度な使用法
生のレスポンスデータ(例:ヘッダー)へのアクセス
fetch()
によって返される「生の」Response
は、すべてのメソッドが返すAPIPromise
型の.asResponse()
メソッドを介してアクセスできます。
.withResponse()
メソッドを使用して、解析されたデータとともに生のResponse
を取得することもできます。
const client = new Mux();
const response = await client.video.assets
.create({
inputs: [{ url: 'https://storage.googleapis.com/muxdemofiles/mux-video-intro.mp4' }],
playback_policies: ['public'],
})
.asResponse();
console.log(response.headers.get('X-My-Header'));
console.log(response.statusText);
const { data: asset, response: raw } = await client.video.assets
.create({
inputs: [{ url: 'https://storage.googleapis.com/muxdemofiles/mux-video-intro.mp4' }],
playback_policies: ['public'],
})
.withResponse();
console.log(raw.headers.get('X-My-Header'));
console.log(asset.id);
カスタム/非ドキュメント化されたリクエストの実行
このライブラリは、ドキュメント化されたAPIに便利にアクセスするために型付けされています。非ドキュメント化されたエンドポイント、パラメータ、またはレスポンスプロパティにアクセスする必要がある場合でも、ライブラリを使用できます。
非ドキュメント化されたエンドポイント
非ドキュメント化されたエンドポイントにリクエストを送信するには、client.get
、client.post
、およびその他のHTTPメソッドを使用できます。クライアントのオプション(例:リトライ)は、これらのリクエストを行う際に尊重されます。
await client.post('/some/path', {
body: { some_prop: 'foo' },
query: { some_query_arg: 'bar' },
});
非ドキュメント化されたパラメータ
非ドキュメント化されたパラメータを使用してリクエストを行うには、非ドキュメント化されたパラメータに// @ts-expect-error
を使用できます。このライブラリは実行時にリクエストが型に一致することを検証しないため、送信するすべての追加値はそのまま送信されます。
client.foo.create({
foo: 'my_param',
bar: 12,
baz: 'undocumented option',
});
GET
メソッドのリクエストの場合、追加のパラメータはクエリに含まれ、その他のすべてのリクエストは追加のパラメータをボディに送信します。
明示的に追加の引数を送信する場合は、query
、body
、およびheaders
リクエストオプションを使用できます。
非ドキュメント化されたプロパティ
非ドキュメント化されたレスポンスプロパティにアクセスするには、レスポンスオブジェクトに// @ts-expect-error
を使用するか、レスポンスオブジェクトを必要な型にキャストできます。リクエストパラメータと同様に、APIからのレスポンスの追加プロパティは検証または削除されません。
フェッチクライアントのカスタマイズ
デフォルトでは、このライブラリはNodeでnode-fetch
を使用し、その他の環境ではグローバルなfetch
関数を期待します。
Node環境でもグローバルなWeb標準準拠のfetch
関数を使用したい場合(例えば、--experimental-fetch
でNodeを実行している場合、またはundici
でポリフィルされるNextJSを使用している場合)、最初にfrom "Mux"
をインポートする前に次のインポートを追加します。
import '@mux/mux-node/shims/web';
import Mux from '@mux/mux-node';
逆にするには、import "@mux/mux-node/shims/node"
を追加します(これはポリフィルをインポートします)。
これは、Response
のTypeScript型が間違っている場合にも役立ちます(詳細)。
ロギングとミドルウェア
クライアントをインスタンス化する際に、カスタムのfetch
関数を指定することもできます。これを使用して、各リクエストの前後にRequest
またはResponse
を検査または変更できます。
import { fetch } from 'undici';
import Mux from '@mux/mux-node';
const client = new Mux({
fetch: async (url: RequestInfo, init?: RequestInit): Promise<Response> => {
console.log('About to make a request', url, init);
const response = await fetch(url, init);
console.log('Got response', response);
return response;
},
});
DEBUG=true
環境変数が指定されている場合、このライブラリはすべてのリクエストとレスポンスを自動的にログに記録します。
これはデバッグ目的のみを意図しており、将来的に予告なく変更される可能性があります。
HTTP(S)エージェントの構成(例:プロキシ用)
デフォルトでは、このライブラリはすべてのhttp/httpsリクエストに安定したエージェントを使用してTCP接続を再利用し、多くのTCPおよびTLSハンドシェイクを排除し、ほとんどのリクエストから約100msを削減します。
この動作を無効にするか、カスタマイズしたい場合(例えば、プロキシの背後でAPIを使用する場合)、すべてのリクエスト(httpまたはhttps)に使用されるhttpAgent
を渡すことができます。例えば:
import http from 'http';
import { HttpsProxyAgent } from 'https-proxy-agent';
const client = new Mux({
httpAgent: new HttpsProxyAgent(process.env.PROXY_URL),
});
await client.video.assets.retrieve('t02rm...', {
httpAgent: new http.Agent({ keepAlive: false }),
});
セマンティックバージョニング
このパッケージは一般的にSemVerの規則に従っていますが、一部の下位互換性のない変更はマイナーバージョンとしてリリースされる場合があります。
- 実行時の動作を破壊せず、静的な型のみに影響する変更。
- 技術的には公開されているが、外部での使用を意図していない、またはドキュメント化されていないライブラリの内部の変更。(このような内部機能に依存している場合は、GitHubのissueを開いてお知らせください。)
- 実際には大多数のユーザーに影響を与えないと思われる変更。
私たちは下位互換性を真摯に受け止め、スムーズなアップグレード体験を保証するために努力しています。
あなたのフィードバックを歓迎します。質問、バグ、または提案がある場合は、issueを開いてください。
要件
TypeScript >= 4.5がサポートされています。
以下のランタイムがサポートされています。
- Webブラウザ(最新のChrome、Firefox、Safari、Edgeなど)
- Node.js 18 LTS以降のバージョン(非EOL)
- Deno v1.28.0以上
- Bun 1.0以上
- Cloudflare Workers
- Vercel Edge Runtime
- Jest 28以上で、
"node"
環境(現時点では"jsdom"
はサポートされていません)
- Nitro v2.6以上
現時点ではReact Nativeはサポートされていません。
他のランタイム環境に興味がある場合は、GitHubでissueを開くか、投票を行ってください。
コントリビューション
詳細はコントリビューションドキュメントを参照してください。