👌

TypeScriptでe-Stat APIのデータを取得する

2024/07/21に公開

TypeScriptでe-Stat APIのデータを取得する方法

e-Stat APIの概要

e-Stat APIは、日本の政府統計総合窓口(e-Stat)が提供する公式APIです。このAPIを使用することで、日本の様々な統計データに簡単にアクセスできます。主な特徴は以下の通りです:

  1. 豊富なデータセット:人口統計、経済指標、社会調査など、幅広い分野のデータが利用可能です。

  2. リアルタイムデータ:最新の統計情報にアクセスできます。

  3. カスタマイズ可能なクエリ:特定の地域、期間、カテゴリーなどでデータをフィルタリングできます。

  4. JSON形式のレスポンス:プログラムで扱いやすいJSON形式でデータが提供されます。

  5. アクセス制限:APIキーが必要で、1日あたりのリクエスト数に制限があります。

e-Stat APIを使用するには、まず利用登録を行い、APIキーを取得する必要があります。

コードの全体像

まず、完全なコードを見てみましょう:

import { HttpsProxyAgent } from 'https-proxy-agent'
import fetch from 'node-fetch'
import paramsSerializer from './modules/paramsSerializer'
import { EstatParamsType } from './types/params'
import { EStatResponseType } from './types/response'

const API_KEY = process.env.ESTAT_API_APPID
const BASE_URL = 'https://api.e-stat.go.jp/rest/3.0/app/json/getStatsData'
const PROXY_URL = process.env.HTTP_PROXY

const agent = PROXY_URL ? new HttpsProxyAgent(PROXY_URL) : undefined

function isValidEStatResponse(data: unknown): data is EStatResponseType {
  return data && typeof data === 'object' && 'GET_STATS_DATA' in data
}

export async function fetchEstatAPI(
  params: Omit<EstatParamsType, 'appId'>
): Promise<EStatResponseType> {
  const queryParams: EstatParamsType = {
    appId: API_KEY!,
    ...Object.fromEntries(
      Object.entries(params).map(([key, value]) => [
        key,
        Array.isArray(value) ? value.join(',') : value,
      ])
    ),
  } as EstatParamsType

  const url = `${BASE_URL}?${paramsSerializer(queryParams)}`

  try {
    const response = await fetch(url, {
      method: 'GET',
      headers: { 'Content-Type': 'application/json' },
      agent,
    })

    if (!response.ok) {
      throw new Error(
        `e-Stat APIリクエストが失敗しました: ${response.status} ${response.statusText}`
      )
    }

    const data = await response.json()

    if (!isValidEStatResponse(data)) {
      throw new Error('e-Stat APIからの応答形式が無効です')
    }

    return data
  } catch (error) {
    console.error('e-Statデータの取得中にエラーが発生しました:', error)
    throw new Error(
      'e-Statデータの取得に失敗しました。詳細はコンソールを確認してください。'
    )
  }
}

1. 型定義

e-Stat APIを使用する際、適切な型定義は非常に重要です。以下に、すべての型定義を示します:

export interface EstatParamsType {
  appId?: string
  statsDataId: string
  cdCat01: string | string[]
  cdArea?: string | string[]
}

export interface ResultType {
  STATUS: number
  ERROR_MSG: string
  DATE: string
}

export interface NarrowingCondType {
  CODE_CAT01_SELECT: string
}

export interface ParameterType {
  LANG: string
  STATS_DATA_ID: string
  NARROWING_COND: NarrowingCondType
  DATA_FORMAT: string
  START_POSITION: number
  METAGET_FLG: string
}

export interface ResultInfType {
  TOTAL_NUMBER: number
  FROM_NUMBER: number
  TO_NUMBER: number
}

export interface StatNameType {
  code: string
  text: string
}

export interface GovOrgType {
  code: string
  text: string
}

export interface MainCategoryType {
  code: string
  text: string
}

export interface SubCategoryType {
  code: string
  text: string
}

export interface StatisticsNameSpecType {
  TABULATION_CATEGORY: string
  TABULATION_SUB_CATEGORY1: string
}

export interface TitleSpecType {
  TABLE_NAME: string
}

