2026年4月29日水曜日

Node.js環境構築から始める「特許庁API検索アプリ」作成

 特許庁が提供する 特許情報取得API は、

特許検索・経過管理・知財DXに非常に有用です。

しかし、

  • ブラウザから直接呼べない(CORS制限)
  • ID・パスワードをJavaScriptに書けない
  • トークン管理が難しい

という理由から、Node.jsによるプロキシサーバ構築が実質必須になります。

本記事では、

👉 Node.jsのインストール(環境構築)
👉 プロキシAPIサーバ作成
👉 ブラウザ検索アプリ作成

まで、完全な手順書として解説します。

今回はRaspberry pi5のRaspberry Pi OSを使用しています。Ubuntuでも可能と思いますが、動かない場合は適宜手直ししていただれば幸いです。

 


1. Node.js をインストールする(最初にやること)

1-1. Node.jsとは?

Node.js JavaScriptをサーバ側で動かす実行環境 です。
今回のプロキシAPIサーバは Node.js で作成します。


1-2. Node.jsのインストール方法

LinuxRaspberry Pi OS Ubuntu

sudo apt update

sudo apt install nodejs npm

 

または、Node.jsを、以下のコマンでインストールします。

# 例えば、Node.js 18.x をインストール

curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -

sudo apt-get install -y nodejs

 


1-3. インストール確認

ターミナル(コマンドプロンプト)で以下を実行します。

node -v

npm -v

バージョンが表示されれば成功です。


2. プロジェクトフォルダを作成する

mkdir jpo-api-sample

cd jpo-api-sample


3. Node.jsプロジェクト初期化

npm init -y

必要なライブラリをインストールします。

npm install express cors dotenv


4. 環境変数ファイル(.env)を作成

プロジェクト直下に .env を作成し、以下を記述します。

JPO_USERNAME=あなたの特許庁APIユーザーID

JPO_PASSWORD=あなたの特許庁APIパスワード

⚠️ このファイルはGitHub等に公開しないでください


5. ① server.jsNode.js プロキシAPIサーバ)

以下を server.js として保存してください
(コードはそのままコピー&ペーストでOKです)。

// server.js — app_progress 専用版

import express from "express";

import cors from "cors";

// Node.js v18+ fetch が標準搭載

import "dotenv/config";

 

const app = express();

 

app.use(cors());

app.use(express.json());

app.use(express.urlencoded({ extended: true }));

 

// ==================================

// トークンキャッシュ

// ==================================

let cachedToken = null;

let tokenExpireAt = null;

 

// ==================================

// 特許庁 API: トークン取得

// ==================================

async function fetchTokenFromJpo() {

  const url = "https://ip-data.jpo.go.jp/auth/token";

  const params = new URLSearchParams();

  params.append("grant_type", "password");

  params.append("username", process.env.JPO_USERNAME);

  params.append("password", process.env.JPO_PASSWORD);

 

  const response = await fetch(url, {

    method: "POST",

    headers: { "Content-Type": "application/x-www-form-urlencoded" },

    body: params

  });

 

  const data = await response.json();

 

  if (data.access_token) {

    cachedToken = data.access_token;

    tokenExpireAt = Date.now() + data.expires_in * 1000 - 5000; // 期限5秒前更新

  }

  return data;

}

 

// ==================================

// 有効なトークンを返す関数

// ==================================

async function getValidToken() {

  const now = Date.now();

  if (cachedToken && tokenExpireAt && now < tokenExpireAt) {

    return cachedToken;

  }

  const newToken = await fetchTokenFromJpo();

  return newToken.access_token;

}

 

// ==================================

// 1) トークン取得 API

// ==================================

app.post("/api/token", async (req, res) => {

  try {

    const token = await getValidToken();

    res.json({

      access_token: token,

      cached: token === cachedToken

    });

  } catch (e) {

    res.status(500).json({ error: e.toString() });

  }

});

 

// ==================================

// 2) app_progress(特許経過情報)

// 出願番号(10桁)例: 2023063418

// ==================================

app.get("/api/app_progress/:number", async (req, res) => {

  try {

    const token = await getValidToken();

    const number = req.params.number;

    const url = https://ip-data.jpo.go.jp/api/patent/v1/app_progress/${number};

 

    const response = await fetch(url, {

      headers: {

        "Authorization": Bearer ${token}

      }

    });

 

    const text = await response.text();

 

    // -------------------------------

    // JSON でも HTML でも安全に返す

    // -------------------------------

    try {

      const json = JSON.parse(text);

      return res.status(response.status).json(json);

    } catch {

      return res.status(response.status).json({

        error: "JPO API returned non-JSON response",

        status: response.status,

        body: text

      });

    }

  } catch (e) {

    res.status(500).json({ error: e.toString() });

  }

});

 

// ==================================

// サーバ起動

// ==================================

app.listen(3000, () => {

  console.log(" app_progress 専用 JPO Proxy Server 起動!");

  console.log(" トークン取得: POST http://localhost:3000/api/token");

  console.log(" 経過情報: GET http://localhost:3000/api/app_progress/{出願番号}");

});


6. サーバを起動する

node server.js

以下が表示されれば成功です。

app_progress 専用 JPO Proxy Server 起動!


7. ② ブラウザアプリ(index.html

次に、検索用のHTMLを作成します。
以下を index.html として保存し、ブラウザで開いてください。

<!DOCTYPE html>

<html lang="ja">

<head>

  <meta charset="UTF-8">

  <title>特許経過情報(app_progress)検索</title>

  <style>

    body {

      font-family: sans-serif;

      margin: 40px auto;

      max-width: 700px;

    }

    label {

      font-weight: bold;

    }

    input {

      width: 100%;

      padding: 8px;

      margin: 8px 0 16px 0;

      font-size: 16px;

    }

    button {

      padding: 10px 20px;

      font-size: 17px;

      cursor: pointer;

    }

    pre {

      background: #f7f7f7;

      border: 1px solid #ccc;

      padding: 15px;

      white-space: pre-wrap;

      margin-top: 20px;

    }

  </style>

</head>

<body>

 

<h2>📄 特許経過情報(app_progress)検索</h2>

 

<label>出願番号(10桁数字:例 2023063418</label>

<input id="appNumber" placeholder="2023063418">

 

<button onclick="search()">検索する</button>

 

<pre id="result">ここに検索結果が表示されます</pre>

 

<script>

async function search() {

  const num = document.getElementById("appNumber").value.trim();

  const result = document.getElementById("result");

 

  if (!num.match(/^[0-9]{10}$/)) {

    result.textContent = "⚠️ 出願番号は10桁の数字を入力してください。";

    return;

  }

 

  result.textContent = "問い合わせ中…";

 

  try {

    const res = await fetch(http://localhost:3000/api/app_progress/${num});

    const json = await res.json();

    result.textContent = JSON.stringify(json, null, 2);

  } catch (err) {

    result.textContent = "エラーが発生しました:\n" + err;

  }

}

</script>

 

</body>

</html>


8. 動作確認

  1. server.js を起動
  2. index.html をブラウザで開く
  3. 出願番号を入力して検索

👉 特許庁の 経過情報(app_progress が表示されます。


まとめ

Node.jsインストールからスタート
セキュアな特許庁APIプロキシ構築
ブラウザ検索UI完成

この構成を使えば、

  • 社内システム連携
  • Excel / Power BI 連携
  • AI・分析基盤への接続

まで、知財DXの土台がすぐに作れます。

ぜひこの構成をベースに、応用・拡張してみてください。