Docs · spec v1.0 · 8 言語対応

SDK で郵便番号を
3 行で検索

登録不要、API キー不要。お好みの言語の SDK をインストールするだけで、関数 1 つで郵便番号データが取り出せます。

サポート言語 · TypeScript / Go / Python / Rust / Ruby / Dart / PHP / Swift の 8 言語で SDK を 提供しています。全 SDK の API シグネチャは spec v1.0 に揃えています。

はじめに

jpzip は静的 JSON ファイル群を https://jpzip.nadai.dev から配信するデータセットです。各言語の SDK は このデータを取得し、メモリ / 永続キャッシュを管理し、オフラインでも動かすための薄いラッパーを提供します。

インストール

# JavaScript / TypeScript (Node / browser / Bun / Deno)
npm i @jpzip/jpzip

# Go (1.21+)
go get github.com/jpzip/go

# Python (3.10+)
pip install jpzip

# Rust (1.75+)
cargo add jpzip

# Ruby (3.2+)
gem install jpzip

# Dart (3.0+) / Flutter
dart pub add jpzip

# PHP (8.2+)
composer require jpzip/jpzip

# Swift (5.9+) — SwiftPM Package.swift
.package(url: "https://github.com/jpzip/swift", from: "0.1.0")

60 秒クイックスタート

最小の使用例 — シングルトンが自動で初期化されるので、いきなり呼べます。下の SDK セクションで言語タブを切り替えてください。

SDK