export interface TableInfType {
  id: string
  STAT_NAME: StatNameType
  GOV_ORG: GovOrgType
  STATISTICS_NAME: string
  TITLE: string | Record<string, unknown>
  CYCLE: string
  SURVEY_DATE: number
  OPEN_DATE: string
  SMALL_AREA: number
  MAIN_CATEGORY: MainCategoryType
  SUB_CATEGORY: SubCategoryType
  OVERALL_TOTAL_NUMBER: number
  UPDATED_DATE: string
  STATISTICS_NAME_SPEC: StatisticsNameSpecType
  TITLE_SPEC: TitleSpecType
}

export interface ClassType {
  code: string
  name: string
  level: string
  unit: string
}

export interface ClassObjType {
  id: string
  name: string
  CLASS: ClassType | ClassType[]
}

export interface ClassInfType {
  CLASS_OBJ: ClassObjType[]
}

export interface NoteType {
  char: string
  text: string
}

export interface ValueType {
  tab: string
  cat01: string
  area: string
  time: string
  unit: string
  text: string
}

export interface DataInfType {
  NOTE: NoteType[]
  VALUE: ValueType[]
}

export interface StatisticalDataType {
  RESULT_INF: ResultInfType
  TABLE_INF: TableInfType
  CLASS_INF: ClassInfType
  DATA_INF: DataInfType
}

export interface GetStatsDataType {
  RESULT: ResultType
  PARAMETER: ParameterType
  STATISTICAL_DATA: StatisticalDataType
}

export interface EStatResponseType {
  GET_STATS_DATA: GetStatsDataType
}

これらの型定義により、APIリクエストのパラメータ(EstatParamsType)とレスポンス(EStatResponseType)の構造が明確になります。また、StatisticalDataTypeのような中間の型定義により、レスポンスデータの詳細な構造も把握できます。

型定義を使用することで、以下のメリットがあります:

  1. コード補完: IDEが適切なプロパティを提案してくれます。
  2. 型チェック: コンパイル時にエラーを検出できます。
  3. ドキュメンテーション: コードの理解が容易になります。

2. 必要なモジュールのインポート

import { HttpsProxyAgent } from 'https-proxy-agent'
import fetch from 'node-fetch'
import paramsSerializer from './modules/paramsSerializer'
import { EstatParamsType } from './types/params'
import { EStatResponseType } from './types/response'

ここでは、必要なモジュールとカスタム型をインポートしています。HttpsProxyAgentはプロキシ接続のため、fetchはHTTPリクエスト用、paramsSerializerはクエリパラメータの変換用です。また、EstatParamsTypeEStatResponseTypeはAPIのパラメータとレスポンスの型定義です。

3. 定数の設定

const API_KEY = process.env.ESTAT_API_APPID
const BASE_URL = 'https://api.e-stat.go.jp/rest/3.0/app/json/getStatsData'
const PROXY_URL = process.env.HTTP_PROXY

const agent = PROXY_URL ? new HttpsProxyAgent(PROXY_URL) : undefined

ここでは、API認証キー、ベースURL、プロキシURL(必要な場合)を設定しています。環境変数を使用することで、セキュリティを確保しつつ、柔軟な設定が可能になります。

4. レスポンス検証関数

function isValidEStatResponse(data: unknown): data is EStatResponseType {
  return data && typeof data === 'object' && 'GET_STATS_DATA' in data
}

この関数は、APIからのレスポンスが期待される形式かどうかを検証します。型ガードとして機能し、TypeScriptの型安全性を強化します。

5. メインのAPI取得関数

export async function fetchEstatAPI(
  params: Omit<EstatParamsType, 'appId'>
): Promise<EStatResponseType> {
  // ... (実装詳細)
}

この関数が、実際にAPIからデータを取得する中心的な部分です。非同期関数として実装され、プロミスを返します。

6. クエリパラメータの構築

const queryParams: EstatParamsType = {
  appId: API_KEY!,
  ...Object.fromEntries(
    Object.entries(params).map(([key, value]) => [
      key,
      Array.isArray(value) ? value.join(',') : value,
    ])
  ),
} as EstatParamsType

