Laravelで郵便番号検索APIを作るの開設編の話

前回、ちょっとだけ早足でしたので今回はもう少しゆっくり解説を書こうと思います

初めに、DB関係ですが、今回はsqliteを使いました。正直パフォーマンスとか考えましたが、それほどネックにはなりませんでした。

初めに、必要な情報からテーブルを考えました。
ま、migrateさせるます

database/migrations/2020_12_14_132447_create_zip_table.php

ポイントとしては、日付部分をちゃんと指定します。初めに短縮のcreateとしたら… NGでした

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateZipTable extends Migration
{
    public function up()
    {
        Schema::create('zip', function (Blueprint $table) {
            $table->string('pref_code');
            $table->string('zip');
            $table->string('zip_first');
            $table->string('pref_name');
            $table->string('city_name');
            $table->string('town_name');
        });
    }

    public function down()
    {
        Schema::dropIfExists('zip');
    }
}

はい、zipテーブルにpref_code,zip,zip_first,pref_name,city_name,town_nameを文字列で指定しています。

次に、seedでcsvファイルを読み取るseedを作成しました。
csvファイルは、database/seeds/csv/KEN_ALL.CSVに置いているのを読み取ります。このファイルは郵政省から提供されているファイルを使いました。
※ SHIFT_JIS からUTF-8変換を忘れずに

掘り込むSEEDは以下です

database/seeders/DatabaseSeeder.php

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        $file = new \SplFileObject(database_path('seeds/csv/KEN_ALL.CSV'));
        $file->setFlags(
            \SplFileObject::READ_CSV |
            \SplFileObject::READ_AHEAD |
            \SplFileObject::SKIP_EMPTY |
            \SplFileObject::DROP_NEW_LINE
        );

        foreach ($file as $i => $line) {
            DB::table('zip')->insert([
                'pref_code' => $line[0],
                'zip' => $line[2],
                'zip_first' => $line[1],
                'pref_name' => $line[6],
                'city_name' => $line[7],
                'town_name' => $line[8],
            ]);

        }
    }
}

はい、CSVファイルを読み込んで、zipテーブルにinsertしています。

次はロジック系です

Zip検索は… Repositoryにするべきだったかw

web.phpは実際はapiです。
apiのソースはこんなの

Route::get('v1/zip', 'App\Http\Controllers\ZipController@index');

次に参照しているZipController.php

<?php
namespace App\Http\Controllers;

use App\Classes\Models\ZipRequest;
use App\Classes\Models\ZipResponse;
use App\Classes\Services\ZipService;
use Illuminate\Http\Request;
use function PHPUnit\Framework\isEmpty;

class ZipController extends Controller
{
    private $service;
    public function __construct(ZipService $service){
        $this->service = $service;
    }
    public function index(Request $current_request){
        $request = $this->getZipRequest($current_request);

        $response = new ZipResponse();
        $response->request = $request;

        $response->data = $this->service->search($request);
        return response()->json($response);
    }

    private function getZipRequest(Request $current_request)
    {
        $zipRequest = new ZipRequest();
        $zipRequest->zip = $current_request->input('zip');
        if(isEmpty($zipRequest->zip)){
            $zipRequest->zip = $current_request->input('zip_first');
            $zipRequest->zip .= $current_request->input('zip_last');
        }
        return $zipRequest;
    }
}

isEmptyなんて使っているw

基本的な動きはindexだけ、Httpリクエストから。Service用のリクエストを変換しているのがgetZipRequestで変換します
んで、サービスのsearchにそのリクエストを投げて、返ったデータをdataへ、jsonへリクエスト内容を入れて返しています。

次に実際のサービスです

<?php
namespace App\Classes\Services;

use App\Classes\Models\ZipRequest;
use App\Models\Zip;
use Illuminate\Support\Facades\Log;

class ZipService
{
    /**
     * 郵便番号検索サービス
     * @param ZipRequest $request
     * @return \App\Classes\Models\Zip
     */
    public function search(ZipRequest $request){

        $db_zip = Zip::select()->where('zip','=',$request->zip)->first();

        $zip = new \App\Classes\Models\Zip();
        $zip->pref_code = $db_zip->pref_code;
        $zip->zip = $db_zip->zip;
        $zip->zip_first = $db_zip->zip_first;
        $zip->pref_name = $db_zip->pref_name;
        $zip->city_name = $db_zip->city_name;
        $zip->town_name = $db_zip->town_name;
        return $zip;
    }
}

はい、selectして、結果を入れています…

全体としてはこんな感じですね

これで、郵便番号の検索ができますw