こんにちは。メルカリモバイル フロントエンドエンジニアのtoshickです。
この記事は、Merpay & Mercoin Tech Openness Month 2025 の9日目の記事です。
この記事は以下の二部構成となっています。
- (その1)GAS(Google Apps Script)に助けられたMVNO開発の話
- (その2)Jiraのissue作成のためのGAS
(その1)GAS(Google Apps Script)に助けられたMVNO開発の話
わたくしtoshickは2025年今年リリースされたメルカリモバイルというプロジェクトのフロントエンド担当として開発をしています。
メルカリモバイルとはメルカリがMVNO事業者としてモバイル通信事業に参画したものです。
当然MNP(Mobile Number Portability)に対応しているため、お客さまが他のモバイル事業者から転入してきたり、逆にメルカリモバイルから他事業者へ転出されたりするようなケースにも対応しておく必要があります。
これらをポートイン(転入)、ポートアウト(転出)と呼びます。
他事業者との連携なのであらかじめやりとりのためAPIを決めておき、エンドユーザーが任意のタイミングでポートインやポートアウトを実行できるようにしておきます。
MNPワンストップ方式とMNPツーストップ方式
MNPの手続きの大まかな流れは以下です。
- お客さまは今自分が契約している通信事業者に対してMNP予約番号の発行を要請しこれを取得する。
- お客さまはその予約番号の有効期限内に乗り換え先となる通信事業者にて予約番号を入力して新規契約を行う。
このようにお客さまが自ら予約番号を取得して乗り換え先にもっていくMNPの方法をMNPツーストップ方式と呼びます。
一方で最近はその予約番号発行手続きをAPIから行うようにした、手順が簡略化されたフローが主流となっています。
これがMNPワンストップ方式と呼ばれる方法です。
お客さまからすると特にデメリットはないので、もし利用できる場合には多くのお客さまはこちらのMNPワンストップ方式で事業者変更の手続きを行っているはずです。
MNPワンストップ方式での動作テスト
メルカリモバイルもこのMNPワンストップ方式に対応している事業者となります。
ここで問題になるのがワンストップ方式時のテストになります。
ワンストップ方式はメルカリ内部だけで完結するものではないので、ワンストップ時のAPIの受け口となる本番と同様のふるまいをする別MVNO事業者のようなものが必要になります。
これを動作検証仮事業者と呼ぶことにします。(以降 仮事業者)
メルカリと仮事業者のAPIでのやりとりを模したテストのためのダミーの事業者としてふるまいます。
開発もかなりすすんできていた段階で、仮事業者も静的なページを用意すればなんとかなると考えていたのですがよく考えると問題がありました。
静的なWebページだとpostのリクエストを処理できないのです。
その事実に気づいた時にやっと「仮事業者はWebサーバ上で起動されたWebアプリケーションである必要がある」ということに気づきました。
動作検証仮事業者の開発
社内でカジュアルにWebアプリケーションを立ち上げて任意のjsを実行できるような環境をスピーディに用意する必要にかられていろいろ相談しましたが、今から新しくマイクロサービスを作成するのは時間的に不可能だということがわかりました。
素早く、新規マイクロサービス作成とかいう高コストでもなく、社内QAからアクセス可能で、postリクエストを処理可能な、社内向けのWebアプリケーションを作成する方法を見つける必要があります。
この問題をチームに相談したところ
「GASでできるかもしれない」
というアドバイスをもらいました。
自分はいままでほとんどGASに触ってこなかったのでそのアイデアは目からウロコです。
早速サンプルのGASを作成してpostのリクエストを送信したところちゃんとリクエストパラメータを取得して画面に出力することができました。
さらにjs実行によりform post(同期post)の実行もできることがわかったのです。
これなら仮事業者としてメルカリモバイルのAPIにむけて特定のパラメータ付きでpostリクエストをコールしたり、メルカリモバイル側からpostリクエストをうけとってから任意のタイミングでコールバックをコールしたりするような本番の外部MVNO事業者と同じふるまいをするアプリケーションが用意できます。
GASによる仮事業者の作成
本格的にGASでアプリケーションを作成してみたところいろいろ課題や混乱が発生しました。
まず最初はコード管理の問題でした。
通常の開発はGitを利用した差分管理およびGitHubへのpush、review、mergeといった手順をふむのが普通ですが、GASの場合はなんとブラウザ上でコードを修正し、ブラウザ上でデプロイを行うものでした。
これだとGit開発でうけている恩恵がうけられません。コードの差分のreveiewも不可能です。
claspの導入
みなさんがどうやってGASを開発しているのか調べたところ、claspというcliツールがgoogleから提供されていることがわかりました。
https://github.com/google/clasp?tab=readme-ov-file
claspはGAS開発のための便利なコマンドを提供しており、ローカルから自分のGASアプリへコードをpushすることが可能になります。
これでコードをGit上で管理しつつ、GASへの反映もブラウザ上のファイル編集ではなくローカルのファイルのpushにより可能になるのでより安全な開発になります。
GASの癖
GASのWebアプリケーション作成は少し違和感を覚えるかもしれません。
まず、ランタイム時の依存ファイルのインポートが不可能です。
通常のJavaScript(js)を利用したWebアプリケーションはimport文(もしくはrequire文)を利用して依存するファイルをロードするのが普通ですが、GASだとそれができません。
アプリのアクセス時のSSR処理時にコードをinjectするしか方法がないということです。
PHPのようなやり方ですね。
// これでjsの書かれたhtmlをinjectできる
<script>
<?!= includeFile('jsUtil') ?>
</script>
もし関数を定義してそれをコールしたい場合、それはグローバルに定義してあらかじめhtmlのヘッダで読み込んでおく必要があります。
次に、GAS上で取り扱うファイルは拡張子がhtmlである必要があります。
上記のコード includeFile(‘jsUtil’) は jsUtil.html をここに読み込んでくださいという命令になっています。
htmlとなっていはいますが、中身はjsです。
GASが「htmlしか動的に読み込ませない」というルールにしているためにこのようなヘンテコなことになっているようです。
- 開発側は定義した関数をjsとしてファイルに書き込み、デプロイ時はその拡張子をhtmlとしてpushする。
- さらに実行html内には includeFile関数をつかってヘッダからその関数をグローバルに読み込む。
といった工夫が必要になります。
別に直接実行htmlに関数を書いてもよいですが、複数htmlに同じ関数は書きたくないでしょう。
GASアプリからURLのクエリに含まれた値やpostでリクエストされた値を取得する場合built-inで用意された変数があるので、以下のような関数をhtmlに定義すればjs側でランタイム時に利用できるようになります。
<script>
<!-- postパラメータをinject -->
function getHtmlPostParams() {
return {
<? for (let key in postParams) { ?>
<?= key ?>: <?= postParams[key] ?>,
<? } ?>
};
}
</script>
<!-- クエリパラメータをinject -->
<script>
function getHtmlGetParams() {
return {
<? for (let key in getParams) { ?>
<?= key ?>: <?= getParams[key] ?>,
<? } ?>
};
}
</script>
これ以外にも新規デプロイするたびにURLが変わるけど、URLが変わらないデプロイ手順があったりと癖の多いツールですが理解さえしてしまえばなんとかなりました。
動作検証仮事業者の画面サンプル
仮事業者ポートアウト | 仮事業者ポートイン | 仮事業者ポートイン完了 |
---|---|---|
![]() |
![]() |
![]() |
ポートインとポートアウトという言葉はわかりやすいようでわかりづらいです。
なぜなら一方でのポートインは、同時に他方からするとポートアウトだからです。
ここは混乱しないように仮事業者のタイトルにはわかりやすく主語を明記しておきました。
結論その1
無事メルカリモバイルの動作チェックのための仮事業者のアプリケーションを立ち上げることができました。
仮とはいってもQAのためのアプリなので、メルカリモバイルの堅牢性確認のため様々なパターンのリクエストを発生させる機能も入っています。
このように、claspとGASを利用して手軽にpostリクエストを処理できるWebアプリケーションを社内に用意することができました。
post処理可能なWebアプリケーションを簡単に作成できるツールがこんなに身近にあるとは発想としてありませんでした。
みなさんもテストなどの際に社内におけるpostやgetを処理するための受け皿となるWebサービスが必要になるときが来るかもしれません。
そのとき、これほど簡単に自前サーバーも必要なく立ち上がってくれるこのツールを思い出すと役に立つかもしれません。
(その2)Jiraのissue作成のためのGAS
もうひとつGASで効率をあげた話をします。
メルカリは開発のサポートとしてAIを積極的に導入しています。
その一環でMCPサーバ経由からのJira issueの作成を試してみました。
MCPサーバとはAI経由でサードパーティのツール(Jiraやfigma等いろいろ)を操作するための仕組みです。
今まではAIに操作のやり方をおしえてもらって自分でツールを操作していたと思いますが、これを使うとAIが直接ツールを操作することができるようになります。つまり、Jiraのissue作成もやってもらえます。
CursorというAIツール上のプロンプトから日本語で、issue作成を依頼してみました。
XXXプロジェクトに以下のJira issueを作成してください
タイトル: MCP経由からのチケットさくせい
(AIからの回答)
Jiraチケットが正常に作成されました!
チケット番号: XXX-0000
タイプ: タスク
ステータス: To Do
URL: https://******
なんと簡単にissueが作成されてしまいました。
しかしこれだけではわたくしは満足せず、どうせならGoogleスプレッドシートに属性をすべて定義しておいてそれからissueを作成してほしいなと考えました。
// シートのイメージ
サマリー | issueのリンク | Epic | 担当 | ラベル | スプリント | ストーリーポイント
rowごとにissueの属性を定義し、isseの生成が完了するとリンクがシートに追加されるというものです。
前からJiraのissue作成後の手動属性追加は面倒だと考えていたため、属性をシートでまとめて管理できるのはよいアイデアだと考えました。
Jiraのissue管理は便利な反面、指定すべき項目が多いです。
手動で付与していると設定忘れが発生したりします。
- タイトル
- 説明
- 担当
- 複数ラベル(Frontendラベルおよびチームのラベル等)
- スプリントへの追加
- ストーリーポイントの追加
- 親Epicの追加
- リリースバージョンの追加
ローカルnodeアプリケーションからのJira issue作成
最初は対象のスプレッドシートを読み込んでJiraのAPIをコールするようなローカルのnodeアプリケーションを考えたので、Cursorに聞きながらnodeのexpressアプリケーションを作成しました。
expressである必要もなかったかもしれないですが、即座にコードが出力されて割と簡単にアプリを作成してJira issueが追加できるようになりました。
ほぼ想定どおりの動きをするアプリケーションができあがったあと、いちいちローカルのWebアプリを起動するのも面倒だなと考えてしまいました。
GASによるスプレッドシートからのJira issue作成
ということで、結局はこのローカルコードをクラウド上で実行すれば一番楽だということに気づいたのでCursorに依頼をしました。
このnodeアプリケーションをGASに持っていって、GAS上のボタンを押すとJiraのissueが追加されるようにしたいです
(AIからの回答)
GAS (Google Apps Script) への移行についてアドバイスさせていただきます。
現在のNode.jsアプリケーションをGASに移行するために、主な変更点と実装方法を説明します。
まず、コードベースを確認させていただきます。
...
現在のNode.jsアプリケーションをGAS(Google Apps Script)に移行するために、以下のような変更を提案します:
1. GASプロジェクトの作成
2. スプレッドシートとの連携
3. Jira APIとの連携
4. UIの実装(ボタンの追加)
...
素晴らしいです。ものすごくわかりやすく段階的な手順を明示してから具体的なコードを提示してもらえました。
これにより無事スプレッドシート上で動くGASアプリを使って簡単にJira issueを作成することができるようになりました。
いままでどちらかというとJiraのissue作成は面倒に感じていたのですが、せっかく自分でツールを作成したとなるとそうは言っていられません。
シートのタブごとに実行できるので文脈をかえてどんどんissueを作成していけます。
リリースバージョンごと、アサイニーごと、エピックごとというようにさまざまな文脈でシートを作成してissueを作成していけます。
もちろん属性のつけ忘れは存在しません。
ボタンを押した後にissue作成が成功するとIssueのカラムに自動的にリンクが付与されます。
すでにリンクが存在している行は無視されて作成からは除外されるようになっています。
ラベルも任意の数紐づけが可能です。
自分で作成したJira issueのヒストリーも見られるのがよいなと感じています。
結論その2
このように、GASを利用して効率をあげることができた事例を紹介しました。
他にも気づいていないだけでさまざまな業務を要所要所で自動化できるかもしれません。
ひらめいたアイデアをツールに落とし込むためのAIの存在も見逃せないところです。
いままでアイデアはあったけれどもどうやってツールにすればよいかわからなくてあきらめていたという人は、ぜひともAIに問いかけてアイデアを実現してみることをおすすめします。
以上でわたくしからの話は終わりです。
読んでいただきありがとうございました。
明日の記事は @anzaiさんの「Davin にE2Eテストの実装を任せる」と @somaさんの「メルペイインターンで機能の改修・設計からLLM AgentベースのSlack Bot開発まで色々やった話」です。引き続きお楽しみください。