ここでは、APIに送信するクエリパラメータを構築しています。配列パラメータはカンマ区切りの文字列に変換されます。

7. APIリクエストの実行

const url = `${BASE_URL}?${paramsSerializer(queryParams)}`
const response = await fetch(url, {
  method: 'GET',
  headers: { 'Content-Type': 'application/json' },
  agent,
})

構築したURLを使用してAPIリクエストを実行します。プロキシが設定されている場合は、agentを使用します。

8. エラーハンドリングとレスポンス処理

if (!response.ok) {
  throw new Error(
    `e-Stat APIリクエストが失敗しました: ${response.status} ${response.statusText}`
  )
}

const data = await response.json()

if (!isValidEStatResponse(data)) {
  throw new Error('e-Stat APIからの応答形式が無効です')
}

return data

レスポンスのステータスコードとデータ形式を確認し、エラーがあれば例外をスローします。正常なレスポンスの場合、データを返します。

EstatParamsType の詳細

EstatParamsType はe-Stat APIへのリクエストパラメータを定義するインターフェースです。主要なプロパティは以下の通りです:

export interface EstatParamsType {
  appId?: string
  statsDataId: string
  cdCat01: string | string[]
  cdArea?: string | string[]
}
  • appId: APIキー。通常は環境変数から取得します。
  • statsDataId: 取得したい統計データのID。e-Statのウェブサイトで確認できます。
  • cdCat01: データのカテゴリコード。単一の文字列または文字列の配列で指定できます。
  • cdArea: 地域コード。オプションで、単一の文字列または文字列の配列で指定できます。

この型定義により、APIリクエストを作成する際に必要なパラメータを明確に把握でき、誤ったパラメータ名の使用や必須パラメータの欠落を防ぐことができます。

使用例:

const params: Omit<EstatParamsType, 'appId'> = {
  statsDataId: '0003348423',
  cdCat01: ['A1100', 'A1200'],
  cdArea: '13000'
};

EStatResponseType の詳細

EStatResponseType はe-Stat APIからのレスポンスの構造を定義するインターフェースです。この型は複雑な入れ子構造を持っています:

export interface EStatResponseType {
  GET_STATS_DATA: GetStatsDataType
}

export interface GetStatsDataType {
  RESULT: ResultType
  PARAMETER: ParameterType
  STATISTICAL_DATA: StatisticalDataType
}

主要な部分を詳しく見ていきます:

  1. RESULT: APIリクエストの結果情報

    export interface ResultType {
      STATUS: number
      ERROR_MSG: string
      DATE: string
    }
    
    • STATUS: リクエストの状態コード
    • ERROR_MSG: エラーがある場合のメッセージ
    • DATE: レスポンスの日付
  2. PARAMETER: リクエストで使用されたパラメータの情報

    export interface ParameterType {
      LANG: string
      STATS_DATA_ID: string
      NARROWING_COND: NarrowingCondType
      DATA_FORMAT: string
      START_POSITION: number
      METAGET_FLG: string
    }
    
  3. STATISTICAL_DATA: 実際の統計データ

    export interface StatisticalDataType {
      RESULT_INF: ResultInfType
      TABLE_INF: TableInfType
      CLASS_INF: ClassInfType
      DATA_INF: DataInfType
    }
    
    • RESULT_INF: データの結果情報(総数、範囲など)
    • TABLE_INF: テーブル情報(統計名、作成機関など)
    • CLASS_INF: データの分類情報
    • DATA_INF: 実際の統計値データ

この詳細な型定義により、レスポンスデータの構造を正確に把握し、型安全な方法でデータにアクセスできます。また、IDEの自動補完機能を最大限に活用できるため、開発効率が向上します。

使用例:

function processResponse(response: EStatResponseType) {
  const status = response.GET_STATS_DATA.RESULT.STATUS;
  if (status !== 0) {
    console.error(`Error: ${response.GET_STATS_DATA.RESULT.ERROR_MSG}`);
    return;
  }
  
  const data = response.GET_STATS_DATA.STATISTICAL_DATA.DATA_INF

Discussion