Railsで郵便番号一覧を加工して返却する住所検索APIを作ってみる。

## 07. 郵便番号一覧を加工して返却する住所検索APIを作ってみる。

この記事の続きになります。

(01〜05はこちら)
[とりあえず住所検索APIサーバーをRailsで構築してみました。（住所の精度は無視しています。） - Qiita](https://qiita.com/sea_ship/items/e8fd1eea3e5a4ad51bfd)
(06はこちら)
[RailsでKEN_ALL.CSVファイルを取り込む時にバルクインサートを利用して処理時間を改善する。 - Qiita](https://qiita.com/sea_ship/items/216b3d464e11b7595aff)

これから作成するV2バージョンのAPIでは町域について置換処理で加工したデータを返却します。

## 郵便番号情報を返却するための簡単なサービスクラスを作成します。

置換についての仕様です。

- 郵便番号は全角->半角置換
- 郵便番号は半角数値以外は削除
- 町域名に以下の置換処理を追加します。こちらの記事を参考にしました。
  [郵便番号から住所を検索するサービスにまともなものがない - ぐるぐる～](http://bleis-tift.hatenablog.com/entry/20080531/1212217681)

  - "以下に掲載がない場合"を削除する。
  - "〜"からはじまる以降の文字列を削除する
  - "、"からはじまる以降の文字列を削除する
  - "（"からはじまる以降の文字列を削除する

町域名を加工するサービスクラス

```ruby:services/yubin_service.rb
class YubinService < BaseService
  attr_reader :zipcode,
              :yubins

  def initialize(zipcode)
    @zipcode = zipcode.to_s.tr('０-９', '0-9').sub(/[^0-9]/, '')
    @yubins = Yubin.where(zipcode: @zipcode).order('street_address ASC')
  end

  private
    def perform
      @yubins.each do |yubin|
        yubin.street_address.sub!(/～.+$|（.+$|、.+$|以下に記載がない場合|^[0-9０-９].+$/,'')
      end
      @yubins
    end
end

```

サービス基底クラス

```ruby:services/base_service.rb
class BaseService
  include ActiveModel::Model

  def provide
    raise_validation_error if invalid?
    perform
  end

  private

    def perform
      raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
    end

    def raise_validation_error()
      raise ActiveRecord::RecordInvalid.new(self)
    end
end

```

コントローラークラス

```ruby:api/v2/yubin_controller.rb
module Api
  module V2
    class YubinController < ApplicationController
      def search
        @yubins = YubinService.new(params[:id]).provide
        @message = "該当の郵便番号は見つかりませんでした。" if @yubins.blank?
        @status = @yubins.blank? ? 400 : 200
      end
    end
  end
end
```

## リクエストバージョンV1とV2の比較

```sh:v1リクエストで住所検索
$ http http://0.0.0.0:3000/api/v1/yubins/3994232
HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Content-Type: application/json; charset=utf-8
ETag: W/"28120c12e7f0a450c054bed0f65f937b"
Referrer-Policy: strict-origin-when-cross-origin
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Frame-Options: SAMEORIGIN
X-Permitted-Cross-Domain-Policies: none
X-Request-Id: 165f830b-116d-46fe-a135-c601e14ec9af
X-Runtime: 0.019229
X-XSS-Protection: 1; mode=block

{
    "count": 2,
    "message": "",
    "results": [
        {
            "locality": "駒ヶ根市",
            "region": "長野県",
            "street_address": "下平（２０７０～２１１９、２３０９～２３１１、２４１９、２４２１～２４２６",
            "zipcode": "3994232"
        },
        {
            "locality": "駒ヶ根市",
            "region": "長野県",
            "street_address": "、２４３３～２４５０）",
            "zipcode": "3994232"
        }
    ],
    "status": 200
}
```

```sh:V2リクエストで住所検索
$ http http://0.0.0.0:3000/api/v2/yubins/3994232
HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Content-Type: application/json; charset=utf-8
ETag: W/"b65937ad761ca2c99434f8ba51f6bd33"
Referrer-Policy: strict-origin-when-cross-origin
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Frame-Options: SAMEORIGIN
X-Permitted-Cross-Domain-Policies: none
X-Request-Id: 2f9fda59-f5e0-4c25-8a88-60d747118c3f
X-Runtime: 0.007724
X-XSS-Protection: 1; mode=block

{
    "count": 2,
    "message": "",
    "results": [
        {
            "locality": "駒ヶ根市",
            "region": "長野県",
            "street_address": "",
            "zipcode": "3994232"
        },
        {
            "locality": "駒ヶ根市",
            "region": "長野県",
            "street_address": "下平",
            "zipcode": "3994232"
        }
    ],
    "status": 200
}
```

`street_address`(町域)がスッキリですね。