3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【驚愕】なんかできちゃった『Chrome拡張機能』!2年目エンジニアが拡張機能開発でスキル伸びた気がする話

Last updated at Posted at 2025-07-09

はじめに

こんにちは、コード苦手な2年目エンジニアです

最近、ふとしたきっかけで「Chrome拡張機能」の世界に足を踏み入れました。今回は、そんな私が作ってみたURL短縮ツール拡張機能のお話と、その中で見つけた(ような気がする)学習したことを書き留めていきます。

本記事は駆け出しエンジニアにはおすすめかもしれません。

作成手順

1.見慣れないmanifest.jsonとの出会い

「まずは何から...。」とググってみると、最初に出てくるのが manifest.json というファイル。JSON形式のただのファイルかと思いきや、これが拡張機能の核みたいなもので、バージョンから権限、ポップアップの設定まで全部ここに書く必要がある。

{
  "manifest_version": 3, // 見慣れない数字に戸惑う。とりま最新
  "name": "しょーたくん",
  "version": "1.0",
  "host_permissions": [
    "https://*.amazonaws.com/*" // これ書いてなくて外部API叩けなかった!
  ],
  "permissions": [
    "activeTab", // 今開いてるタブのURL欲しい!
    "storage",   // データ保存したい!
    "clipboardWrite" // コピーしたい!
  ],
  "action": {
    "default_popup": "popup.html" // ポップアップはHTMLで書くのね
  },
  // ...あとはアイコンとか
}

「何これ」と「これで合ってるのか…?」と思いました。特に host_permissions は重要で、これを書き忘れると後で CORS エラーの沼にハマることになります(ハマりました)。

2.ポップアップは意外と普通なWeb開発

popup.htmlpopup.js を書いていくフェーズに入ると、急に苦手な世界が広がりました。DOM操作、Fetch API、JavaScript…。普段Webフロントエンドを触る方なら、ここが一番すんなり進む部分だと思います。

// popup.js (一部抜粋)
document.addEventListener('DOMContentLoaded', async () => {
    // 現在のタブのURLを取得
    const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
    const currentTabUrl = tabs[0].url;
    document.getElementById('currentUrl').textContent = currentTabUrl;

    // ローカルのuserNameを取得し、入力フィールドに設定
    chrome.storage.local.get(['userName'], function(result) {
        if (result.userName) {
            userNameInput.value = result.userName;
        }
    });
    
    // API Gatewayへのリクエスト
    const apiUrl = 'https://your-api-gateway-url/dev/'; // ここにデプロイしたAPI GatewayのURLを設定
    const requestBody = {
        "URLs": [{"urlstring": currentTabUrl}],
        "userName": "hoge@example.com" // ローカルストレージから取得したユーザー名
    };

    const res = await fetch(apiUrl, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json; charset=UTF-8',
            // APIキーはここで直接書かずに、API Gatewayで隠蔽する設計!
        },
        body: JSON.stringify(requestBody)
    });
    const data = await res.json();
    // 短縮URLを画面に表示&コピーボタンでコピー!
});

ほんとはエラー処理とかも書かないといけないんですけどね・・・。やってない!

3.API GatewayとCORSとの戦い

開発段階ではAPIキーを直接コードに埋め込んでいたのですが、今回はAWSの「API Gateway」を経由してバックエンドリクエストを送る形式で隠蔽しました!
その際に私の前に立ちはだかったのがCORSエラー403 Forbiddenエラーの野郎でした。

CORSエラー (No 'Access-Control-Allow-Origin' header is present):
ブラウザが「あんたの拡張機能、このAPIにはアクセスしちゃダメだよ!」とブロックしてくるやつです。
解決策: API Gatewayのリソースに対してCORSを有効化し、OPTIONS メソッドも許可する。そして、変更したら必ずAPIをデプロイする!

403 Forbiddenエラー (the server responded with a status of 403):
CORSを乗り越えたと思ったら、今度はAPI Gatewayから「Forbidden!」と門前払い。これはサーバー側からの拒否です。

解決策:
私のケースでは、クライアントからAPI Gatewayへのリクエストを間違えていたこと&API Gatewayがバックエンドに転送するAPIキーが間違っていたことが原因でした。そもそもクライアントからAPI Gatewayへ正しいリクエストが送れていなかったことに加えて、API Gatewayがバックエンドに送る認証情報が不正だったため、バックエンドAPIが403を返していたのです。

統合リクエストでのAPIキー転送の再確認:

  • API Gatewayコンソールで、あなたのAPIを開く
  • ルートリソース (/) の下の POST メソッドを選択
  • 「統合リクエスト (Integration Request)」をクリック
  • 「HTTP ヘッダー」セクションを展開
    ここで、APIキーの「マッピング元」が、単一引用符で囲まれた正しいリテラル文字列として設定されているかを一文字一句確認してください。

例: api-key の「マッピング元」が 'hogehogefugafuga' となっているか。

間違いやすいポイントとして、引用符を付け忘れるとAPI Gatewayは変数を参照しようとしてしまい、正しい値が渡されません。

4.最後の一歩!

ファイルが用意できたら、いよいよChromeに追加します!

  • Chromeのメニュー(右上の縦3点リーダー)>「拡張機能」>「拡張機能を管理」をクリック!
  • 拡張機能管理ページの右上に「デベロッパーモード」というトグルスイッチがあります。これをオン!
  • 左上に「パッケージされていない拡張機能を読み込む」というボタンが表示されます。これをクリック!
  • あとはフォルダを選択するのみ!

最後に

紆余曲折ありましたが、なんとか拡張機能は完成しました!
ちなみにこんな感じ(社内のAPIだからメアド入力させてます)

こんな小さな開発でも学ぶものは多かったです。

  • APIの叩き方
  • Chromeのローカルストレージの存在
  • API Gatewayの使い方
  • Qiita初投稿
    駆け出しエンジニアにとっては開発力を高める上でも拡張機能の開発はおすすめできる品物でした。

この記事が、これからChrome拡張機能開発に挑戦する方や、普段の業務でちょっと息抜きしたいエンジニアの皆さんの参考になれば幸いです。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?