SupDesk SDK のご紹介

SupDesk Team

本格的なプロダクトを開発していると、いずれ統合レイヤーを書くことになります。受信箱から読み込むスクリプト、ボードを同期する cron ジョブ、自社 UI からフィードバックを登録するエンドポイントなどです。キーボードに向かっているときは SupDesk コンソールが最適ですが、自動化したいと思った瞬間から API が必要になり、API の利便性はそれを操作するクライアントの出来に左右されます。

本日、4 つの SDK をリリースします。

SDK のラインナップ

  • JavaScript / TypeScript — npm の supdesk。ランタイム依存関係ゼロで、Node 18+、Deno、Bun、Cloudflare Workers 上でそのまま動作します。
  • Python — PyPI の supdesk。単一の httpx コアを共有する同期の SupDesk クライアントと非同期の AsyncSupDesk クライアント。
  • Gogithub.com/rabinapps/supdesk-go。標準ライブラリのみで構成されているため、GOOS=wasip1 による Cloudflare Workers を含め、Go 1.23+ が動作するあらゆる環境でビルド可能です。
  • Dart — pub.dev の supdesk。dio をベースに構築されているため、インターセプター、CancelToken、プロキシアダプターがすべて想定通りに機能します。

インストール

npm install supdesk
pip install supdesk
go get github.com/rabinapps/supdesk-go
dependencies:
  supdesk: ^0.1.0

1 つの API、4 つの言語

これらの SDK は単に 4 つの別個のラッパーではありません。すべての言語で同じセマンティクスを持つ同一の API です。いずれか 1 つの言語で投稿を読み込む方法を理解していれば、4 つすべてで同様に操作できます。

自動ページネーション。 list() は非同期イテラブルでもあるページを返します。for await で全ページを巡回することも、必要なときに最初のページだけを取得することも可能です。

型付きリソース。 投稿、フィードバック、チェンジログエントリー、メッセージ、ウェイトリスト登録、ベータプログラムとテスター、ヘルプセンターの文言・カテゴリーなど、各リソースには想定通りのメソッドと型付きパラメーターが備わっており、タイポは本番環境ではなくコンパイル時に検知されます。

型付きエラー。 すべてのエラーは単一のベースクラス(JS/Python では SupDeskError、Go では APIError、Dart では SupDeskException)を継承しています。そのため、1 つの catch ですべてを処理しつつ、instanceoferrors.As で特定のケースに絞り込むことができます。

Webhook。 constructEventFromRequestconstruct_event_from_headersConstructEventconstructEventFromHeaders は定数時間で SupDesk の署名を検証するため、受信側が処理するデータの信頼性を確保できます。

組み込みのレジリエンス。 すべてのクライアントは指数バックオフとジッターで再試行を行い、Retry-After を尊重します。また、すでに受理された可能性のある従量課金対象の POST を再試行することはありません。不安定なネットワークによってユーザーのチケットが二重送信される心配はありません。

サーバーサイド専用設計

SupDesk API キーはプロジェクト全体として認証を行うため、SDK はブラウザー上での実行を拒否します。JS および Dart のコンストラクターは DOM やクライアントビルドを検出すると例外をスローし、README にはその理由が明記されています。キーは、自身が管理するエンドポイントの背後にあるサーバーサイドの環境変数に保管してください。

補足として知っておくべき 2 つの点:読み取りは全プランで機能しますが、書き込み(POST/PATCH/DELETE)には有料プランが必要です。また、キーはプロジェクトスコープであるため、環境ごとに独自のキーを割り当てれば、他の環境に影響を与えることなく 1 つだけを失効させることができます。

SupDesk の適用領域

これらの SDK は、SupDesk SaaS 統合ガイド のバックエンド側の役割を果たします。自社システムにサポート機能を埋め込みたいプロダクト向けに、マルチテナントサポート、API アクセス、Webhook を提供します。完全なリファレンスは API ドキュメント をご覧ください。

はじめる

ワークスペース設定 → API キー から API キーを取得し、お使いのスタックに対応するクライアントをインストールして、このページのクイックスタートを実行してください。その後、リポジトリをクローンして README をご覧ください。

supdesk.app で始める

バックエンド統合のためのサーバーサイドSDK

各SDKのGitHubリポジトリから取得したライブコード例。

RabinApps/supdesk-nodeJavaScript / TypeScript
import { SupDesk } from "supdesk";

const supdesk = new SupDesk({ apiKey: process.env.SUPDESK_API_KEY! });

// Auto-pages: iterating walks every page for you.
for await (const submission of await supdesk.submissions.list({
  status: "open",
})) {
  console.log(submission.title);
}

await supdesk.submissions.create({
  type: "bug",
  title: "Export button does nothing",
  email: "user@example.com",
  body: "Clicking Export on the reports page has no effect.",
});
RabinApps/supdesk-pythonPython
from supdesk import SupDesk

supdesk = SupDesk()  # api_key=... or $SUPDESK_API_KEY

# Auto-pages: iterating walks every page for you.
for submission in supdesk.submissions.list(status="open"):
    print(submission.title)

supdesk.submissions.create(
    type="bug",
    title="Export button does nothing",
    email="user@example.com",
    body="Clicking Export on the reports page has no effect.",
)
RabinApps/supdesk-goGo
import "github.com/rabinapps/supdesk-go/supdesk"

client, err := supdesk.New(os.Getenv("SUPDESK_API_KEY"))
if err != nil {
    log.Fatal(err)
}

page, err := client.Submissions.List(ctx, supdesk.SubmissionsListParams{
    Status: ptr("open"),
})
if err != nil {
    return err
}
// Auto-pages: All walks every page for you.
for sub, err := range page.All(ctx) {
    if err != nil {
        return err
    }
    fmt.Println(sub.Title)
}

_, err = client.Submissions.Create(ctx, supdesk.SubmissionsCreateParams{
    Type:  supdesk.SubmissionTypeBug,
    Title: "Export button does nothing",
    Email: "user@example.com",
    Body:  "Clicking Export on the reports page has no effect.",
})
RabinApps/supdesk-dartDart
import 'dart:io';
import 'package:supdesk/supdesk.dart';

final supdesk = SupDesk(apiKey: Platform.environment['SUPDESK_API_KEY']!);

// Auto-pages: the stream walks every page for you.
final page = await supdesk.submissions.list(status: PostStatus.open);
await for (final submission in page.autoPaging()) {
  print(submission.title);
}

await supdesk.submissions.create(
  type: SubmissionType.bug,
  title: 'Export button does nothing',
  email: 'user@example.com',
  body: 'Clicking Export on the reports page has no effect.',
);

タグ

#sdk#api#developers