ありそうでなかった会計向けSDK
freee が国内初なようで、2020/02時点の対応言語は「C#」「Java」「PHP」
freee API と統制をとるために「OpenApi generator」を利用して有志が開発しているとのこと
https://github.com/freee/freee-accounting-sdk-csharp/
https://github.com/freee/freee-accounting-sdk-java
https://github.com/freee/freee-accounting-sdk-php/
PHPの場合は、composer で用意されており、さらにサンプル用に Docker & Laravel が公開されている。
コールバックURL
freee APIアプリの「コールバックURL」は以下を設定しておく
※デフォルト:urn:ietf:wg:oauth:2.0:oob
※Laravel dでも後に設定する
http://localhost:8000/auth-callback
サンプルは SDK の中に入っているので git clone
$ git clone https://github.com/freee/freee-accounting-sdk-php.git
.env を設定する
$ cd freee-accounting-sdk-php.git
$ cd samples/BasicWebApp
$ cp .env.example .env
freeeアプリ の Client ID、Secret ID を記述
FREEE_ACCOUNTING_CLIENT_ID=Client ID
FREEE_ACCOUNTING_CLIENT_SECRET=Secret ID
freee-accounting-sdk-php にあるサンプルを利用する
$ cd freee-accounting-sdk-php/samples/BasicWebApp
$ cd samples
$ docker-compose build
$ docker-compose up -d
$ docker exec -it samples_webapp_1 /bin/bash
version: "3.7"
services:
console:
build:
context: .
dockerfile: Dockerfile
image: freee-accounting-sdk-php-console
volumes:
- "./BasicConsole:/usr/src/app"
command: /bin/sh -c "while sleep 1000; do :; done"
webapp:
build:
context: .
dockerfile: Dockerfile
image: freee-accounting-sdk-php-webapp
ports:
- "80:80"
- "8000:8000"
volumes:
- "./BasicWebApp:/usr/src/app"
command: /bin/sh -c "while sleep 1000; do :; done"
FROM php:7.3-cli
RUN apt-get update; \
curl -sL https://deb.nodesource.com/setup_12.x | bash -; \
apt-get install -y --no-install-recommends \
git \
libzip-dev \
nodejs \
unzip \
zlib1g-dev \
; \
rm -rf /var/lib/apt/lists/*
RUN docker-php-ext-install zip
WORKDIR /tmp
RUN curl https://raw.githubusercontent.com/composer/getcomposer.org/76a7060ccb93902cd7576b67264ad91c8a2700e2/web/installer -o - -s | php -- --quiet; \
mv composer.phar /usr/local/bin/composer
WORKDIR /usr/src/app
RUN composer global require laravel/installer
ENV PATH /root/.composer/vendor/bin:$PATH
EXPOSE 8000
webpackが用意されているので、すぐインストールできる
# composer install
composer、Laravel を直にインストールする場合
$ composer require freee/freee-accounting-sdk
$ composer require socialiteproviders/generators
$ composer require socialiteproviders/manager
artisan で socialiteproviders/generators を実行
$ php artisan make:socialite FreeeAccounting --spec=oauth2 --authorize_url=https://accounts.secure.freee.co.jp/public_api/authorize --access_token_url=https://accounts.secure.freee.co.jp/public_api/token --user_details_url=https://api.freee.co.jp/api/1/users/me
$ composer dumpautoload
Laravel/UI を作成
$ composer require laravel/ui --dev
$ php artisan ui vue --auth
$ npm install && npm run dev
# php artisan key:generate
# php artisan serve
Docker の場合は、ホスト指定します。
# php artisan serve --host 0.0.0.0
プロジェクトルートは「samples/BasicWebApp/」
Auth::routes([
'register' => false,
'reset' => false,
]);
Route::get('login', 'Auth\LoginController@redirectToProvider')->name('login');
Route::get('auth-callback', 'Auth\LoginController@handleProviderCallback')->name('authCallback');
「client_id」「client_secret」「redirect」をそれぞれ設定 (リダイレクトURLは、freeeのアプリ管理と合わせる)
'freeeaccounting' => [
'client_id' => env('FREEE_ACCOUNTING_CLIENT_ID'),
'client_secret' => env('FREEE_ACCOUNTING_CLIENT_SECRET'),
'redirect' => 'http://localhost:8000/auth-callback',
],
freee用ドライバー、プロバイダー設定
'defaults' => [
'guard' => 'freee',
'passwords' => 'users',
],
....
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
'freee' => [
'driver' => 'freee',
'provider' => 'freee',
],
],
...
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'freee' => [
'driver' => 'freee',
],
],
ログイン処理は、Laravel Socialite ドライバーを利用し、GenericUser で認証する
use App\Http\Controllers\Controller;
use Illuminate\Auth\GenericUser;
use Illuminate\Support\Facades\Auth;
use Socialite;
...
public function redirectToProvider()
{
return Socialite::driver('freeeaccounting')->redirect();
}
public function handleProviderCallback()
{
$user = Socialite::driver('freeeaccounting')->user();
$genericUser = $user->getRaw();
$genericUser['token'] = $user->token;
$genericUser['remember_token'] = '';
Auth::login(new GenericUser($genericUser));
return redirect()->intended($this->redirectTo);
}
public function logout()
{
Auth::logout();
return redirect()->intended('/');
}
namespace App\Providers;
use App\Extensions\SampleSessionGuard;
use App\Extensions\FreeeUserProvider;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
// 'App\Model' => 'App\Policies\ModelPolicy',
];
public function boot()
{
$this->registerPolicies();
Auth::extend('freee', function ($app, $name, array $config) {
return new SampleSessionGuard(
$name,
Auth::createUserProvider($config['provider']),
$app['session.store']
);
});
Auth::provider('freee', function ($app, array $config) {
return new FreeeUserProvider();
});
}
}
namespace App\Providers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use SocialiteProviders\Manager\SocialiteWasCalled;
use SocialiteProviders\FreeeAccounting\FreeeAccountingExtendSocialite;
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
SocialiteWasCalled::class => [
FreeeAccountingExtendSocialite::class,
],
];
public function boot()
{
parent::boot();
}
}
https://api.freee.co.jp/api/1/users/me からユーザを返す関数を作成
protected function getUserByToken($token)
{
$response = $this->getHttpClient()->get('https://api.freee.co.jp/api/1/users/me', [
'headers' => [
'Authorization' => 'Bearer '.$token,
],
]);
$body = json_decode($response->getBody(), true);
return $body['user'];
}
protected function mapUserToObject(array $user)
{
$user['name'] = $user['last_name'] . ' ' . $user['first_name'];
return (new User())->setRaw($user)->map([
'id' => $user['id'],
'name' => $user['name'],
'email' => $user['email'],
'display_name' => $user['display_name'],
'first_name' => $user['first_name'],
'last_name' => $user['last_name'],
'first_name_kana' => $user['first_name_kana'],
'last_name_kana' => $user['last_name_kana'],
]);
}
ログイン認証したユーザトークンを、Configuration クラスに設定
$user = Auth::user();
$config = Configuration::getDefaultConfiguration()->setAccessToken($user->token);
ちなみに、getAccessToken() でアクセストークンを確認できる。
$config->getAccessToken()
CompaniesApi で事業所IDを取得
$companiesApiInstance = new CompaniesApi(null, $config);
$companiesResponse = $companiesApiInstance->getCompanies();
$targetCompanyId = $companiesResponse->getCompanies()[0]->getId();
DealsApi で取引(収入/支出)一覧の取得
$limit = 5;
$dealsApiInstance = new DealsApi(null, $config);
$dealsResponse = $dealsApiInstance->getDeals(
$targetCompanyId,
null, null, null, null, null, null, null, null, null, null, null, null,
$limit);
$deals = $dealsResponse->getDeals();
getDeals() の引数がちょっとどうなんだろ?