
Figma REST APIを使ってアイコンの書き出しを自動化する
こんにちは。私は普段はUIデザイナーとしてデザイン業務を行っています。
社内には複数のプロダクトが存在し、それぞれプロジェクトチームがあり、
デザイナーもエンジニアもメンバーが異なります。
ただし、社内のプロダクトの為一定のデザイン基調は合わせる必要がありますが、スケジュールがタイトなこともあり、細かな違いが出ることは多いです。
具体的に言うと、プロダクト横断して共通のボタンが、プロダクトやプラットフォーム(iOS、Android、Web)などでデザインが(色、スペース…など)違ってしまっていたりします。
また、同じアイコンにもかかわらずプロダクト毎に書き出している為、書き出し形式が異なっていたり、後からアイコンを差し替える場合、「プロダクト×プラットフォーム」分の対応が必要となり、なかなか大変です。
そこでこのようなデザイントークンと呼ばれるようなものを、共通化できなかと思い、まずはアイコンライブラリを作成してみようと仕組みだけ調べてみました。
まだ調べ途中なところもあり、文末の参考リンクのほうがわかりやすいと思います。
ゴールのイメージ
イメージとしてはこちらです。

GitHub ActionsなどのCIから、Figmaのcomponentを取得
取得したcomponentをSVGファイルとして生成
差分があればPull Requestを出す
といった流れです。
Figma REST APIを使ってみる
それでは、FigmaのREST APIを使って画像を取り出してみたいと思います。
アクセストークンを取得
まずはアクセストークンを取得します。
「メニュー > Help and account > Account setting」 からPersonal access tokensから作成することができます。
作成したアクセストークンは1度しか表示されないのでコピーしておく必要があります。


APIを使ってみる
こちらを参考にAPIをリクエストしてみます。
まずはファイル情報をすべて取得してみます。
curl -H 'X-FIGMA-TOKEN: <personal access token>' 'https://api.figma.com/v1/files/:file_key'
リクエスト用のフォームが用意されているので、動きを確かめるにはこちらが手軽かもしれません。
先ほど作成した、アクセストークンとfile_keyを入力するとリクエスト用のcurlコマンドが作成されます。
file_keyはFigmaのファイルのリンク用のURLから取得します。
https://www.figma.com/design/{file_key}/{file名}?node-id=0-1

レスポンスの内容も画面内で見ることができます。

component一覧を取得してみる
以下で取得できます。
ただし、ライブラリをパブリッシュする必要があるので注意!
※ライブラリのパブリッシュは有料版のみ利用できます
https://api.figma.com/v1/files/{file_key}/components
レスポンスはこんな感じです。
{
"error": false,
"status": 200,
"meta": {
"components": [
{
"key": "315a....",
"file_key": "F2l...",
"node_id": "2:53",
"thumbnail_url": "https://s3-alpha.figma.com/checkpoints/...",
"name": "componentName",
"description": "",
"description_rt": "",
"created_at": "2024-06-28T06:58:03.228Z",
"updated_at": "2024-06-28T06:58:03.228Z",
"containing_frame": {
"pageId": "0:1",
"pageName": "Page 1"
},
"user": {
"id": "125...",
"handle": "userName",
"img_url": "https://s3-alpha.figma.com/profile/..."
}
},
...省略
]
},
"i18n": null
}
SVGファイルを取得する
以下で特定のnodeを画像として取得できます。
https://api.figma.com/v1/images/{file_key}?ids=${ids}
idsは、以下のようにnode_idを「, 」で区切った文字列として設定します。
https://api.figma.com/v1/images/{file_key}?ids=1:2,1:3,1:4
公式のドキュメントを見るとパラメータがわかりやすいです。

他にも色々あります。

