郵便番号で住所情報を返却するAPIをNode.jsで簡単構築


## 概要
よくある郵便番号に対して住所情報を返却するAPIをNode.jsで構築しました。
①定期的に日本郵便のサイトから住所情報をダウンロードし、SQLiteに登録
②郵便番号を受け取り住所情報をSQLiteから取得し返却するAPIをNode.jsで構築

## 環境
・CentOS
・Node.js
・SQLite
※Vagrantにて仮想環境構築

## 事前準備
### npm
日本郵便のデータ読込(shift-jis)

```
npm install icov-lite
```

ダウンロードしたZIP解凍用

```
npm install unzip
```


Node.jsでsqlite操作するためにインストール(※)

```
npm install sqlite3
```
※手元の環境だとエラーになったため、Gitから直接インストールしました。

```
npm install https://github.com/mapbox/node-sqlite3/tarball/master
```

### SQLite
yumコマンドでSQLiteをインストール

```
yum -y sqlite
```

DBを作成

```
sqlite3 ZipInfo.db
```

住所情報を登録するためのテーブル作成

```
CREATE TABLE zipinfotbl (
  allLocalCode varchar(128)
  ,oldZipCode varchar(128)
  ,zipCode varchar(128)
  ,prefectureKana varchar(128)
  ,townKana varchar(128)
  ,localKana varchar(128)
  ,prefectureName varchar(128)
  ,townName varchar(128)
  ,localName varchar(128)
  ,IsMultiLocalOneZipCode varchar(1)
  ,IncludeSmallChar varchar(1)
  ,IncludeChome varchar(1)
  ,IsZipDuplication varchar(1)
  ,IsUpdate varchar(1)
  ,ChangeKbn varchar(1)
  );
```

## ソース

```JavaScript:WriteZipDB.js
var http = require('http');
var unzip = require('unzip');
var fs = require('fs');
var iconv = require('iconv-lite');
var readline = require('readline');
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('ZipInfo.db');

var ZIP_FILE  = "KEN_ALL.zip";
var CSV_FILE = "KEN_ALL.csv";


function downloadZIPCSV(){
    // 日本郵便の住所情報データURL
    var downloadUrl = 'http://www.post.japanpost.jp/zipcode/dl/kogaki/zip/ken_all.zip';

    // ダウンロードしZIPを解凍
    var outFile = fs.createWriteStream(ZIP_FILE);
    var rss = ''; 
    var req = http.get(downloadUrl, function (res) {
        
         res.pipe(outFile);
         res.on('end', function () {
            outFile.close();

            fs.createReadStream(ZIP_FILE).pipe(unzip.Extract({ path: './' }));
         }); 
    });
}

function writeDB(){
    // CSVファイルを１行ずつ読込
    var kenALLCSVFS = fs.createReadStream('KEN_ALL.CSV').pipe(iconv.decodeStream('shift_jis'));
    var kenALLCSVRL = readline.createInterface({'input': kenALLCSVFS, 'output': {}});
    kenALLCSVRL
    .on('line', function(line){
        //　読み込んだ行情報を配列化しDBに登録
        var csvdata = line.replace(/\"/g,"").split(",");
        insert(csvdata);
    })
}

var insert = function (param){
  db.serialize(function () {
 
    db.run('insert or replace into zipinfotbl'
     +' (allLocalCode,oldZipCode,zipCode,prefectureKana,townKana,localKana,prefectureName,townName,localName,IsMultiLocalOneZipCode,IncludeSmallChar,IncludeChome,IsZipDuplication,IsUpdate,ChangeKbn) '
     +' values ($allLocalCode,$oldZipCode,$zipCode,$prefectureKana,$townKana,$localKana,$prefectureName,$townName,$localName,$IsMultiLocalOneZipCode,$IncludeSmallChar,$IncludeChome,$IsZipDuplication,$IsUpdate,$ChangeKbn)', 
      {
        $allLocalCode : param[0],
        $oldZipCode : param[1],
        $zipCode : param[2],
        $prefectureKana : param[3],
        $townKana : param[4],
        $localKana : param[5],
        $prefectureName : param[6],
        $townName : param[7],
        $localName : param[8],
        $IsMultiLocalOneZipCode : param[9],
        $IncludeSmallChar : param[10],
        $IncludeChome : param[11],
        $IsZipDuplication : param[12],
        $IsUpdate : param[13],
        $ChangeKbn : param[14]
      }
    );
  });
};


// 日本郵便からZIPファイルをダウンロードしCSVとして解凍
downloadZIPCSV();
// SQLiteに書き込み
writeDB();

```


```JavaScript:GetZipInfoAPI.js
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('ZipInfo.db');
var http = require('http');
var url = require('url');
var port = "3000";

function GetZipInfoAPI(zipCode, callback){
    db.all("SELECT * FROM zipinfotbl where zipCode = ?",[zipCode], function(err, rows){
      if (!err) {
          callback(rows[0]);
      }else{
          callback(null);
      }
    }); 
}


http.createServer(function (req, res) {
    res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });

    var url_param = url.parse(req.url,true);
    var zipCode = url_param.query.zipCode;
    console.log(zipCode);
    if(zipCode == null || zipCode == undefined){
        res.write('RequiredParam : zipCode');
        res.end(); 
        return;
    }

    // 住所情報取得
    var zipinfodata = GetZipInfoAPI(zipCode, function(row){
        if(row == null){
            res.write('No Data...');
            res.end(); 
        }else{
            res.write('{ '
                + ' "adr1" : "' + row.prefectureName + '"'
                + ' "adr2" : "' + row.townName + '"'
                + ' "adr3" : "' + row.localName + '"'
                + ' "adrK1" : "' + row.prefectureKana + '"'
                + ' "adrK2" : "' + row.townKana + '"'
                + ' "adrK3" : "' + row.localKana + '"'
                + '}');
            res.end();
        }
    });

   

}).listen(port);
```


# 利用方法
## 住所情報を日本郵便からダウンロード

```
node WriteZipDB.js
```

ダウンロード〜DB登録まで約１０分ぐらい掛かります。
パフォーマンスもっと良い方法があるとは思いますが簡易版ということでご勘弁を…

定期実行の間隔としては一週間に一度実施する程度のcron設定で十分かと思います。


## API起動

```
node GetZipInfoAPI.js
```
サンプルソースではポート3000を利用してます。
アクセスしてみて住所情報が取得出来ればOK.
![スクリーンショット 2017-08-06 3.48.16.png](https://qiita-image-store.s3.amazonaws.com/0/48623/2af358aa-276d-0d1a-3a4c-04afed71d9c1.png)