言語タブで切り替えてください。URL の hash (例: #go-client) で直接該当言語にも飛べます。

import { lookup } from "@jpzip/jpzip";

const e = await lookup("2310017");
if (e) console.log(e.prefecture, e.city, e.towns[0].town);
// 神奈川県 横浜市中区 本町

npm パッケージ名 @jpzip/jpzip。ESM / CJS 両対応、完全型付き、Node 18+ / 主要ブラウザ / Bun / Deno / Cloudflare Workers で動作します。

関数 API (シングルトン)

1 つの app に 1 つのクライアントで足りる場合は関数 API が最も簡潔です。内部で遅延初期化された JpzipClient を共有し、L1 メモリキャッシュが効きます。

import {
  lookup,        // (zip: string) => Promise<ZipcodeEntry | null>
  lookupGroup,   // (prefix: 1-3桁) => Promise<ZipcodeDict>
  lookupAll,     // () => Promise<ZipcodeDict> (内部で /g/0..9 並列)
  preload,       // ({ scope: 'all' | '0' | '23' | '231' }) => Promise<void>
  getMeta,       // () => Promise<Meta | null>
  isValidZipcode,// (zip: string) => boolean ← fetch しない簡易検証
  configure,     // シングルトンに options を渡し直す
} from "@jpzip/jpzip";

// 単発検索 — /p/231.json を 1 回 fetch → L1 にキャッシュ
const e = await lookup("2310017");

// グループ — 3桁=1 file / 2桁=10 並列 / 1桁=/g/{n}.json
const dict = await lookupGroup("23");

// 全件 preload — /g/0..9 を並列 fetch して L1 を温める
await preload({ scope: "all" });
// 以降の lookup() / lookupGroup() はネットワーク不要

JpzipClient (明示的なインスタンス)

テスト、マルチ環境、独立した永続キャッシュなどが必要な場合は new JpzipClient() を直接作ります。

import { JpzipClient } from "@jpzip/jpzip";

const client = new JpzipClient({
  // すべてのオプションは省略可
  baseUrl: "https://jpzip.nadai.dev",  // デフォルト
  memoryCacheSize: 100,               // L1 LRU の prefix 数
  cache: undefined,                  // L2 (後述)
  fetch: globalThis.fetch,           // テストで差し替え可
  onSpecMismatch: ({ expected, received }) =>
    console.warn(`spec mismatch: ${received}`),
});

const e = await client.lookup("1500001");
await client.refresh();  // L1/L2 を破棄して meta を再取得

永続キャッシュ (L2)

cache オプションに PersistentCache インタフェースを満たすオブジェクトを渡すと、 起動をまたいでデータが保持されます。標準実装は意図的に同梱していません — 環境に合わせて選んでください。

interface PersistentCache {
  get(key: string): Promise<Uint8Array | null>;
  set(key: string, value: Uint8Array, ttl?: number): Promise<void>;
  delete(key: string): Promise<void>;
  clear(): Promise<void>;
}

ブラウザでは IndexedDB、Node ではファイル、Cloudflare では KV / Cache API、Redis なども差し込めます。

// 例: Node.js のシンプルなファイルキャッシュ
import { readFile, writeFile, unlink, rm } from "node:fs/promises";
import { createHash } from "node:crypto";
import { JpzipClient, PersistentCache } from "@jpzip/jpzip";

const dir = "./.jpzip-cache";
const path = (k: string) =>
  `${dir}/${createHash("sha1").update(k).digest("hex")}.bin`;

const cache: PersistentCache = {
  async get(k) { try { return await readFile(path(k)); } catch { return null; } },
  async set(k, v) { await writeFile(path(k), v); },
  async delete(k) { await unlink(path(k)).catch(() => {}); },
  async clear() { await rm(dir, { recursive: true, force: true }); },
};

const client = new JpzipClient({ cache });
await client.preload({ scope: "all" });
// → 全件 L2 に永続化、次回起動でもネットワーク不要

Edge / Serverless 環境での注意

  • Cloudflare Workers / Vercel Edge ではファイル L2 は使えません。caches.default や Workers KV をラップした PersistentCache 実装を渡してください。
  • 短命プロセスでは L1 がリクエスト間で再利用されない可能性が高いので、preload は init 時に一度だけ実行する設計にします。
  • getMeta() は SDK 内で 1 度しか呼ばれません (キャッシュ) — 毎リクエストで叩かないでください。

API 一覧 (lookup / lookupGroup / lookupAll / preload / getMeta / refresh / isValidZipcode)、L1 LRU、オプショナル L2 キャッシュ、5xx 指数バックオフリトライ、データ version 変更時の自動 invalidate ― これらは全 SDK で共通実装されています。

キャッシュ戦略

SDK は 3 層のキャッシュを区別して管理します。デフォルト挙動を理解しておくと、preload / refresh のタイミングを判断しやすくなります。

目的サイズ目安デフォルト
L1 メモリ LRU同一プロセス内の重複 fetch 抑制~1 MB常時 ON (内部)
L2 永続キャッシュpreload / 起動高速化最大 ~10 MBOFF (ユーザー有効化)
L3 HTTP キャッシュブラウザ / OS / fetch 層環境依存Cache-Control 準拠

月次のデータ更新は /meta.jsonversion 変化で検知し、SDK は L1 と L2 を自動で invalidate します。明示的に再取得したい場合は refresh() を呼んでください。

MCP server

Claude / 任意の Model Context Protocol クライアントから日本の郵便番号を検索できる stdio サーバー @jpzip/mcp-server-jpzip を別パッケージとして提供しています。背後は同じ jpzip.nadai.dev の静的データなので、SDK と同一の結果が返ります。 stateless で、Claude プロセスのメモリにのみキャッシュを持ちます (永続キャッシュなし)。

インストール

Claude Code:

claude mcp add jpzip -- npx -y @jpzip/mcp-server-jpzip

Claude Desktop など mcp.json を直接編集する場合:

{
  "mcpServers": {
    "jpzip": {
      "command": "npx",
      "args": ["-y", "@jpzip/mcp-server-jpzip"]
    }
  }
}

提供 Tool

Tool引数用途
lookup_zipcode zipcode: string (7 桁、ハイフン許容) 郵便番号 → 住所 (漢字 / カナ / ローマ字 + JIS / 総務省コード)
search_by_address query: string, limit?: int (1–200、既定 20) 住所文字列 → 郵便番号候補 (漢字 / カナ / ローマ字横断、空白無視の部分一致)
list_cities_in_prefecture prefecture: string 都道府県 → 市区町村一覧 (総務省コード付き)
get_metadata データ version・件数・生成時刻

動作モデル

  • lookup_zipcode は対応する 3 桁 prefix (~10 KB) のみを CDN から取得し、SDK の L1 LRU にキャッシュします。
  • search_by_address / list_cities_in_prefecture は初回呼び出し時に全件 (~25 MB) を CDN から取得しメモリ保持。 同一 MCP プロセス内の以降の呼び出しは即時です。
  • 永続キャッシュは持ちません (stateless)。Claude の再起動でメモリは破棄され、次回必要になった時点で再取得します。
  • 駅・路線・事業所情報は jpzip データセットに含まれません (郵便番号 ⇄ 住所のみ)。 検索は 1 言語 (漢字 / カナ / ローマ字) 内の連続部分一致のみ対応します。

ソース: github.com/jpzip/mcp / npm: @jpzip/mcp-server-jpzip

プロトコル仕様

SDK を使わず raw HTTP で叩く場合や、別言語の SDK を実装する場合の参照です。spec の正本は github.com/jpzip/spec にあります。

エンドポイント

パス内容サイズ目安
/meta.jsonバージョン & 統計~10 KB
/g/{1}.json1 桁プレフィックスの全エントリ3〜4 MB
/p/{3}.json3 桁プレフィックスの全エントリ~10 KB

/all.json は意図的にありません — 全件で 25 MiB を超え Cloudflare Pages の上限を超過するためです。 全件が必要なときは /g/0.json/g/9.json を並列取得してマージします (SDK の lookupAll / preload はこれを自動で実行します)。

curl https://jpzip.nadai.dev/p/231.json \
  | jq '."2310017"'

スキーマ

/g/*/p/* は同じ構造のフラットな辞書。キーは 7 桁の zipcode、値は ZipcodeEntry

{
  "prefecture":      "神奈川県",
  "prefecture_kana": "カナガワケン",
  "prefecture_roma": "Kanagawa",
  "prefecture_code": "14",           // JIS X 0401 (2桁)
  "city":            "横浜市中区",
  "city_kana":       "ヨコハマシナカク",
  "city_roma":       "Yokohama Shi Naka Ku",
  "city_code":       "14104",         // 総務省コード (5桁)
  "towns": [
    { "town": "本町", "kana": "ホンチョウ", "roma": "Honcho" }
  ]
}

1 つの zipcode に複数町域が紐づく場合 (例: 京都の通り名) は towns 配列が複数要素になります。 「以下に掲載がない場合」のような特記事項は towns[].note に正規化されます。

HTTP 仕様

  • Method: GET のみ (クエリパラメータなし)
  • Content-Type: application/json; charset=utf-8
  • Encoding: gzip / brotli (Cloudflare 自動)
  • Cache-Control: public, max-age=86400 (24h)
  • CORS: Access-Control-Allow-Origin: *
  • 404: 実在しない prefix。SDK は「該当なし」として扱う
  • 5xx / network: SDK は指数バックオフで最大 3 回リトライ

バージョニング

  • spec_version (1.0 など): プロトコルのバージョン。SemVer 準拠。v1 系列の中では 既存フィールドの削除・型変更は行わない。
  • version (2026-05 など): データの月次バージョン。互換性とは無関係、データの 新鮮さの指標。

ライセンス

  • 仕様書 / SDK / ETL: MIT
  • 配信データ: Public Domain 相当 (元データは日本郵便)

商用利用・再配布・改変、いずれも自由です。

仕様は固定 実装は最小限

spec v1.0 はもう固定済み。プロトコルが薄いから、SDK の中身は数十行。各言語で同じシグネチャ、同じキャッシュ戦略を揃えています。