取得したSVGをファイルとしてダウンロードする
取得したSVG画像をファイルとしてダウンロードできるようにします。
現状のファイル構成としてはこんな感じ。
.
├── figma.js
├── node_modules
├── package-lock.json
└── package.json
準備
最終的にはCIで実行できるようにしたいので、コマンドを準備します。
package.jsonに実行用のscriptを追加。
"scripts": {
"build:assets": "node ./figma.js"
},
npm modulesを読み込む際にimportを利用したいので、package.jsonに"type": "module",を追加。
{
"name": "figma",
"version": "1.0.0",
"description": "",
"main": "figma.js",
"type": "module", // 追加
メインコード
実行するコードはこんな感じです。
◎figma.js
import fetch from "node-fetch";
import path from "path";
import { fileURLToPath } from "url";
import fs from "fs";
import * as dotenv from "dotenv";
dotenv.config();
const FIGMA_FILE_KEY = process.env.FIGMA_FILE_KEY;
const FIGMA_TOKEN = process.env.FIGMA_TOKEN;
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const download = async (url, path) => {
const res = await fetch(url);
const data = await res.text();
fs.writeFileSync(path, data);
};
const getComponents = async () => {
try {
const res = await fetch(
`https://api.figma.com/v1/files/${FIGMA_FILE_KEY}/components`,
{
headers: {
"X-FIGMA-TOKEN": FIGMA_TOKEN,
},
responseType: "json",
}
);
const body = await res.json();
return body.meta.components;
} catch (error) {
throw error;
}
};
const getSvgImages = async (ids) => {
const res = await fetch(
`https://api.figma.com/v1/images/${FIGMA_FILE_KEY}?ids=${ids}&format=svg`,
{
headers: {
"X-FIGMA-TOKEN": FIGMA_TOKEN,
},
responseType: "json",
}
);
const images = await res.json();
return images;
};
async function main() {
// ディレクトリを削除して初期化
await fs.promises.rm(`${__dirname}/assets`, { recursive: true, force: true });
// ディレクトリを作成
await fs.promises.mkdir(`${__dirname}/assets`, { recursive: true });
// コンポーネントを取得
const components = await getComponents();
// 画像を取得
const ids = components.map((r) => r.node_id).join(",");
const { images } = await getSvgImages(ids);
// 画像をダウンロード
const nodeIds = Object.keys(images);
nodeIds.forEach(async (nodeId) => {
const url = images[nodeId];
const component = components.find((r) => r.node_id === nodeId);
const name = component.name;
const filePath = `${__dirname}/assets/${name}.svg`;
await download(url, filePath);
});
}
main();
◎Figma
以下のようにアイコンをcomponent化の上、ライブラリをパブリッシュします。

実行する
figma.js直下で、npm run build:assets実行すると、実行環境直下にassetsディレクトリが作成されて、Figma内のcomponentがSVGファイルとしてダウンロードされます。
.
├── assets // ← 作成される
│ ├── Ellipse.svg
│ ├── Rectangle.svg
│ └── Star.svg
├── figma.js
├── node_modules
├── package-lock.json
└── package.json
GitHub actionsでPRを作成する
FigmaのREST API経由で生成したSVGファイルを、CIで自動化したいと思います。
※参考にしたサイトは文末に記載していますが、そちらを見たほうがわかりやすいかもしれません。
GitHub actionsからworkflowを作成する
GitHub actionsは.github/workflows/ 配下にyamlファイルを作成します。
GitHub上で作成するには「Actions」タブから行います。

実行するコードはこちら。
name: Update Icon
on: [workflow_dispatch]
jobs:
update-icon:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: "20.x"
- name: Install
run: npm ci
- name: Update Icon
run: FIGMA_TOKEN=${{ secrets.FIGMA_TOKEN }} FIGMA_FILE_KEY=${{ secrets.FIGMA_FILE_KEY }} npm run build:asset
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
commit-message: "feat: update icons"
committer: GitHub <noreply@github.com>
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
branch: feat/update-icons
branch-suffix: timestamp
delete-branch: true
title: "feat: update icons"
body: Icons has been updated
何をしているか簡単に説明すると、
ヘッドブランチをチェックアウト
Figma APIでSVGファイルを生成
Pull Requestを作成する
GitHubシークレットを利用してトークンを管理
表に出せないトークン情報などは、Actions secrets and variablesを利用します。
Settings > Secreats and variables >Actions から登録できます。

登録した変数は以下のように利用します。
${{ secrets.FIGMA_TOKEN }}
workflowを実行
登録したworkflowを実行します。 実行のトリガーをon: [workflow_dispatch] としているので、取り合えすgithub上から実行します。
Actionsの「Run workflow」を押します。

処理が実行されて、問題なければ緑のチェックマークがつき、Pull Requestが作成されます。

まとめ
とりあえずSVGファイルをCI上で生成してプルリクエスト出すところまで来ました。
残りの課題は以下になります。こちらも追々検討したいと思います。
SVGのままだと使えないので各プラットフォームで利用できるように変換すること
プロダクトからどのように取得するか
参考
大変参考になりました。