はじめに
この記事はfreee APIで業務を楽しく便利にハックしよう!アドベントカレンダー2021の3日目の記事として投稿しています。
本記事では、freeeアプリを作成するハードルを劇的に下げる**「freeeアプリスターターパック」という自作のひな形アプリ・ツールセット**を紹介します。このパックを使うと、5分で0からfreeeアプリをデプロイしてAPIを叩けるところまで実装できます。
デフォルトで作成できるアプリはこんな感じです。freeeとの認証・認可を通して、ウェブアプリでfreeeAPIを叩くとこまで出来ているのがわかると思います。
freeeアプリでHello Worldするのが大変な2つの理由
freeeではAPIを使ったデータ連携するアプリを作成し、アプリストアで公開することができます。そのfreeeアプリ開発でまず試しにと、Hello World的な最低限のアプリを作ろうとすると、大きな2つのハードルがあります。
- freeeとのOpenID Connect連携の実装が必須。アクセストークン・リフレッシュトークン等の使い方を理解し、コードにする必要があります。
- どんな小さなアプリでも、インターネット上に公開した形で動かす必要あり。ローカルサーバーでは基本不可。アプリはfreeeのインフラ上で動くわけではありません。
この2つのハードルが高く、スクラッチで開発する方は取り掛かりづらいかもしれません。freeeアプリストアを見ると、既存サービスとの連携アプリか、Google SpreadSheetをハックしたローコード開発アプリがほとんどで、スクラッチでアプリを作っているものはごく少数のようです。
freeeのデータってパワフル
そんな難しいアプリ開発ですが、その一方で**freeeのデータってすごくパワフルで面白いんです!**例えば会計APIのドキュメントを見ると、仕訳帳や勘定科目のレベルでデータ操作ができ、ニッチサービスを作るにはパワフルすぎるくらいのAPIになってます。
こんなにいいデータを既存サービス連携だけに使うのはもったいないと思います。
じゃあひな形作ってみよう
そんなモチベーションから、freeeアプリを動かすまでの最低限の実装・デプロイツールをひな形化した「freeeアプリスターターパック」を作って公開しました。GitHubリンクはこちらとなります。
このパックを使うと、**約5分でアプリをデプロイし、freeeのプラットフォームと連携して、APIアクセスができる状態で公開することができます。**スターターパックという名前の通り、実装したい機能を簡単に追加できるようにしているので、このパックを元に本番アプリの作成・公開も可能です。
スターターパックの概要
スターターパックでは、freeeアプリをGoogle Cloud上にデプロイします。クラウドを使用するものの、無料枠で十分動くので料金は気にしなくて大丈夫です。以下のウェブアプリとデータベースの2つのサービスがGoogle Cloud上で動くことになります。
- ウェブアプリ:Google Cloud Functionで動き、インターネット上でアクセス可能です。Cloud FunctionはFaaS(Function as a Service)の一つです。ウェブアプリはPythonで書かれてます。
- データベース:FirestoreというGoogle CloudのNoSQLデータベースを使用しています。
スターターパックで作れるもの
スターターパックをデプロイしたアプリのデフォルトの動作は、最初のGIF動画の通りとなります。
流れとして、ユーザーはアプリにアクセスすると、まずfreeeにリダイレクトされ、ログイン・認可を要求されます。認可すると、アプリのメインページに戻り、アクセストークンの値とAPIへのコール結果を画面に表示します。アプリで使用するアクセストークンとリフレッシュトークン、セッションクッキーはデータベースに保持してあります。
スターターパックの中身
中身は4つのファイルのみです。
- main.py: メインのウェブアプリです。認可後はアクセストークンを使用してfreeeAPIからデータを取得できます。
- requirements.txt: 必要なPythonライブラリのリストです。ライブラリのインストールはCloud Functionが自動で行ってくれます。
- deploy.sh: Google Cloudへのデプロイ作業がすべて一つのコードになってます。このスクリプトを実行するだけでデプロイが完了します。
- env.yaml: freeeと連携するために必要な設定を保持します。
実際に5分間でfreeeアプリをデプロイしてみる
事前準備
- Google Cloudのアカウントとfreeeの開発者アカウントを用意(既にお持ちの方はスキップ)
- Google Cloud CLIをインストール(こちらのドキュメントを参照にして下さい)
- GitHubからスターターパックのコードをダウンロード
5分でデプロイの概要
- Google Cloudで新しいプロジェクトを作成し、Firestoreを新規作成【約30秒】
- 1で作成したプロジェクトIDをdeploy.shにコピー【約10秒】
- freeeの開発画面でアプリを新規作成し、IDやURLを
env.yaml
にコピー【約30秒】 -
./deploy.sh
でCloud Functionにコードをデプロイ【約1分半】 - Cloud FunctionのトリガーURLを
env.yaml
にコピーし、さらにURL末尾に?page=redirect
を加えた文字列を、freeeのアプリ画面の「コールバックURL」にコピー【約30秒】 - Cloud FunctionのトリガーURLを
env.yaml
にコピーし、再度./deploy.sh
でコードをデプロイ【約1分半】
という流れで、約5分でfreeeアプリを作成・デプロイすることができます。デプロイ後にCloud Functionにアクセスすると、freeeのログイン・認可画面が出るので、認可するとアプリのメインページにリダイレクトされます。そのメインページで、アクセストークンとAPI呼び出しの結果が表示されているのを確認できると思います。
5分でデプロイの詳細
各ステップの詳細をスクリーンショットで紹介します。
1.Google Cloudで新しいプロジェクトを作成し、Firestoreを新規作成
2. 1で作成したプロジェクトIDをdeploy.shにコピー
3. freeeの開発画面でアプリを新規作成し、IDやURLを設定ファイルenv.yaml
にコピー
4. ./deploy.sh
でCloud Functionにコードをデプロイ
5. Cloud FunctionのトリガーURLをenv.yaml
にコピーし、さらにURL末尾に?page=redirect
を加えた文字列を、freeeのアプリ画面の「コールバックURL」にコピー
このように、たった5分間で0からfreeeのアプリを公開し、連携してAPIからデータを取得するところまで実行できました。スターターパックで作れるもののセクションでデモしたように、URLにアクセスしてみてください。
スターターパックの詳細な実装について
アプリとfreeeの連携データフロー
アプリに連携するには、freeeのログイン・認可フローが必要となります。freeeのドキュメントにも解説がありますが、本パックでのアプリでの処理内容もいれると以下の図のような流れになります。
Firestoreではセッションクッキーやアクセストークン・リフレッシュトークンの管理を行います。リフレッシュトークンを保持することで、アクセストークンの期限が切れたら再度取得することができます。(もちろんユーザーがアプリへの連携を切ると取得できません。)
コード紹介
Google Cloudへデプロイするコードはこんな形です。コメントの通りの処理を行います。
#!/bin/bash
# デプロイ先のプロジェクトをセットします
gcloud config set project <your-project-id>
# Cloud Functionをデプロイ
gcloud functions deploy freee-main\
--source main\
--env-vars-file env.yaml\
--entry-point mainpage\
--memory 128mb \
--runtime python38 --region asia-northeast1 --trigger-http --allow-unauthenticated
アプリのコードの中でキーとなる処理を以下に抜粋します。
- Cloud Functionは一つのエンドポイントURLしかもちません。なので、freeeからのOIDCリダイレクトとアプリのメイン画面、というように2つ以上のアクセスURLが欲しい今回のケースでは、GETパラメーターで処理をスイッチさせています。
- freeeから認可のリダイレクトが来た際には、トークンをDBに保存したあと、紐付けるためのクッキーをユーザーにセットさせてメインページに戻します。
- メインページでは、セッションクッキーを用いてアクセストークンをDBから取り出し、APIコールを行ってます。
# Cloud Functionから最初に呼ばれる関数
def mainpage(request):
# GETパラメーターのpageによって、処理を変える
nav_page = request.args.get('page', default='main')
# page=mainもしくはパラメーターなしの場合はこちら
if nav_page == "main":
...
access_token = validate_cookie_and_get_access_token(request.cookies[cookie_name])
...
simplest_api_response = test_api_call(access_token)
# page=redirectの場合はこちら。freeeからのOIDCリダイレクト用
elif nav_page == "redirect":
...
response = make_response(redirect(mainpage_url))
response.set_cookie(cookie_name, value=cookie, expires=expire_date)
return response
クッキーやセッションは、以下のような関数でFirestoreに簡単に保存できます。
# クッキーやトークンをFireStoreに保存する関数
def store_cookie_in_Firestore(cookie_value, access_token, access_token_expires_at_unixtime, refresh_token, scope):
try:
db = get_firestore_instance()
data = {
u'access_token': access_token,
u'access_token_expires_at_unixtime': access_token_expires_at_unixtime,
u'refresh_token': refresh_token,
u'scope' : scope
}
db.collection(Firestore_session_collection_name).document(cookie_value).set(data)
本番運用のために必要なこと
スターターパックでは、簡便にするため何点か本番運用に適さない部分があります。どれも簡単に変えられるポイントなので、以下を直して下さい。
- すべての設定値をenv.yamlに保持していますが、よりセキュアにするため、freeeのクライアントシークレットは環境変数でなく、Google Secret Managerを用いて管理してください。
- 開発する内容によっては、Firestoreにユーザーデータを保持するかと思います。その場合、必ずFirestoreのアクセス権限ルールを設定してください。最低限、ユーザーごとのCollection階層を作り、そのユーザーしかアクセスできない、というユーザー分離のルールを設定しましょう。Firestoreルールについては、こちらの記事がわかりやすいと思います。
おわりに
freeeアプリのひな形を作ってみた、という記事でした。freeeのAPI連携はなかなか素直で、一旦連携してしまえばかなり管理は楽ですね。今回のスターターパックはPython+Google Cloudでしたが、AWSやAzure連携、他言語でのアプリ実装など大歓迎ですので、ぜひプルリクお待ちしています!