🐿 こども経済新聞 Python入門SQL入門ネットワークGit・GitHub
段階
0 / 17 ステップ

まず、全体の地図

用語より先に、「1本のリクエストが往復する順番」をつかむ

API学習でいちばん多い挫折は、「サンプルコードは動いたけれど、少し違う相手先になると何も分からない」という状態です。 これは、連携をコピーしたコードのかたまりとして覚えてしまっているために起こります。 実務で本当に役立つのは、「自分のプログラムから相手のサーバーまで、何を送り、何が返り、失敗したらどこを見るか」を、 一本の線として説明できる力です。相手のAPIが変わっても、この線を持っている人は5分で対応できます。 このページは、その一本の線を下から順に積み上げる構成にしています。

段階ステップ身につくことできるようになること
基礎 STEP 0〜3 APIの役割、HTTPの往復、URLとメソッド、JSONの読み書き APIドキュメントの1ページ目を、意味を分かって読める
しくみ STEP 4〜8 ヘッダーとステータスコード、REST、認証と認可、curl、仕様書(OpenAPI) 初めて見るAPIを、ドキュメントだけを頼りに自力で1回叩ける
実装 STEP 9〜12 JavaScriptのfetch、Pythonのrequests、フォーム連携、エラー処理とリトライ 画面やバッチ処理に、API連携を自分で組み込める
運用 STEP 13〜14 ページネーション、レート制限、Webhook、ログ、テスト 1万件の取り込みや、24時間動く連携を任される
セキュリティ STEP 15 鍵の保管、CORS、署名検証、最小権限、個人情報の扱い 「その実装で漏れませんか」に理由つきで答えられる
実務 STEP 16 要件の確認、見積り、設計書、障害対応、引き継ぎ 連携案件を、最初から最後までひとりで回せる

目安の期間は「1日30分〜1時間、週5日」を想定しています。すでにプログラミングの経験がある方は、STEP 4から入っても構いません。急ぐ必要はありません。手を動かした分だけ身につく分野です。

17ステップの目次

17ステップ

すべての段階 / 17件を表示中
STEP 0 基礎

APIとは何か ── 学ぶ順番を決める

目安 1〜2日
このステップの到達点 ── 「API」を、技術の名前ではなくサービス同士の受付窓口として説明できる。そして、これから学ぶ順番がなぜこの順番なのかを言える。ここができていれば、あとの16ステップは地図に地名を書き込んでいく作業になります。

APIとは「機械のための受付窓口」

API(Application Programming Interface)とは、あるサービスが「ここに、この形式で頼んでくれれば、この形式で返します」とあらかじめ公開している窓口のことです。人間向けの窓口が画面(Webサイトやアプリ)なら、プログラム向けの窓口がAPIです。

レストランで考えると分かりやすくなります。厨房(データベースや業務ロジック)に客が直接入ることはできません。客はメニュー(=APIドキュメント)を見て、店員(=API)に注文します。店員は決まった書き方の伝票で厨房に伝え、料理を持って帰ってきます。ここで大事なのは、客は厨房の作り方を知らなくてよいということです。これがAPIの本質で、カプセル化と呼ばれる考え方です。

いちばん大まかな全体像
あなたのプログラム 相手のサービス あなたの アプリ・画面 通信 (HTTPS) APIの 受付窓口 相手のDB・ 業務ロジック
  • 何を頼むか決める(リクエストを組み立てる)
  • インターネットを通って相手に届く(暗号化される)
  • 相手が「あなたが誰か」を確かめ、頼みを処理する(認証・認可)
  • 結果をJSONという形式に整えて返す → ①に戻って受け取る

APIを学ぶと、何ができるようになるのか

抽象的な話が続くと退屈なので、先に「できるようになること」を挙げます。すべて、実際の会社で日常的に発生している仕事です。

データを自動で取り込む

会計サービスや販売管理の売上を、毎朝5時に自動で自社の集計表に取り込む。

画面に外部の情報を出す

自社サイトに、天気・地図・為替・在庫といった外部サービスの情報を表示する。

通知を飛ばす

問い合わせが届いたら、SlackやLINE、メールに自動で通知する。

システム同士をつなぐ

受注システムに入った注文を、倉庫システムへ自動で流す(連携の中心的な仕事)。

AIを組み込む

文章の要約や分類を、AIサービスのAPIに任せて自社の業務に組み込む。

自社のAPIを作る

取引先に「うちのデータはここから取ってください」と窓口を提供する側になる。

学ぶ順番は「1本のリクエスト」を中心に据える

APIの学習でよくある遠回りは、いきなりライブラリやフレームワークの使い方から入ることです。それだと、そのライブラリの外へ出た瞬間に何もできなくなります。順番はこうです。

  1. HTTPの往復を知る(STEP 1〜2)── すべてのWeb APIはこの上に乗っています
  2. JSONを読み書きできる(STEP 3)── 返ってくるデータの形はほぼこれです
  3. ヘッダー・ステータスコード・認証を知る(STEP 4〜6)── 失敗の9割はここが原因です
  4. curlで手で叩く(STEP 7)── プログラムを書く前に、必ず手で1回叩きます
  5. プログラムに落とす(STEP 9〜10)── ここで初めてコードを書きます

この順番には理由があります。APIがうまく動かないとき、原因のほとんどはプログラムではなく「リクエストの中身」にあるからです。手で叩ける人は、原因の場所を数分で切り分けられます。

手を動かす準備 このページのコマンドは、Windowsなら「コマンドプロンプト」か「PowerShell」(検索窓に cmd と入力)、Macなら「ターミナル」(アプリケーション → ユーティリティ)で実行します。curl は最近のWindows・Mac・Linuxには最初から入っています。Pythonの例を動かす場合はPythonの導入が必要ですが、STEP 9まではブラウザとcurlだけで進められます。
最初の一歩:本当にAPIを1回叩いてみる
# 使える道具があるか確認する
curl --version

# 誰でも使える練習用のAPIに、いま日本は何時かを聞いてみる
curl "https://worldtimeapi.org/api/timezone/Asia/Tokyo"
返ってくるもの(例・一部)
{"abbreviation":"JST","datetime":"2026-08-14T09:12:34.567890+09:00",
 "day_of_week":5,"timezone":"Asia/Tokyo","utc_offset":"+09:00", ...}

ぐしゃっとした文字列が出てくれば大成功です。あなたはいま、世界のどこかにあるサーバーに話しかけ、返事をもらいました。これがAPI連携のすべての土台です。この読みにくい文字列を「読める形」にするのがSTEP 3です。

この分野の「略語の多さ」との付き合い方

APIの世界も、英語の頭文字を取った略語(HTTP、REST、JSON、OAuth……)が非常に多い分野です。ここで挫折する人が多いのですが、対処法ははっきりしています。略語を覚えようとせず、「何をする役目か」を一言で覚えることです。

略語読み方正式名称一言でいうと
APIエーピーアイApplication Programming Interfaceプログラム向けの受付窓口
HTTPエイチティーティーピーHyperText Transfer ProtocolWebでやり取りするときの共通ルール
HTTPSエイチティーティーピーエスHTTP SecureHTTPを暗号化したもの。APIは必ずこちら
URLユーアールエルUniform Resource Locator「どこに」頼むかを表す住所
JSONジェイソンJavaScript Object Notationデータをやり取りする、いまの標準の書式
RESTレストREpresentational State TransferAPIの作り方の作法。いちばん普及している
CRUDクラッドCreate Read Update Deleteデータ操作の4種類(作る・読む・直す・消す)
OAuthオーオースOpen Authorizationパスワードを渡さずに許可だけ渡すしくみ
SDKエスディーケーSoftware Development KitAPIを楽に使うための、公式の道具箱
CORSコルスCross-Origin Resource Sharingブラウザから別サイトのAPIを呼ぶときの許可制度

この表は、ステップを進めるたびに戻ってきてください。10個の役目が言えるようになれば、API連携の会話の8割はついていけます。

ふりがな機能について このページは、難しい漢字や英語の略語にふりがなを付けています。画面上部の「ふりがな ON/OFF」ボタンでいつでも切り替えられ、設定は次に開いたときも引き継がれます。読み方を間違えて覚えると、会話で通じない・検索できないという実害が出ます(OAuthを「オーオース」ではなく別の読み方で覚えていて話が通じない、というのは実際によくあります)。最初は必ずONで読んでください
一問一答
  1. APIとは何ですか。一言で答えてください。
  2. APIを使う側は、相手の中身(データベースの構造など)を知る必要がありますか。それはなぜですか。
  3. プログラムを書く前に、まずcurlで手で叩くとよいのはなぜですか。
解答を見る
  1. サービスが公開している、プログラム向けの受付窓口(決まった形で頼めば、決まった形で返してくれる約束ごと)。
  2. 必要ない。APIが中身を隠し、決まった入口と出口だけを見せているため(カプセル化)。相手が内部を作り替えても、窓口の形が同じなら使う側は影響を受けない。
  3. うまくいかない原因のほとんどは、プログラムではなくリクエストの中身(URL・ヘッダー・認証情報)にあるため。手で叩けると切り分けが数分で済む。
STEP 1 基礎

HTTPの往復 ── リクエストとレスポンスがすべての土台

目安 3日
このステップの到達点 ── 「リクエスト」と「レスポンス」が、それぞれ3つの部品でできていることを言える。そして、自分が送った1本のリクエストを、部品ごとに分解して説明できる。実務では、この分解ができるだけで障害対応の速さが変わります。

Web APIは「1往復」しかしない

Web APIの通信は、驚くほど単純です。あなたが1回頼み(リクエスト)、相手が1回返す(レスポンス)。それで1回分は終わりです。相手のサーバーは、あなたのことを次の瞬間には忘れています。この「毎回まっさらから始まる」性質をステートレス(状態を持たない)と呼びます。

だからこそ、毎回のリクエストに「自分が誰か」を書いて送る必要があるのです。ここが分かっていないと、STEP 6の認証で必ずつまずきます。「1回ログインしたのに、なぜ毎回トークンを付けるのか」の答えが、このステートレスという性質です。

1往復の中身
【リクエスト】あなた → 相手 ① 開始行 GET /v1/users/12 HTTP/1.1 ② ヘッダー(付帯情報) Host: api.example.com Authorization: Bearer … ③ ボディ(本文・任意) {"name":"山田太郎"} 【レスポンス】相手 → あなた ① ステータス行 HTTP/1.1 200 OK ② ヘッダー(付帯情報) Content-Type: application/json X-RateLimit-Remaining: 58 ③ ボディ(本文) {"id":12,"name":"山田太郎"}
  • どこに何をしたいか どんな条件・資格で 実際のデータ

3つの部品の役割を、はっきり分ける

部品入るもの具体例ここが原因の失敗
開始行メソッド+パス+バージョンGET /v1/users/12404(住所が違う)、405(メソッドが違う)
ヘッダー認証情報、データ形式、言語、独自の指定AuthorizationContent-Type401(資格なし)、415(形式が違う)
ボディ送りたいデータ本体(JSONなど){"name":"山田"}400(中身が不正)、422(値が不適切)

初学者が最も多く踏む地雷はヘッダーの書き忘れです。「コードは合っているのに401が返る」の9割は、認証ヘッダーの付け方かデータ形式の指定ミスです。

実際に、往復のすべてを目で見る

curl -v(verbose = 詳しく)を付けると、送った内容と返ってきた内容がすべて画面に出ます。これはAPI学習で最も効く道具のひとつです。

往復の全部を見る
# -v で通信の中身を表示(> が送った内容、< が返ってきた内容)
curl -v "https://httpbin.org/get"

# ヘッダーだけを見たいとき(-I は HEAD リクエスト)
curl -I "https://httpbin.org/get"
画面に出るもの(抜粋)
> GET /get HTTP/1.1          ← ここから下が「あなたが送った」内容
> Host: httpbin.org
> User-Agent: curl/8.4.0
> Accept: */*
>
< HTTP/1.1 200 OK            ← ここから下が「相手が返した」内容
< Content-Type: application/json
< Content-Length: 258
<
{ "args": {}, "headers": { ... }, "url": "https://httpbin.org/get" }

> が送信、< が受信です。この画面を読めるようになることが、STEP 1の目的です。うまくいかないときは、まずこれを出して「自分が本当は何を送っていたのか」を確かめます。

練習に使える公開API httpbin.org は、送った内容をそのまま返してくれる練習専用のサービスです。自分が何を送ったかを確認する鏡として使えます。ほかに jsonplaceholder.typicode.com(架空の投稿データ)もよく使われます。どちらも認証なしで叩けます。

APIサーバー・クライアント・エンドポイント

用語を3つだけ整理します。ここは実務の会話でそのまま出ます。

  • クライアント:頼む側。あなたのプログラム、ブラウザ、curl、スマホアプリなど
  • サーバー:返す側。相手のサービス
  • エンドポイント:頼み先の具体的なURL。https://api.example.com/v1/users のように、1つの機能につき1つ用意されている

APIドキュメントを開くと、まず「エンドポイント一覧」が載っています。それは「この会社に頼めることの一覧」だと思ってください。

やってはいけないこと 練習だからといって、他人のAPIに短い間隔で大量のリクエストを送らないでください。相手のサーバーに負荷をかける行為で、攻撃とみなされることがあります。繰り返し試すときは1秒以上の間隔を空け、公開APIの利用規約(利用条件)に必ず目を通してください。
一問一答
  1. リクエストを構成する3つの部品を挙げてください。
  2. HTTPが「ステートレス」であるとは、どういう意味ですか。それが認証にどう影響しますか。
  3. 「コードは正しいのに401が返る」とき、まずどこを疑いますか。
解答を見る
  1. 開始行(メソッド+パス)、ヘッダー、ボディ。
  2. サーバーは前回の通信を覚えていないという意味。そのため、毎回のリクエストに認証情報(トークンなど)を付けて送る必要がある。
  3. ヘッダー。Authorization の書式(Bearerの有無、余分な空白や改行)と、鍵の有効期限・環境(本番/検証)の取り違え。
STEP 2 基礎

URLとメソッド ── 「どこに」「何をするか」を書く

目安 2〜3日
このステップの到達点 ── 初めて見るURLを部品ごとに分解でき、パスパラメータとクエリパラメータの違いを説明できる。GET・POST・PUT・PATCH・DELETEを、意味を分かって選べる。

URLを部品に分解する

APIドキュメントに書かれたURLは、必ず同じ構造をしています。一度覚えれば、どの会社のAPIでも同じように読めます。

URLの構造
https://api.example.com/v1/users/12?fields=name,email&limit=20 クエリパラメータ(条件・絞り込み) パスパラメータ(どの1件か=ID) リソース名(何を扱うか。ふつう複数形) バージョン(v1・v2。仕様変更に備えた区切り) ホスト名(どのサーバーか) スキーム(通信方式。APIは必ず https)

パスパラメータとクエリパラメータの使い分け

ここは初学者が混乱する場所ですが、判断基準は明快です。

種類書く場所意味使う場面
パスパラメータURLの道の途中どれか1つを特定する/users/12ID指定。無ければ404が正しい
クエリパラメータ? より後ろ条件を付ける・絞り込む?status=active&limit=20検索、並び替え、ページ指定

覚え方は「パスは住所、クエリは注文の細かい要望」です。「12番の社員を見せて」は住所(/users/12)、「在籍中の人を20件だけ、名前順で」は要望(?status=active&limit=20&sort=name)です。

クエリパラメータの書き方の決まり 最初のひとつは ?、2つめ以降は & でつなぎます。値に日本語・空白・記号が入る場合はURLエンコード(パーセントエンコーディング)が必要です。「東京」は %E6%9D%B1%E4%BA%AC、空白は %20 になります。curlなら --data-urlencode、プログラムなら各言語の標準機能が自動で処理してくれます。手で書かず、道具に任せるのが鉄則です。

HTTPメソッド ── 「何をするか」を1語で伝える

メソッドは、同じURLに対して「読むのか、作るのか、消すのか」を示す動詞です。URLは名詞、メソッドは動詞と覚えてください。

メソッド意味CRUDボディ冪等性
GET取得する(読むだけ)ReadなしありGET /usersGET /users/12
POST新しく作る・処理を実行するCreateありなしPOST /users
PUTまるごと置き換えるUpdateありありPUT /users/12
PATCH一部だけ直すUpdateあり場合によるPATCH /users/12
DELETE消すDeleteふつうなしありDELETE /users/12

冪等性 ── 実務でいちばん大事な性質

冪等性(べきとうせい/idempotency)とは、同じ操作を何回繰り返しても、結果が1回のときと同じになる性質のことです。読み方を間違えやすい言葉ですが、意味は難しくありません。

  • GET /users/12 を100回叩いても、データは何も変わらない → 冪等
  • DELETE /users/12 を100回叩いても、消えている状態は同じ → 冪等
  • POST /orders を100回叩くと、注文が100件できる冪等ではない

この違いが効くのは、通信が失敗して、もう一度送るべきか迷ったときです。GETやPUTなら安心して再送できますが、POSTの再送は二重注文・二重請求を生みます。だから支払いや注文のAPIには、Idempotency-Key という「同じ鍵の依頼は1回しか受け付けない」ヘッダーが用意されていることが多いのです(STEP 11で扱います)。

実務でのやらかし 「送信ボタンを押したが反応がないので、もう一度押した」──これで二重注文が発生する事故は、いまも毎日どこかで起きています。POSTを扱うときは、再送されうる前提で設計するのが実務の常識です。
メソッドを変えて試す
# 取得(GET)。-X は省略してよい(curlの既定がGETのため)
curl "https://jsonplaceholder.typicode.com/posts/1"

# 一覧を条件つきで取得(クエリパラメータ)
curl "https://jsonplaceholder.typicode.com/posts?userId=1&_limit=3"

# 作成(POST)。-d でボディを送り、形式をヘッダーで伝える
curl -X POST "https://jsonplaceholder.typicode.com/posts" \
  -H "Content-Type: application/json" \
  -d '{"title":"はじめてのAPI","body":"テスト投稿","userId":1}'

# 削除(DELETE)
curl -X DELETE "https://jsonplaceholder.typicode.com/posts/1"
POSTの結果(例)
{
  "title": "はじめてのAPI",
  "body": "テスト投稿",
  "userId": 1,
  "id": 101
}

送っていない id が付いて返ってきました。採番は相手のサーバーの仕事だからです。「作成したものの結果を返す」のはREST APIの標準的なふるまいで、この id を控えておくと、あとで更新や削除ができます。

一問一答
  1. /products/88?color=red のうち、パスパラメータとクエリパラメータはそれぞれどれですか。
  2. 冪等性とは何ですか。POSTは冪等ですか。
  3. 「更新」にPUTとPATCHのどちらを使うべきか、判断基準を述べてください。
解答を見る
  1. パスパラメータは 88(どの商品か)、クエリパラメータは color=red(絞り込み条件)。
  2. 同じ操作を何回繰り返しても結果が1回と同じになる性質。POSTは冪等ではない(叩いた回数だけ作られる)。
  3. 送らなかった項目まで空にしてよいならPUT(まるごと置き換え)、送った項目だけを変えたいならPATCH(部分更新)。実務ではPATCHのほうが事故が少ない。
STEP 3 基礎

JSON ── 返ってくるデータを読み書きする

目安 3日
このステップの到達点 ── JSONを見て、ほしい値までの道すじ(パス)を口で言える。オブジェクトと配列を見分けられ、書式の誤りを自分で直せる。ここができると、APIの返事が「読める文書」に変わります。

JSONは、たった6種類しかない

JSON(ジェイソン)は、データを文字で表すための書式です。覚えるのは6種類だけです。

種類書き方注意点
文字列ダブルクォートで囲む"山田太郎"シングルクォートは不可
数値そのまま書く1200-3.5先頭0や桁区切りのカンマは不可
真偽値小文字で書くtruefalseTrue(大文字始まり)は不可
nullnull「値が無い」ことを表す。0や空文字とは違う
オブジェクト{ } 名前と値の組{"name":"山田","age":30}名前も必ずダブルクォート
配列[ ] 順番に並んだ値[1,2,3][{...},{...}]順番に意味がある

よくある書式エラーは3つです。①末尾のカンマ(最後の項目のうしろにカンマを付けてしまう)、②シングルクォート、③コメントを書いてしまう。JSONにコメントは書けません。

入れ子(ネスト)を、道すじとして読む

実際のAPIの返事は、オブジェクトの中に配列、配列の中にオブジェクト……と入れ子になっています。読み方のこつは、上から順に「〜の中の〜の中の」と声に出すことです。

よくある形のレスポンス
{
  "status": "ok",
  "total": 2,
  "users": [
    {
      "id": 12,
      "name": "山田太郎",
      "active": true,
      "department": { "code": "S01", "name": "営業部" },
      "tags": ["新規", "重点"]
    },
    {
      "id": 13,
      "name": "鈴木花子",
      "active": false,
      "department": { "code": "K02", "name": "経理部" },
      "tags": []
    }
  ]
}
道すじの読み方
山田太郎の所属部署名がほしい
  → users の 0番目 の department の name
  → users[0].department.name  = "営業部"

2人目の1つ目のタグは?
  → users[1].tags[0]  = 存在しない(空の配列)→ ここで落ちるコードが多い

配列の番号は0から始まります。1件目は [0] です。ここを間違えると、実務でも「1件ずれる」不具合の温床になります。

実務でいちばん多いバグ 「あるはずの項目が無い」ことによるエラーです。上の例の tags のように空だったり、項目そのものが返らなかったり、null だったりします。APIの返事は、いつも同じ形とは限りません。STEP 11で、この防ぎ方を扱います。

読める形に整える(整形とjq)

curlの結果は1行にぎゅっと詰まっていて読めません。整形する方法を覚えておくと、以降の学習が一気に楽になります。

JSONを読める形にする
# Python が入っていれば、追加インストール不要で整形できる
curl -s "https://jsonplaceholder.typicode.com/users/1" | python3 -m json.tool

# jq を使う場合(別途インストール。API業務では定番の道具)
curl -s "https://jsonplaceholder.typicode.com/users/1" | jq

# ほしい値だけ取り出す(jq)
curl -s "https://jsonplaceholder.typicode.com/users/1" | jq '.address.city'

# 一覧から、名前だけを並べる
curl -s "https://jsonplaceholder.typicode.com/users" | jq '.[].name'
jq の結果(例)
"Gwenborough"

"Leanne Graham"
"Ervin Howell"
"Clementine Bauch"
 …

-s は進捗表示を消すオプションです。jq の書き方は JSONの道すじをそのまま書くだけ.users[0].name)なので、上で練習した読み方がそのまま使えます。

ブラウザでも整形できます Chromeなら、APIのURLをそのままアドレス欄に貼れば結果が見られます(認証不要のAPIに限る)。開発者ツール(F12キー)の「ネットワーク」タブを開くと、いま見ているサイトが裏で叩いているAPIも全部見えます。これは学習教材の宝庫です。

日付・数値・文字コードの落とし穴

  • 日付"2026-08-14T09:12:34+09:00" という書式(ISO 8601)が標準です。末尾の Z は世界標準時(UTC)を意味し、日本時間より9時間前です。ここを取り違えると「日付が1日ずれる」不具合になります。
  • 数値:金額やIDは、文字列で返ってくることがあります"1200")。桁が大きいIDは、数値として扱うと精度が落ちるためです。ドキュメントの型を必ず確認してください。
  • 文字コード:JSONの文字コードはUTF-8が基本です。日本語が「譁�蟄怜喧縺�」のように化けたら、まず文字コードの指定を疑います。
一問一答
  1. JSONで文字列を囲むとき、シングルクォートは使えますか。
  2. 上の例で「鈴木花子の部署コード」を取り出す道すじを書いてください。
  3. null、空文字 ""0 の違いを説明してください。
解答を見る
  1. 使えない。JSONの文字列は必ずダブルクォートで囲む。
  2. users[1].department.code(= "K02")。配列は0から数えるため、2人目は[1]。
  3. nullは「値が無い・未設定」、""は「空という値がある」、0は「ゼロという数値がある」。たとえば在庫が null は「未調査」、0 は「品切れ」を意味しうる、まったく別の情報。
STEP 4 しくみ

ステータスコードとヘッダー ── 失敗の9割はここで分かる

目安 3日
このステップの到達点 ── 返ってきた3桁の数字を見て、「悪いのは自分か相手か」を即答できる。主要なヘッダーの役割を言え、Content-Type の指定ミスを自力で直せる。実務の切り分けは、ほぼこの2つで決まります。

ステータスコードは「百の位」で意味が決まる

細かい番号を暗記する必要はありません。百の位だけで、責任の所在が分かります

区分意味悪いのはまずやること
2xx成功結果を使う
3xx別の場所を見て(転送)転送先URLを確認。http://のままでないか
4xxあなたの頼み方が悪い自分URL・ヘッダー・ボディ・権限を見直す
5xx相手のサーバーの中で失敗した相手時間を置いて再送。続くなら相手に連絡

4xxを見て相手に問い合わせるのは恥ずかしい、と覚えてください。4xxは「あなたの依頼書の書き方が違う」という意味です。逆に5xxが続くなら、こちらでいくら直しても直りません。この一線を引けることが、実務での信頼につながります

これだけは覚える12個

コード名前意味よくある原因と対処
200OK成功
201Created作成できたPOSTの成功。Locationヘッダーに作られた場所が入る
204No Content成功したが返す中身なしDELETEの成功。ボディが空でも失敗ではない
301/302Moved / Found転送URLが変わった。curlは-Lを付けないと追わない
400Bad Request頼み方が不正JSONの書式ミス、必須項目の抜け
401Unauthorizedあなたが誰か分からない鍵が無い・間違い・期限切れ。ヘッダーの綴りも確認
403Forbidden誰かは分かるが、権限がないプランや権限設定の問題。鍵を変えても直らない
404Not Foundその住所は無いURLの綴り、バージョン(v1/v2)、IDの存在
405Method Not Allowedそのメソッドは使えないGETすべき所にPOSTしている等
409Conflictいまの状態と矛盾する重複登録、同時更新のぶつかり
422Unprocessable形式は合うが内容が不適切メール欄に電話番号、日付の範囲外など
429Too Many Requests叩きすぎレート制限。Retry-After秒待って再送(STEP 13)
500Internal Server Error相手の中で例外が起きた再送。続くなら相手に連絡(送った内容を添えて)
503Service Unavailable相手が一時的に受けられないメンテナンスや過負荷。間隔を空けて再送
401と403の違いは、面接でもよく聞かれます 401=「名乗ってください」(認証の問題)、403=「あなたには見せられません」(認可の問題)。401は鍵を直せば通りますが、403は鍵を何度直しても通りません。管理者に権限を付けてもらう必要があります。ここを取り違えると、何時間も無駄にします。

覚えておくべきヘッダー

ヘッダー向き役割よくある値
Content-Type両方ボディの形式を伝えるapplication/json
Accept送る返してほしい形式application/json
Authorization送る資格情報Bearer eyJhbGciOi...
User-Agent送る誰のプログラムかmy-batch/1.0 (ueki@example.jp)
Content-Length両方ボディの大きさ自動で付く
Location返る作られた場所・転送先/v1/users/12
Retry-After返る何秒待てばよいか30
X-RateLimit-Remaining返るあと何回叩けるか58
X-Request-Id返る問い合わせ用の通し番号7f3a...

X- で始まるものは、各社が独自に定めたヘッダーです。X-Request-Id は必ずログに残してください。相手のサポートに問い合わせるとき、この番号があるかないかで解決までの時間が何倍も変わります。

ステータスコードとヘッダーを実際に見る
# わざと404を返してもらう
curl -i "https://httpbin.org/status/404"

# ステータスコードだけを数字で取り出す(バッチ処理の判定でよく使う書き方)
curl -s -o /dev/null -w "%{http_code}\n" "https://httpbin.org/status/500"

# 自分が送ったヘッダーを、そのまま見せてもらう
curl -s "https://httpbin.org/headers" -H "X-My-Header: test123"

# 応答にかかった時間も測る
curl -s -o /dev/null -w "code=%{http_code} time=%{time_total}s\n" "https://httpbin.org/delay/2"
結果(例)
HTTP/1.1 404 NOT FOUND
Content-Type: text/html; charset=utf-8
Content-Length: 0

500
code=200 time=2.213145s

-i はヘッダーも一緒に表示するオプション、-w は好きな情報を書き出すオプションです。-o /dev/null -w "%{http_code}" の書き方は、実務のシェルスクリプトで頻出なので覚えておくと役立ちます。

200が返っても成功とは限りません 一部のAPIは、エラーでも200を返し、ボディの中に {"result":"error","message":"..."} と書いてきます。ステータスコードとボディの両方を確認するのが安全です。特に国内の古いシステムや、SOAP由来のAPIでよく見られます。
一問一答
  1. 401と403の違いを説明してください。
  2. 5xxが返り続けるとき、自分のコードを直せば解決しますか。
  3. 429が返ったとき、まず確認すべきヘッダーは何ですか。
解答を見る
  1. 401は「あなたが誰か分からない」=認証の失敗。403は「誰かは分かるが権限がない」=認可の失敗。403は鍵を直しても通らず、権限の付与が必要。
  2. 解決しない。5xxは相手のサーバー内部の問題。時間を置いて再送し、続くようなら送った内容とX-Request-Idを添えて相手に連絡する。
  3. Retry-After(何秒待つべきか)。あわせてX-RateLimit-*系で残り回数と上限も確認する。
STEP 5 しくみ

REST API ── いま最も普及している作法

目安 3日
このステップの到達点 ── RESTの考え方(リソース中心)を説明でき、エンドポイント一覧を見ただけで「これは何ができるAPIか」を推測できる。RESTでないAPI(SOAP・GraphQL・gRPC)との違いも一言で言える。

RESTとは「データを名詞として扱う」考え方

REST(レスト)は、規格ではなく設計の作法です。中心にある考え方はひとつだけ、「操作対象(リソース)をURLで表し、操作の種類はHTTPメソッドで表す」ことです。

作法に沿っていないAPIは、こう書かれます。

悪い例と良い例
✕ 動詞をURLに入れる(何でもPOST) POST /getUserInfo POST /createUser POST /deleteUser URLを見ても何ができるか分からない。 窓口の数が、機能の数だけ無限に増える。 ○ 名詞+メソッド(RESTの作法) GET /users 一覧を取る GET /users/12 1件取る POST /users 作る PATCH /users/12 一部を直す DELETE /users/12 消す 5つの型を覚えれば、どのリソースも同じように扱える。

RESTらしいURLの作り方(自社APIを作る側になったときも同じ)

  • リソース名は複数形の名詞/users/orders/invoices
  • 階層は「親/子」で表す/users/12/orders(12番の利用者の注文一覧)
  • 深い階層は2段まで:3段以上は分かりにくくなる。/orders?user_id=12 のほうがよい場合が多い
  • 絞り込み・並び替え・ページは、クエリで?status=paid&sort=-created_at&page=2
  • バージョンを先頭に置く/v1/users。仕様変更のとき、古い利用者を壊さずに済む
どうしても動詞が必要なとき 「送信する」「取り消す」「再計算する」のような、CRUDに収まらない操作はあります。その場合は、その操作を1つのリソースとみなすのが定石です。POST /orders/12/cancellationPOST /orders/12/actions/cancel のように書きます。原理主義に陥る必要はありません。チーム内で一貫していることのほうが大事です。

典型的なエンドポイント設計を、表で覚える

やりたいことメソッドURL成功時のコード返るもの
一覧を取るGET/v1/orders?status=paid&limit=20200配列+総件数
1件取るGET/v1/orders/1001200オブジェクト1つ
作るPOST/v1/orders201作られたもの+Location
まるごと更新PUT/v1/orders/1001200更新後のもの
一部更新PATCH/v1/orders/1001200更新後のもの
消すDELETE/v1/orders/1001204なし(空)
子を一覧GET/v1/users/12/orders200配列

REST以外の方式も、名前だけは知っておく

方式読み方特徴出会う場面
RESTレストURL+メソッド+JSON。学習コストが低いいちばん多い。まずこれを覚える
GraphQLグラフキューエル1つの窓口に「ほしい項目」を書いて頼む。取りすぎ・足りないが起きにくい画面が複雑なサービス、新しめの企業
gRPCジーアールピーシー速い。人間には読めない形式(バイナリ)社内のシステム同士、大規模基盤
SOAPソープXMLを使う古い方式。厳格で重い金融・保険・官公庁・古い基幹系
Webhookウェブフック向きが逆。相手から自分に通知が来る決済・チャット連携(STEP 13)

日本の企業システムでは、いまもSOAP・XML・固定長ファイルの連携が現役です。RESTだけが連携ではない、と知っておくと、現場で驚かずに済みます。

同じリソースを、メソッドを変えて一通り触る
# 一覧(絞り込みつき)
curl -s "https://jsonplaceholder.typicode.com/posts?userId=1&_limit=2"

# 1件取得
curl -s "https://jsonplaceholder.typicode.com/posts/1"

# 一部更新(PATCH)
curl -s -X PATCH "https://jsonplaceholder.typicode.com/posts/1" \
  -H "Content-Type: application/json" \
  -d '{"title":"題名だけ差し替え"}'

# 親子の関係(1番の投稿に付いたコメント一覧)
curl -s "https://jsonplaceholder.typicode.com/posts/1/comments?_limit=2"
一問一答
  1. RESTの中心にある考え方を一言で述べてください。
  2. POST /deleteUser?id=12 という設計の問題点を2つ挙げてください。
  3. POSTで作成が成功したとき、返るべきステータスコードと、確認すべきヘッダーは何ですか。
解答を見る
  1. 操作対象(リソース)をURLで表し、操作の種類はHTTPメソッドで表す。
  2. ①URLに動詞が入っており、エンドポイントが無限に増える。②削除なのにPOSTのため、意味(冪等性・安全性)がHTTPの規約と食い違い、途中の機器やライブラリの前提が崩れる。正しくは DELETE /users/12
  3. 201 Created。Location ヘッダーに、作成されたリソースのURLが入る。
STEP 6 しくみ

認証と認可 ── APIキー・Bearerトークン・OAuth 2.0

目安 5日(最重要)
このステップの到達点 ── 認証と認可の違いを説明でき、APIキー方式とOAuth方式を、ドキュメントを見て区別できる。アクセストークンとリフレッシュトークンの役割を言え、期限切れの扱いを設計できる。ここが実務でいちばん詰まる場所です。

認証(Authentication)と認可(Authorization)

言葉読み意味たとえ失敗時
認証にんしょう誰であるかを確かめる身分証を見せる401
認可にんか何をしてよいかを決める入館証で入れる階が決まる403

英語だとどちらも「Auth」で始まるため、略して AuthN(認証)/AuthZ(認可) と書き分けることがあります。ドキュメントで見かけたら思い出してください。

方式は、実務では4つに絞られる

方式送り方手軽さ使われる場面注意点
APIキーX-API-Key: abc123 または ?api_key=abc123◎ 簡単社内連携、単純な公開API漏れたら誰でも使える。URLに書く方式は履歴やログに残るので危険
Basic認証Authorization: Basic (ID:PWをBase64)古いシステム、社内ツールBase64は暗号化ではない。誰でも復元できる。HTTPS必須
BearerトークンAuthorization: Bearer eyJ...◎ 標準的いま最も多い有効期限がある。期限切れ時の処理が必要
OAuth 2.0手順を踏んでトークンを取得し、Bearerで送る△ 手順が多い他社サービスの利用者のデータを扱うとき登場人物が4者いる。混乱しやすい
Base64は暗号ではありません Basic認証の文字列は、誰でも一瞬で元に戻せます。「暗号化されているから安全」という説明を聞いたら、それは誤りです。安全性を担保しているのはHTTPS(通信路の暗号化)のほうです。

OAuth 2.0を、登場人物で理解する

OAuth 2.0(オーオース ツーテンゼロ)は、「パスワードを渡さずに、必要な権限だけを他社アプリに貸す」ためのしくみです。「〇〇でログイン」ボタンの裏側は、たいていこれです。

OAuth 2.0 の登場人物と流れ(認可コード方式)
① 利用者 サービスの使い手 ② あなたのアプリ クライアント ③ 認可サーバー ログイン画面 ④ リソースサーバー データを持つAPI ① 利用者を③の画面へ送る ② 利用者が「許可します」を押す ③ 認可コードを渡す ④ 認可コード+自分の秘密を送る ⑤ アクセストークンを発行 ⑥ Bearerトークンを付けて叩く ⑦ データが返る
  • ②(あなたのアプリ)は、利用者のパスワードを一度も受け取りません。だから安全で、利用者はいつでも許可を取り消せます。

ここで最も大事な点は、あなたのアプリは利用者のパスワードを一度も受け取らないことです。だから安全ですし、利用者はいつでも許可を取り消せます。「なぜOAuthが要るのか」と聞かれたら、この一点を答えてください

アクセストークンとリフレッシュトークン

種類有効期限役割扱い方
アクセストークン短い(1時間など)APIを叩くときに毎回付ける期限が切れたら作り直す。ログに出さない
リフレッシュトークン長い(数十日〜)アクセストークンを作り直すための引換券最重要機密。安全な場所に保管し、使い回さない

実装のときは、「401が返ったらリフレッシュして1回だけ再試行する」という定石をそのまま実装します。ここを毎回書くのは大変なので、公式SDKがある場合はSDKに任せるのが賢明です。

認証つきでAPIを叩く(4方式)
# ① APIキー(ヘッダーで送る。推奨)
curl -s "https://api.example.com/v1/users" \
  -H "X-API-Key: $API_KEY"

# ② Basic認証(curlが自動でBase64にしてくれる)
curl -s -u "myuser:mypassword" "https://api.example.com/v1/users"

# ③ Bearerトークン(いま最も多い形)
curl -s "https://api.example.com/v1/users" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

# ④ OAuth 2.0 でトークンを取る(クライアントクレデンシャル方式=機械同士の連携)
curl -s -X POST "https://api.example.com/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=$CLIENT_ID" \
  -d "client_secret=$CLIENT_SECRET"
④の返り(例)
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "users.read orders.read"
}

expires_in秒数です。3600なら1時間で切れます。受け取った時刻+expires_in を控えておき、期限前に作り直すのが定石です。scope は「この鍵でできること」の一覧で、認可の範囲を表します。

環境変数で鍵を扱う 上の例で $API_KEY と書いているのは、鍵をコマンドに直接書かないためです。export API_KEY="abc123"(Windows PowerShellなら $env:API_KEY="abc123")としてから実行します。直接書くと、シェルの履歴ファイルに平文で残ります。詳しくはSTEP 15で扱います。
JWT(ジェイダブリューティー)について Bearerトークンの中身が eyJ... で始まっていたら、それはJWT(JSON Web Token)です。ピリオドで3つに区切られ、真ん中に利用者IDや有効期限がJSONで入っています。Base64なので誰でも中身を読めます(改ざんは署名で防いでいるだけ)。JWTに個人情報やパスワードを入れてはいけません。中身は jwt.io のようなサイトで確認できますが、本番のトークンを他人のサイトに貼らないでください
一問一答
  1. 認証と認可の違いを、返るステータスコードとあわせて説明してください。
  2. OAuth 2.0を使う最大の利点は何ですか。
  3. リフレッシュトークンの役割と、扱い上の注意を述べてください。
解答を見る
  1. 認証は「誰か」を確かめること(失敗は401)、認可は「何をしてよいか」を決めること(失敗は403)。
  2. 利用者のパスワードを、連携するアプリ側に渡さずに済むこと。権限の範囲(scope)を限定でき、利用者がいつでも許可を取り消せる。
  3. 期限の短いアクセストークンを作り直すための引換券。長期間有効なため最重要機密として扱い、ログや画面に出さず、安全な場所(環境変数・秘密管理サービス)に保管する。
STEP 7 しくみ

curl ── プログラムを書く前に、手で叩けるようになる

目安 3日
このステップの到達点 ── curlの主要オプション10個を使い分けられ、ドキュメントのサンプルを自分の環境用に書き換えて実行できる。ここまで来ると、「動かない」ときに自分ひとりで原因までたどり着けます。

なぜ、まずcurlなのか

プログラムからAPIを呼んで失敗したとき、原因の候補は「リクエストの中身」「プログラムの書き方」「相手の状態」の3つあります。curlで手で叩いて成功すれば、原因はプログラム側だと確定します。逆にcurlでも失敗すれば、プログラムをいくら直しても無駄だと分かります。この切り分けができるかどうかが、初学者と実務者の分かれ目です。

覚えるべきオプション10個

オプション読み方・意味使う場面
-X POSTメソッドを指定GET以外を送るとき
-H "名前: 値"ヘッダーを付ける認証・形式指定。最頻出
-d '本文'ボディを送るPOST・PUT・PATCH
-i返ってきたヘッダーも表示ステータスコードを見たいとき
-v送受信のすべてを表示うまくいかないときの第一手
-s進捗表示を消す結果を他の道具に渡すとき
-o ファイル名結果をファイルに保存大きな結果、後で確認したいとき
-L転送(3xx)を追う301/302が返るとき
--max-time 3030秒で打ち切る本番のバッチでは必須
-u ID:PWBasic認証古いAPI
実務でそのまま使える形(雛形)
# 【雛形】これをコピーして、URLとヘッダーだけ差し替える
curl -s -i --max-time 30 \
  -X POST "https://api.example.com/v1/orders" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"product_id":"A-100","quantity":2}'

# 長いJSONは、ファイルに書いて渡すほうが確実(@はファイル指定の意味)
curl -s -X POST "https://api.example.com/v1/orders" \
  -H "Content-Type: application/json" \
  -d @order.json

# クエリに日本語や記号が入るときは、curlに変換させる(-G はGETで送る指定)
curl -s -G "https://api.example.com/v1/search" \
  --data-urlencode "q=東京 支店" \
  --data-urlencode "limit=10"
Windowsのコマンドプロンプトでの落とし穴 Windowsの cmd では、シングルクォート(')が使えません。JSONを送るときはダブルクォートを使い、中のダブルクォートを \" と書く必要があります(例:-d "{\"id\":1}")。面倒なので、WindowsではPowerShellを使うか、JSONをファイルにして -d @file.json で渡すのが実務上の解決策です。改行を続ける記号も、cmdは ^、PowerShellは `(バッククォート)で、Mac/Linuxの \ とは違います。

うまくいかないときの手順(この順番で)

  1. 1. -v を付けるまず curl -v自分が実際に何を送ったかを見る。ここで解決することが非常に多い
  2. 2. コードを見る4xxなら自分、5xxなら相手(STEP 4)。ここで調べる方向が決まる
  3. 3. ボディを読むエラーの本文に理由が書いてある。{"error":{"message":"..."}} を必ず読む
  4. 4. ヘッダーを疑うAuthorization の綴り、Bearer の後の半角空白、鍵の前後の改行や空白
  5. 5. URLを疑う末尾のスラッシュ、バージョン(v1/v2)、本番と検証(sandbox)の取り違え
  6. 6. 通信の外側を疑う社内プロキシ、ファイアウォール、IP制限(相手側の許可リストに自社IPが入っているか)
切り分けに使う小技
# 通信の詳細だけを見て、本文は捨てる
curl -v -o /dev/null "https://api.example.com/v1/ping"

# 応答が遅いのか、処理が遅いのかを測る
curl -s -o /dev/null -w "接続:%{time_connect}s 初回応答:%{time_starttransfer}s 合計:%{time_total}s\n" \
  "https://api.example.com/v1/orders"

# 証明書の問題を確認する(-k は検証を無視。原因調査のときだけ使う)
curl -v -k "https://api.example.com/v1/ping"

# プロキシ越しに叩く(社内ネットワークでよく必要になる)
curl -s -x "http://proxy.example.co.jp:8080" "https://api.example.com/v1/ping"
-k を本番で使ってはいけません -k--insecure)は、通信相手が本物かどうかの確認を飛ばすオプションです。原因調査で「証明書が原因か」を確かめるときだけ使い、本番のプログラムには絶対に残さないでください。中間者攻撃(通信を横取りされる攻撃)を防げなくなります。
ブラウザからcurlコマンドを作れます Chromeの開発者ツール(F12)→「ネットワーク」タブ→対象の通信を右クリック→「Copy as cURL」。いま見ている画面が裏で叩いているリクエストが、そのまま実行できるcurlコマンドとして手に入ります。他社APIの挙動を調べるときの、最も実用的な技のひとつです。
一問一答
  1. プログラムでAPI呼び出しが失敗したとき、curlで叩いてみると何が分かりますか。
  2. -v-i の違いを説明してください。
  3. 本番のバッチ処理で --max-time を必ず付けるべき理由は何ですか。
解答を見る
  1. 原因がリクエストの中身にあるのか、プログラムの書き方にあるのかを切り分けられる。curlで成功すればプログラム側、curlでも失敗すればリクエストか相手側の問題。
  2. -iは「返ってきたヘッダー+本文」を表示する。-vは「送った内容と返ってきた内容の両方」を通信の詳細まで表示する。原因調査では-v
  3. 相手が応答を返さないとき、処理が永久に止まってしまうため。上限を決めておかないと、バッチが翌日まで終わらない、後続処理が全部止まる、といった事故になる。
STEP 8 しくみ

APIドキュメントの読み方 ── OpenAPIとPostman

目安 3日
このステップの到達点 ── 初めて見るAPIドキュメントを、決まった順番で読んで15分で1回目の呼び出しにたどり着ける。OpenAPI(Swagger)の画面から必要な情報を拾え、Postmanで試験と共有ができる。

ドキュメントは、この順番で読む

どの会社のAPIドキュメントも、載っている項目はほぼ同じです。読む順番を固定しておくと、初見でも迷いません

  1. 1. 認証「Authentication」の節。ここを最初に読む。鍵の取り方と、送り方(ヘッダー名)を確認
  2. 2. 基点URL「Base URL」。本番と検証(sandbox / staging)でURLが違うことに注意
  3. 3. クイックスタート「Getting Started」の最初のサンプルをそのままコピーして実行。まず1回成功させる
  4. 4. エンドポイント一覧「API Reference」。目的の機能を探す。目次だけ眺めて全体像をつかむ
  5. 5. 制限「Rate Limits」。1分あたり何回まで叩けるか。ここを読まずに作ると本番で止まる
  6. 6. エラー「Errors」。返るコードの一覧と、独自エラーコードの意味
  7. 7. 変更履歴「Changelog」。いつ仕様が変わるか。廃止予定(deprecated)の項目に注意
まず1回成功させることを最優先に 全部を読んでから作り始めるのは、遠回りです。クイックスタートの1本を成功させてから、必要な部分だけ読み進めてください。1本通っていれば、認証・URL・形式がすべて正しいと確定しているので、あとは中身を変えるだけになります。

OpenAPI(Swagger)── 機械が読める仕様書

OpenAPI(オープンエーピーアイ/旧称Swagger)は、APIの仕様をYAMLやJSONで書いた設計図です。これがあると、次のことが自動でできます。

  • ブラウザでそのまま試せる画面(Swagger UI)が生成される
  • 各言語の呼び出しコードが自動生成できる
  • Postmanなどの道具にまるごと読み込める
openapi.yaml(読み方のポイントだけ)
openapi: 3.0.3
info:
  title: 受注管理API          # このAPIの名前
  version: "1.0.0"
servers:
  - url: https://api.example.com/v1     # ← 基点URL(本番)
  - url: https://sandbox.example.com/v1 # ← 検証環境
paths:
  /orders:                    # ← エンドポイント
    get:                      # ← メソッド
      summary: 注文の一覧を取得する
      parameters:
        - name: status
          in: query           # ← クエリパラメータ(in: path ならパス)
          required: false
          schema: { type: string, enum: [pending, paid, shipped] }
      responses:
        "200":
          description: 成功
          content:
            application/json:
              schema:
                type: array
                items: { $ref: "#/components/schemas/Order" }
        "401": { description: 認証エラー }
components:
  schemas:
    Order:
      type: object
      required: [id, status]   # ← 必ず入っている項目
      properties:
        id:       { type: integer, example: 1001 }
        status:   { type: string,  example: "paid" }
        amount:   { type: number,  example: 12000 }
        note:     { type: string,  nullable: true }  # ← null が来る可能性あり
ここだけ見れば実装できる
① servers          → どこに送るか
② paths のキー      → URL(/orders)
③ その下のメソッド   → get / post / patch …
④ parameters       → 送れる条件(in: query か in: path か)
⑤ requestBody      → 送るJSONの形(POST・PATCHのとき)
⑥ responses の 200 → 返ってくるJSONの形
⑦ required / nullable → 必須項目と、nullが来る項目 ★実装で最重要

required に無い項目は、返ってこないことがありますnullable: true の項目は null が入ります。この2つを見落とすと、STEP 11で扱う「項目が無くて落ちる」不具合になります。

Postman ── 試して、記録して、共有する

Postman(ポストマン)は、APIを画面上で試すための道具です。curlと同じことができますが、チームで共有できる点が実務では決定的に便利です。

機能何ができるか実務での価値
コレクションリクエストを整理して保存「この案件で使うAPI一式」をチームに渡せる
環境変数{{base_url}}{{token}} で差し替え検証と本番をボタン1つで切り替え。鍵をコードに書かずに済む
インポートOpenAPIやcurlを読み込むドキュメントから一瞬で試験環境が作れる
コード生成各言語のコードを書き出す動作確認できた形を、そのまま実装に移せる
テスト返り値の検証を自動化仕様変更の検知(STEP 14)
Postmanで気をつけること本番の鍵をコレクションに直接書いて共有しない(環境変数に入れ、共有対象から外す)。②クラウド同期をONにすると、入力した鍵が社外のサーバーに保存されます。会社の規程を必ず確認してください。③無料の「オンラインAPIテストサイト」に本番データを貼るのも同じ理由で危険です。

ドキュメントが無い・古いとき(実務ではよくある)

社内システムや古い連携先では、ドキュメントが存在しない、あっても実物と食い違うことが日常的にあります。そのときの手順です。

  • まず実物を叩いて、返ってきたJSONを保存する。それが最も正しい仕様書になります
  • ブラウザの開発者ツールで、既存画面が叩いている通信を観察する
  • 相手の担当者に聞くときは、「叩いたURL・送った内容・返ってきたコードと本文・X-Request-Idをそろえて聞く。これがあるかないかで、返答の速さがまるで違います
  • 分かったことは、自分でOpenAPIかMarkdownに書き起こして残す。次の担当者を救い、自分の評価にもつながります
一問一答
  1. 初めてのAPIドキュメントで、最初に読むべき節はどこですか。
  2. OpenAPIの requirednullable は、実装のとき何を意味しますか。
  3. ドキュメントが実物と食い違っているとき、どちらを正としますか。
解答を見る
  1. 認証(Authentication)。鍵の取得方法と送り方が分からないと、何ひとつ叩けないため。次に基点URLとクイックスタート。
  2. requiredに無い項目は返ってこない可能性があり、nullable: trueの項目はnullが来る可能性がある。どちらも、そのまま値を取り出すと落ちるため、存在確認や既定値の用意が必要。
  3. 実物(実際に返ってきたレスポンス)。ただし、実物が仕様外の異常動作である可能性もあるため、食い違いは必ず相手に確認し、記録に残す。
STEP 9 実装

JavaScriptのfetch ── ブラウザからAPIを呼ぶ

目安 5日
このステップの到達点 ── fetchasync/await を使って、取得・作成・エラー処理まで書ける。「fetchは404でも例外を投げない」という落とし穴を知り、正しく判定できる。CORSエラーの意味と、正しい対処を説明できる。

いちばん短い形

GET:データを取ってきて表示する
// async を付けた関数の中では await が使える
async function getUser(id) {
  const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);

  // ★重要:fetch は 404 や 500 でも例外を投げない。自分で確かめる
  if (!res.ok) {
    throw new Error(`APIエラー: ${res.status} ${res.statusText}`);
  }

  const data = await res.json();   // JSON文字列を、扱える形に変換する
  return data;
}

// 呼び出す側。失敗する前提で try/catch を必ず書く
async function main() {
  try {
    const user = await getUser(1);
    console.log(user.name, user.address.city);
  } catch (err) {
    console.error("取得に失敗しました:", err.message);
  }
}
main();
初学者が100%踏む落とし穴 fetch は、404や500が返ってきても「通信としては成功」とみなし、例外を投げません。例外になるのは、ネットワークが切れている、URLが解決できない、CORSで拒否された、といったそもそも届かなかった場合だけです。if (!res.ok) を書き忘れると、エラーのHTMLをJSONとして読もうとして、意味不明なエラーになります

POSTで送る

POST:JSONを送って作成する
async function createPost(title, body) {
  const res = await fetch("https://jsonplaceholder.typicode.com/posts", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",        // 送る形式を伝える
      "Accept": "application/json",
      // "Authorization": `Bearer ${token}`      // 認証が要るAPIではこれを足す
    },
    body: JSON.stringify({ title, body, userId: 1 })  // ★オブジェクトを文字列に変換
  });

  if (!res.ok) {
    // エラーの本文にも、たいてい理由が書いてある。読まずに捨てない
    const text = await res.text();
    throw new Error(`${res.status}: ${text}`);
  }
  return await res.json();
}

忘れやすい点が2つあります。①body には文字列を渡す(JSON.stringify が必要)。②Content-Type を書かないと、相手が形式を判断できず400や415が返ります。この2つで、初学者のPOSTの失敗はほぼ説明がつきます

タイムアウトを付ける(実務では必須)

fetch には既定のタイムアウトがありません。相手が黙り込むと永久に待ち続けますAbortSignal で必ず上限を付けてください。

10秒で打ち切る
async function fetchWithTimeout(url, options = {}, ms = 10000) {
  const ctrl = new AbortController();
  const timer = setTimeout(() => ctrl.abort(), ms);
  try {
    return await fetch(url, { ...options, signal: ctrl.signal });
  } catch (err) {
    if (err.name === "AbortError") {
      throw new Error(`${ms}ミリ秒以内に応答がありませんでした`);
    }
    throw err;
  } finally {
    clearTimeout(timer);   // 成功しても失敗しても、必ず後片付けする
  }
}

// 新しい環境なら、これだけでも書ける
// const res = await fetch(url, { signal: AbortSignal.timeout(10000) });

CORS ── ブラウザ特有の壁

CORS(コルス)は、ブラウザが持っている安全装置です。「Aというサイトで開いているページが、Bという別のサイトのAPIを勝手に呼ぶ」ことを、既定で禁止しています。これがないと、あなたが開いた悪意あるページが、あなたのログイン済み社内システムを裏で操作できてしまいます。

CORSで拒否されるしくみ
ブラウザ mysite.example.jp を表示中 相手のサーバー api.other.com ① OPTIONS(プリフライト) ② 許可ヘッダーを返す(返さない) 許可があれば通す fetchの結果を受け取れる 無ければブラウザが遮断 サーバーには届いていることも
  • 遮断しているのは「ブラウザ」です。だからcurlやPythonでは成功するのに、ブラウザからだけ失敗します。
状況正しい対処やってはいけない対処
自社のAPIを自社サイトから呼ぶAPIサーバー側に Access-Control-Allow-Origin を設定するブラウザの安全機能を切る拡張機能を常用する
他社APIをブラウザから呼びたい自社サーバーを経由させる(サーバーからAPIを呼び、結果を画面に返す)公開の「CORS回避サービス」を業務データで使う
認証が必要な他社API必ずサーバー経由。鍵をブラウザに置かないJavaScriptにAPIキーを直接書く(全員に見えます
ブラウザのJavaScriptに、APIキーを書いてはいけません ページのソースは誰でも表示できます。「難読化したから大丈夫」も通用しません。秘密の鍵が要るAPIは、必ずサーバー側から呼ぶ。これはAPI連携の最重要の原則のひとつで、実際に多くの情報漏えい事故がここで起きています。
並行して取る 3つのAPIを順番に待つと、3回分の時間がかかります。互いに依存しないなら Promise.all でまとめて投げると、いちばん遅い1本の時間で済みます。ただし相手のレート制限(STEP 13)に注意してください。一部失敗を許容したい場合は Promise.allSettled を使います。
一問一答
  1. fetchは404のときに例外を投げますか。どう判定すべきですか。
  2. POSTでJSONを送るとき、必ず必要な2つのことは何ですか。
  3. curlでは成功するのにブラウザだけCORSエラーになるのは、なぜですか。
解答を見る
  1. 投げない。res.ok(またはres.status)を自分で確認して判定する。
  2. JSON.stringifyでボディを文字列にすること、②Content-Type: application/jsonヘッダーを付けること。
  3. CORSはブラウザが持つ安全装置で、遮断しているのはブラウザだから。curlやサーバー側のプログラムにはこの仕組みがないため、そのまま通る。
STEP 10 実装

フォームからAPIへ ── 入力・検証・送信・表示のひと続き

目安 5日
このステップの到達点 ── 画面のフォームから受け取った値を、検証してJSONに組み立て、APIに送り、結果を画面に返すまでを一人で書ける。二重送信の防止と、利用者に伝わるエラー表示ができる。実務の依頼の半分は、この形です。

フォーム送信の6段階

  1. 1. 既定動作を止めるe.preventDefault()。これを忘れると画面が再読み込みされ、何も起きていないように見える
  2. 2. 値を取り出すnew FormData(form) で、入力欄の値をまとめて受け取る
  3. 3. 検証する必須・形式・桁数を送る前に確かめる。サーバー側の検証も必須(画面の検証は迂回できる)
  4. 4. ボタンを止める送信中はボタンを無効化。これが二重送信を防ぐ最も基本的な手当て
  5. 5. 送るfetchでPOST。タイムアウトを付ける
  6. 6. 結果を出す成功・失敗のどちらも利用者の言葉で表示し、ボタンを戻す
form.html:入力フォーム
<form id="contactForm" novalidate>
  <label for="name">お名前</label>
  <input id="name" name="name" type="text" required maxlength="40">

  <label for="email">メールアドレス</label>
  <input id="email" name="email" type="email" required>

  <label for="qty">数量</label>
  <input id="qty" name="qty" type="number" min="1" max="99" value="1">

  <label for="message">お問い合わせ内容</label>
  <textarea id="message" name="message" rows="5" required></textarea>

  <button type="submit" id="submitBtn">送信する</button>
  <p id="formMsg" role="status" aria-live="polite"></p>
</form>

aria-live="polite" を付けておくと、送信結果が読み上げ環境でも伝わりますlabelid をひも付けるのも同じ理由で、実務では必ず求められます。

form.js:検証してAPIに送る
const form = document.getElementById("contactForm");
const btn  = document.getElementById("submitBtn");
const msg  = document.getElementById("formMsg");

form.addEventListener("submit", async (e) => {
  e.preventDefault();                       // ① 画面の再読み込みを止める

  const fd = new FormData(form);            // ② 値をまとめて取り出す
  const payload = {
    name:    String(fd.get("name")  || "").trim(),
    email:   String(fd.get("email") || "").trim(),
    qty:     Number(fd.get("qty")   || 1),
    message: String(fd.get("message") || "").trim()
  };

  const error = validate(payload);           // ③ 送る前に検証する
  if (error) { show(error, "ng"); return; }

  btn.disabled = true;                       // ④ 二重送信を防ぐ
  show("送信しています…", "");

  try {                                      // ⑤ 送る
    const res = await fetch("/api/contacts", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(payload),
      signal: AbortSignal.timeout(15000)
    });

    if (res.status === 422 || res.status === 400) {
      const err = await res.json();          // 相手が返した項目別エラーを使う
      show(err.message || "入力内容をご確認ください。", "ng");
      return;
    }
    if (!res.ok) throw new Error(`status ${res.status}`);

    const data = await res.json();           // ⑥ 結果を出す
    show(`受け付けました(受付番号: ${data.id})`, "ok");
    form.reset();

  } catch (err) {
    // 利用者には分かる言葉で、開発者にはログで詳細を
    console.error(err);
    show("送信できませんでした。時間をおいて、もう一度お試しください。", "ng");
  } finally {
    btn.disabled = false;                    // 成功でも失敗でも必ず戻す
  }
});

function validate(v) {
  if (!v.name)                       return "お名前を入力してください。";
  if (v.name.length > 40)            return "お名前は40文字以内で入力してください。";
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v.email))
                                     return "メールアドレスの形式をご確認ください。";
  if (!Number.isInteger(v.qty) || v.qty < 1 || v.qty > 99)
                                     return "数量は1〜99の整数で入力してください。";
  if (!v.message)                    return "お問い合わせ内容を入力してください。";
  return null;
}

function show(text, kind) {
  msg.textContent = text;
  msg.className = kind ? `is-${kind}` : "";
}
画面側の検証だけでは守れません ブラウザの検証は、開発者ツールで簡単に迂回できます。受け取るサーバー側でも、必ず同じ検証をしてください。画面側の検証は「利用者に親切に知らせるため」、サーバー側の検証は「システムを守るため」と、目的がまったく違います。

ファイルを送るときは形式が変わる

画像やPDFを送る場合、JSONではなく multipart/form-data という形式を使います。このとき Content-Type を自分で書いてはいけません。ブラウザが区切り文字(boundary)を含めて自動で付けるためです。

ファイル付きの送信
const fd = new FormData();
fd.append("title", "請求書");
fd.append("file", document.getElementById("file").files[0]);

const res = await fetch("/api/uploads", {
  method: "POST",
  body: fd            // ★ headers は書かない(ブラウザが自動で正しく付ける)
});
ここで実際に試せます このページの下のほう「手を動かす道具」に、入力した内容から実際のcurlコマンドとfetchコードを組み立てるフォームを置きました。上で学んだ検証・組み立ての流れが、そのまま動く形で確認できます。
一問一答
  1. フォームのsubmitで e.preventDefault() を書かないと、何が起きますか。
  2. ブラウザ側で検証しているのに、サーバー側でも検証が必要なのはなぜですか。
  3. ボタンの無効化を finally で戻すのはなぜですか。
解答を見る
  1. フォームの既定動作でページが再読み込みされ、JavaScriptの処理が途中で消える(何も起きていないように見える)。
  2. 画面の検証は開発者ツールなどで簡単に迂回できるため。サーバー側の検証がないと、不正な値がそのまま登録されたり、攻撃の入口になったりする。
  3. 成功・失敗・例外のどの経路を通っても必ず実行されるため。tryの中だけで戻すと、エラー時にボタンが押せないままになる。
STEP 11 実装

Pythonのrequests ── 業務バッチとして動かす

目安 5日
このステップの到達点 ── Pythonで取得・作成・認証・タイムアウトを書け、毎朝自動で動く取り込み処理の骨格を組める。鍵を環境変数から読む書き方が身につく。サーバー側の実装は、ほぼこの形です。

準備と、いちばん短い形

導入
# 作業用のフォルダを作り、その中だけで使う環境を用意する(推奨)
python3 -m venv .venv
source .venv/bin/activate        # Windowsは .venv\Scripts\activate
pip install requests
get_users.py:取得して表示する
import os
import requests

BASE = "https://jsonplaceholder.typicode.com"

def get_user(user_id: int) -> dict:
    url = f"{BASE}/users/{user_id}"
    # timeout は (接続, 読み取り) の秒数。★必ず付ける
    res = requests.get(url, timeout=(3.0, 10.0))
    res.raise_for_status()        # 4xx・5xx なら例外を投げてくれる
    return res.json()

if __name__ == "__main__":
    try:
        user = get_user(1)
        print(user["name"], user["address"]["city"])
    except requests.exceptions.Timeout:
        print("時間内に応答がありませんでした")
    except requests.exceptions.HTTPError as e:
        print(f"APIエラー: {e.response.status_code} {e.response.text[:200]}")
    except requests.exceptions.RequestException as e:
        print(f"通信エラー: {e}")

raise_for_status() は、fetchと違って4xx・5xxを例外にしてくれる便利な一行です。ただしこれを書き忘れると、fetchと同じ落とし穴に落ちます。例外は「細かいものから順に」捕まえるのが決まりで、RequestException は最後に置きます。

認証つきで、まとめて叩く(Session)

同じ相手に何度も叩くときは Session を使います。接続を使い回すので速くなり、共通ヘッダーを1か所に書けます。

client.py:実務で使う骨格
import os
import requests

class ApiClient:
    def __init__(self):
        # ★鍵はコードに書かず、環境変数から読む(STEP 15)
        token = os.environ.get("EXAMPLE_API_TOKEN")
        if not token:
            raise RuntimeError("環境変数 EXAMPLE_API_TOKEN が設定されていません")

        self.base = os.environ.get("EXAMPLE_API_BASE", "https://api.example.com/v1")
        self.s = requests.Session()
        self.s.headers.update({
            "Authorization": f"Bearer {token}",
            "Accept": "application/json",
            # 誰からの通信か分かるようにしておく(相手のサポートに好まれる)
            "User-Agent": "kodomo-batch/1.0 (system@example.co.jp)",
        })

    def get(self, path: str, **params) -> dict:
        res = self.s.get(f"{self.base}{path}", params=params, timeout=(3.0, 30.0))
        res.raise_for_status()
        return res.json()

    def post(self, path: str, payload: dict) -> dict:
        # json= を使うと Content-Type: application/json が自動で付く
        res = self.s.post(f"{self.base}{path}", json=payload, timeout=(3.0, 30.0))
        res.raise_for_status()
        return res.json()

if __name__ == "__main__":
    api = ApiClient()
    orders = api.get("/orders", status="paid", limit=20)   # → ?status=paid&limit=20
    print(f"{len(orders)}件 取得しました")
params=json= に任せる クエリ文字列を自分で "?status=" + s のようにつなぐと、日本語や記号のときに壊れます。params= に辞書を渡せば、URLエンコードを自動でやってくれます。同じく json= を使えば、json.dumpsContent-Type の両方が自動になります。手で組み立てないことが、事故を減らす最短路です。

取り込んで、保存するところまで

daily_import.py:毎朝動かす形
import csv
import logging
from datetime import datetime, timezone, timedelta

JST = timezone(timedelta(hours=9))     # ★時差の取り違えは定番の不具合

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[logging.FileHandler("import.log", encoding="utf-8"),
              logging.StreamHandler()],
)
log = logging.getLogger(__name__)

def main():
    api = ApiClient()
    today = datetime.now(JST).strftime("%Y-%m-%d")
    log.info("取り込み開始 date=%s", today)

    try:
        orders = api.get("/orders", date=today, limit=100)
    except Exception:
        log.exception("取得に失敗しました")   # 例外の詳細もログに残す
        raise                                 # 異常終了させ、監視で気づけるようにする

    # 相手の項目名を、自社の項目名に置き換えて保存する
    with open(f"orders_{today}.csv", "w", newline="", encoding="utf-8-sig") as f:
        w = csv.writer(f)
        w.writerow(["注文番号", "金額", "状態", "備考"])
        for o in orders:
            w.writerow([
                o.get("id"),
                o.get("amount", 0),
                o.get("status", "unknown"),
                o.get("note") or "",        # null のとき空文字にする
            ])

    log.info("取り込み完了 件数=%d", len(orders))

if __name__ == "__main__":
    main()
ここに実務の勘所が3つ入っています
① o.get("amount", 0)   … 項目が無くても落ちない書き方(o["amount"] は落ちる)
② o.get("note") or ""  … null のときに空文字へ置き換える
③ encoding="utf-8-sig" … Excelで開いたときに日本語が化けない書き出し方

③は地味ですが、「渡したCSVがExcelで文字化けする」という指摘は実務で非常に多いため、覚えておく価値があります。

定期実行のしかた できあがったスクリプトは、Linuxなら cron、Windowsなら「タスクスケジューラ」、クラウドなら各社のスケジューラで定期実行します。そのとき①必ずログをファイルに残す、②失敗したら気づける仕掛け(通知やメール)を入れる、③同じ時刻に二重起動しないようにするの3点を必ず設計してください。動かしっぱなしで誰も見ていないバッチは、いつか必ず事故になります。
一問一答
  1. requests.get(url)timeout を付けないと、どんな危険がありますか。
  2. o["amount"] ではなく o.get("amount", 0) と書くのはなぜですか。
  3. APIの鍵をソースコードに直接書いてはいけない理由を述べてください。
解答を見る
  1. 相手が応答を返さない場合、処理が永久に待ち続ける。バッチが終わらず、後続処理や翌日の実行まで止まる事故になる。
  2. その項目が返ってこない場合、o["amount"]は例外で処理全体が止まるため。getなら既定値を使って処理を続けられる。
  3. コードは共有・保存・バージョン管理されるため、鍵が社内外に広く残ってしまう。特にGitへ入れると履歴から消すのが困難で、公開リポジトリなら数分で悪用される。環境変数や秘密管理サービスから読む。
STEP 12 実装

エラー処理とリトライ ── 「たまに失敗する」を前提に作る

目安 4日
このステップの到達点 ── 再試行してよい失敗と、してはいけない失敗を区別できる。指数バックオフを実装でき、二重登録を防ぐ冪等キーの使い方を説明できる。ここから先が「実務で使えるコード」です。

通信は、必ず失敗する

ネットワークを越える処理は、ときどき失敗するのが正常です。相手のサーバーの再起動、一瞬の混雑、経路の切り替え。年に数回ではなく、1万回叩けば数回は失敗します。だから実務のコードは、失敗したときにどうするかを最初から書きます。

状況再試行理由やること
タイムアウト・接続切れする一時的な可能性が高い間隔を空けて再試行
429(叩きすぎ)する待てば通るRetry-Afterの秒数だけ待つ
500・502・503・504する相手側の一時的な不調指数バックオフで数回
400・422(内容が不正)しない何度送っても同じ結果ログに残して人に知らせる
401・403(資格・権限)原則しない鍵や権限の問題401はトークン更新後に1回だけ再試行
404(存在しない)しないURLかIDが違う設定を確認
POST(作成)の失敗要注意二重登録の危険冪等キーを使う(後述)

指数バックオフ ── 待ち時間を倍々にする

失敗してすぐ再送すると、相手がまだ回復しておらず、また失敗します。全員が同時に再送すると、相手を完全に停止させることさえあります。そこで、1秒 → 2秒 → 4秒 → 8秒 と待ち時間を倍にしていきます。これを指数バックオフと呼びます。

さらに、そこにランダムなばらつき(ジッター)を足すのが実務の定石です。全員がきっちり同じ秒数で再送すると、また同時に殺到してしまうためです。

retry.py:実務でそのまま使える再試行
import random
import time
import requests

RETRYABLE = {429, 500, 502, 503, 504}      # 再試行してよいコード

def request_with_retry(session, method, url, max_attempts=4, **kwargs):
    kwargs.setdefault("timeout", (3.0, 30.0))

    for attempt in range(1, max_attempts + 1):
        try:
            res = session.request(method, url, **kwargs)

            if res.status_code not in RETRYABLE:
                res.raise_for_status()      # 成功、または再試行しないエラー
                return res

            # 相手が「何秒待て」と言っているなら、それに従う(最優先)
            wait = float(res.headers.get("Retry-After", 0)) or _backoff(attempt)

        except (requests.exceptions.Timeout,
                requests.exceptions.ConnectionError):
            wait = _backoff(attempt)        # 届かなかった場合も再試行の対象

        if attempt == max_attempts:
            raise RuntimeError(f"{max_attempts}回試しましたが失敗しました: {url}")

        print(f"{attempt}回目が失敗。{wait:.1f}秒待って再試行します")
        time.sleep(wait)

def _backoff(attempt: int) -> float:
    base = 2 ** (attempt - 1)               # 1, 2, 4, 8 秒
    return base + random.uniform(0, 0.5)    # ばらつきを足して、殺到を防ぐ
再試行の回数と合計時間に、必ず上限を 「成功するまで無限に再試行」は事故のもとです。相手が長時間停止していると、永久に終わらないバッチができあがります。最大4〜5回、合計1分程度を目安に上限を決め、超えたら諦めて人に知らせる。これが正しい設計です。

冪等キー ── 二重登録を根本から防ぐ

POSTの再試行が怖いのは、「相手は成功していたのに、返事だけが届かなかった」場合があるからです。このとき再送すると、注文が2件できます。

返事だけが失われるパターン
あなた 相手 ▼ 起こりうること POST /orders 相手は注文を登録した(成功している) ✕ 返事が届かない(切断) 成功したか分からない → もう一度送る ★ 2件目の注文ができてしまう ▼ 解決 POST /orders + Idempotency-Key: 9f2c… 「処理済み」と判断し、1件目の結果を返す(登録は1件のまま)
冪等キーの付け方
import uuid

# ★鍵は「1つの注文につき1つ」。再試行のたびに作り直してはいけない
key = str(uuid.uuid4())

res = request_with_retry(
    session, "POST", f"{BASE}/orders",
    headers={"Idempotency-Key": key},
    json={"product_id": "A-100", "quantity": 2},
)

鍵を作る場所が重要です。再試行のループの中で作ると、毎回違う鍵になり、意味がなくなります。「1つの業務上の依頼=1つの鍵」と考えてください。相手のAPIが冪等キーに対応していない場合は、送信前に「同じ内容の登録が既にないか」を確認する処理を自分で入れます。

エラーを「人に伝わる形」で残す

エラーログに Error とだけ書いても、翌朝の担当者は何もできません。次の5点は必ず残してください

  • いつ(時刻。タイムゾーンつき)
  • どこに(メソッドとURL。ただし鍵やトークンは伏せる
  • 何が返ったか(ステータスコードと、本文の先頭200文字程度)
  • X-Request-Id(相手に問い合わせるときの決め手)
  • どの業務データか(注文番号など、こちらの識別子)
残すべきログの形
log.error(
    "API失敗 method=%s url=%s status=%s request_id=%s order_id=%s body=%s",
    "POST", url, res.status_code,
    res.headers.get("X-Request-Id", "-"),
    order_id,
    res.text[:200],          # 全部は出さない(個人情報と容量に配慮)
)
ログに書いてはいけないもの トークン、APIキー、パスワード、クレジットカード番号、個人情報の全体。ログは、開発者以外の目にも触れ、長期間残ります。「調査のために全部出しておこう」が、そのまま情報漏えいになります。出すなら先頭4文字だけなど、伏せた形にしてください。
一問一答
  1. 再試行してよいエラーと、してはいけないエラーを、それぞれ2つ挙げてください。
  2. 待ち時間にランダムなばらつきを足すのはなぜですか。
  3. 冪等キーを、再試行のたびに新しく作ってはいけないのはなぜですか。
解答を見る
  1. してよい:429、500系(502・503・504)、タイムアウト、接続断。してはいけない:400、422、404(何度送っても同じ結果)。
  2. 全員が同じ秒数で再送すると、回復しかけた相手に同時に殺到して再び落としてしまうため。ばらつきで送信タイミングを散らす。
  3. 鍵が毎回変わると、相手は「別の依頼」として扱い、二重登録が起きるため。1つの業務上の依頼につき1つの鍵を使い続ける。
STEP 13 運用

大量データの扱い ── ページネーションとレート制限

目安 4日
このステップの到達点 ── 1万件のデータを、相手に迷惑をかけずに全件取得できる。3種類のページ送り方式を見分けられ、差分取得という考え方で処理を軽くできる。

APIは、一度に全部を返さない

10万件の注文がある相手に GET /orders と頼んでも、10万件は返ってきません。ふつうは20件、100件といった単位で区切られます。これをページネーション(ページ送り)と呼びます。全件ほしいときは、繰り返し取りに行く必要があります。

方式見分け方長所短所
ページ番号?page=2&per_page=100分かりやすい。特定ページに飛べる取得中にデータが増えるとずれる・重複する
オフセット?offset=200&limit=100同上同上。件数が多いと相手の処理が重い
カーソル?cursor=eyJpZCI6MTAwfQずれない。大量データに強い途中のページに飛べない

近年のAPIはカーソル方式が主流です。返り値に next_cursornexthas_more といった項目があれば、それがカーソル方式の目印です。

全件を取りきる(カーソル方式)
def fetch_all(api, path, **params):
    items, cursor, page = [], None, 0
    MAX_PAGES = 1000                       # ★暴走を止める安全装置

    while True:
        page += 1
        if page > MAX_PAGES:
            raise RuntimeError("ページ数が上限を超えました。条件を見直してください")

        q = dict(params, limit=100)
        if cursor:
            q["cursor"] = cursor

        data = api.get(path, **q)
        items.extend(data["items"])
        print(f"{page}ページ目 累計 {len(items)}件")

        cursor = data.get("next_cursor")
        if not cursor:                     # 次が無ければ終わり
            break
        time.sleep(0.2)                    # ★相手への思いやり(叩きすぎ防止)

    return items
無限ループの安全装置を必ず入れる 相手のAPIが仕様どおりでなく、いつまでも同じカーソルを返してくることがあります。最大ページ数と最大件数の上限を必ず入れてください。これが無いと、深夜に何百万回もリクエストを投げ続け、相手から接続を遮断されます(実際に起こる事故です)。

レート制限 ── 1分あたり何回まで叩けるか

レート制限は、APIを提供する側が「1分間に60回まで」のように定めた上限です。超えると429が返ります。ドキュメントの「Rate Limits」に必ず書かれています。

ヘッダー意味使い方
X-RateLimit-Limit上限の回数設計時の目安にする
X-RateLimit-Remainingあと何回叩けるか少なくなったら自分から間隔を空ける
X-RateLimit-Resetいつ回復するか(時刻や秒数)その時刻まで待つ
Retry-After何秒待つべきか429のときは、これに必ず従う
上限に近づいたら、自分から減速する
res = session.get(url, timeout=(3, 30))

remaining = int(res.headers.get("X-RateLimit-Remaining", 999))
if remaining < 5:
    reset = float(res.headers.get("X-RateLimit-Reset", 60))
    print(f"残り{remaining}回。{reset:.0f}秒待って再開します")
    time.sleep(reset)

429を受けてから対処するのではなく、その前に自分で減速するのが上級者の書き方です。429が多発すると、相手側で「行儀の悪い利用者」として記録され、最悪の場合は利用停止になります。

差分取得 ── そもそも取る量を減らす

毎晩10万件を全部取り直すのは、相手にとっても自分にとっても無駄です。多くのAPIは「いつ以降に更新されたか」で絞り込めます。

前回実行時刻以降だけを取る
# 前回取った時刻をファイルやDBに保存しておき、次回はそれ以降だけを取る
last = load_last_run()                       # 例: "2026-08-13T02:00:00+09:00"
items = fetch_all(api, "/orders", updated_since=last)

# ★保存するのは「取得を始めた時刻」。終わった時刻にすると、
#   処理中に更新されたデータを取りこぼす
save_last_run(started_at)
取りこぼしを防ぐ小技 保存する時刻を数分ぶん巻き戻しておく(例:開始時刻の5分前)と、時計のずれや処理の重なりによる取りこぼしを防げます。少し重複して取ることになりますが、取りこぼしより重複のほうが、はるかに直しやすいためです。重複は、こちら側で「同じIDなら上書き」(アップサート)にしておけば無害になります。

大量に送るとき

  • 一括APIがあるか探す:1件ずつ1000回より、100件まとめて10回のほうが、双方にとって圧倒的に軽い
  • 同時実行は控えめに:並行数は3〜5程度から始める。速さを求めて20並行などにすると、相手を落としかねない
  • 途中から再開できるように:どこまで処理したかを記録しておく。1000件目で落ちたとき、最初からやり直すのは大きな損失
  • 夜間・休日に寄せる:相手の業務時間帯を避けるのは、連携の基本的な礼儀
一問一答
  1. ページ番号方式が、取得中にデータが増えると問題になるのはなぜですか。
  2. 429が返ったとき、何秒待てばよいかはどこで分かりますか。
  3. 差分取得で保存する時刻は、処理の「開始時刻」と「終了時刻」のどちらにすべきですか。
解答を見る
  1. 新しいデータが先頭に入ると全体が後ろにずれ、同じ件を二重に取得したり、取りこぼしたりするため。カーソル方式ならずれない。
  2. Retry-Afterヘッダー。無い場合はX-RateLimit-Reset、それも無ければ指数バックオフで待つ。
  3. 開始時刻。終了時刻にすると、処理の実行中に更新されたデータを次回取りこぼす。さらに数分巻き戻すとより安全。
STEP 14 運用

Webhookと運用 ── 受け取る側になる/壊れたと気づける

目安 4日
このステップの到達点 ── Webhookの向きの違いを説明でき、受け口を作るときの3つの必須処理(すぐ200を返す・署名を検証する・重複を許容する)を言える。連携が壊れたときに、人より先に気づける仕掛けを作れる。

Webhookは「呼ばれる側」になること

ここまでは、あなたが相手のAPIを呼ぶ側でした。Webhook(ウェブフック)は逆で、相手が、出来事が起きたときにあなたのURLを呼びに来ます。決済完了、チャットへの投稿、配送状況の変化などの通知に使われます。

ポーリングとWebhookの違い
ポーリング(自分から何度も聞く) あなた 相手 終わった? まだ 終わった? まだ 終わった? 終わった! 無駄が多く、気づくのが遅い Webhook(相手から届く) あなた 相手 出来事が起きた瞬間に POST /hooks/payment {"event":"payment.succeeded"} 速い・無駄がない(受け口を公開する責任は生じる)

受け口を作るときの必須3点

  1. 1. すぐ200を返す重い処理を先にやると、相手がタイムアウトと判断して何度も再送してくる。受け取ったら即200、処理は後ろで(キューに積む)
  2. 2. 署名を検証するURLは公開されている。誰でも偽の通知を送れる。署名がなければ「決済成功」の偽通知で商品を出荷してしまう
  3. 3. 重複を許容する同じ通知が2回以上届く前提で作る(相手は「確実に届ける」ため再送する)。イベントIDで処理済みを記録する
webhook.py:受け口の骨格(Flask)
import hashlib
import hmac
import os
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = os.environ["WEBHOOK_SECRET"].encode()

@app.post("/hooks/payment")
def payment_hook():
    raw = request.get_data()                       # ★署名検証は「生のまま」で行う
    sig = request.headers.get("X-Signature", "")

    # ① 署名を検証する(本物の相手からか確かめる)
    expected = hmac.new(SECRET, raw, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, sig):     # ★==ではなくこれを使う
        abort(401)

    event = request.get_json()
    event_id = event.get("id")

    # ② 重複を弾く(同じ通知が何度も来る前提)
    if already_processed(event_id):
        return "", 200                             # 二重処理せず、成功として返す
    mark_processed(event_id)

    # ③ 重い処理はここでやらない。キューに積んで、すぐ返す
    enqueue(event)
    return "", 200
hmac.compare_digest を使う理由 単純な == による比較は、一致した文字数によって処理時間がわずかに変わります。攻撃者はその差を測って、署名を1文字ずつ突き止められます(タイミング攻撃)。compare_digest は常に同じ時間で比較するため、この攻撃を防げます。署名やトークンの比較には、必ず専用の関数を使ってください
開発中のWebhookの受け取り方 自分のパソコンには、外から届くURLがありません。ngrok のような道具を使うと、一時的に公開URLを作って手元に転送できます。ただしそのURLは世界中からアクセスできます。検証用のダミーデータだけを扱い、使い終わったら必ず停止してください。

壊れたことに、人より先に気づく

連携は「静かに壊れる」のが厄介です。エラーが出るなら気づけますが、0件を正常として処理し続けるのがいちばん怖い壊れ方です。「先月から売上データが入っていませんでした」は、実際に起きる事故です。

見張るもの異常とみなす条件気づけること
実行の成否異常終了した基本。ただしこれだけでは足りない
処理件数0件、または前日比で半分以下静かな停止・条件の誤り(最重要)
実行時刻予定時刻に実行された記録がないスケジューラの停止、サーバー障害
所要時間いつもの3倍かかった相手の不調、データ量の急増
エラー率全体の5%以上が失敗仕様変更、部分的な障害
鍵の期限期限の30日前証明書・トークンの失効事故

テスト ── 相手を呼ばずに試す

テストのたびに本物のAPIを叩くと、相手に迷惑がかかり、レート制限にも当たり、本番データを壊す危険があります。そこでモック(偽物の応答)を使います。

test_client.py:偽の応答で試す
import responses     # pip install responses

@responses.activate
def test_get_order_success():
    responses.add(
        responses.GET, "https://api.example.com/v1/orders/1",
        json={"id": 1, "status": "paid", "amount": 1200}, status=200,
    )
    order = ApiClient().get("/orders/1")
    assert order["status"] == "paid"

@responses.activate
def test_get_order_server_error():
    # ★異常系こそテストする。500のとき正しく諦められるか
    responses.add(responses.GET, "https://api.example.com/v1/orders/1", status=500)
    with pytest.raises(Exception):
        ApiClient().get("/orders/1")

テストすべきは、成功したときよりも失敗したときです。500が返ったとき、項目が欠けていたとき、応答が遅いとき。異常系を一度も試していないコードは、本番で必ず期待と違う動きをします

一問一答
  1. Webhookの受け口で、重い処理を先にやってはいけないのはなぜですか。
  2. 署名の検証をしないと、どんな被害が起こりえますか。
  3. 連携の監視で、「異常終了の有無」だけでは不十分なのはなぜですか。
解答を見る
  1. 返事が遅れると相手がタイムアウトと判断し、同じ通知を何度も再送してくるため。受け取ったらすぐ200を返し、処理は非同期で行う。
  2. 受け口のURLは公開されているため、第三者が偽の通知(例:「決済成功」)を送れてしまう。商品の不正な出荷やデータ改ざんにつながる。
  3. 「0件を正常として処理し続ける」など、エラーを出さずに静かに壊れる場合があるため。処理件数や実行時刻も監視する必要がある。
STEP 15 セキュリティ

安全に連携する ── 鍵の管理と、守るべき原則

目安 4日
このステップの到達点 ── APIキーを置いてよい場所と、置いてはいけない場所を即答できる。最小権限の考え方を実践でき、「その実装で漏れませんか」という問いに理由つきで答えられる。ここは、間違えると会社に実害が出る唯一の章です。

鍵の置き場所 ── これだけは覚える

置き場所可否理由
ソースコードに直接書く✕ 絶対に不可Gitの履歴に残り、消すのが困難。公開リポジトリなら数分で悪用される
ブラウザのJavaScript✕ 絶対に不可ページのソースは誰でも見られる
チャットやメールで共有検索可能な形で長期間残る。退職者にも見え続ける
URLのクエリ(?api_key=△ 避けるアクセスログ、ブラウザ履歴、リファラに残る
設定ファイル(.env.gitignore に必ず入れること。入れ忘れが事故の定番
環境変数コードと分離できる。実行環境ごとに切り替えられる
秘密管理サービス◎ 最良AWS Secrets Manager、GCP Secret Manager など。権限管理と履歴が残る
環境変数の使い方
# Mac / Linux
export EXAMPLE_API_TOKEN="abc123..."

# Windows PowerShell
$env:EXAMPLE_API_TOKEN = "abc123..."

# .env ファイルを使う場合、必ず .gitignore に追記する
echo ".env" >> .gitignore

# 【確認】うっかり鍵をコミットしていないか、履歴を検索する
git log -p | grep -i -E "api[_-]?key|secret|token|password" | head
もし鍵を漏らしてしまったら 慌ててコミットを消しても手遅れです。GitHubに一度でも上がった鍵は、自動収集されていると考えてください。やるべきことは1つ、ただちにその鍵を無効化し、新しい鍵を発行することです。そのうえで上長と情報システム部門に報告してください。隠すのが最悪の対応です。悪用されたときの被害額は、報告の遅れに比例します。

最小権限 ── 「読むだけ」で済むなら、読むだけの鍵を

APIキーやOAuthのスコープには、たいてい細かい権限設定があります。面倒だからといって、全権限を付けた鍵を1つ作って使い回すのは、実務で最も多い設計ミスです。

  • データを取り込むだけの処理 → 読み取り専用の鍵
  • 用途ごとに別々の鍵を発行する(漏れたとき、影響範囲をその用途に閉じ込められる)
  • 検証環境と本番環境で、必ず別の鍵を使う
  • 相手がIP制限に対応しているなら、自社のIPアドレスからのみ許可する
  • 使わなくなった鍵はすぐ無効化。退職者が作った鍵の棚卸しも定期的に

通信と実装で守ること

項目やることやってはいけないこと
通信必ず https:// を使う証明書の検証を無効にする(verify=False、curlの-k
ログトークンは伏せる(先頭4文字のみ等)リクエスト全体をそのまま出力する
エラー画面利用者には「失敗しました」とだけ内部のURL・スタックトレース・SQLを画面に出す
入力値サーバー側で必ず検証する画面の検証だけを信じる
受け取ったデータ画面に出すときはエスケープするAPIの返り値をそのまま innerHTML に入れる
個人情報必要な項目だけ取得・保存する「あとで使うかも」で全項目を保存する
APIの返り値をそのまま innerHTML に入れない 相手のデータに <script> が含まれていた場合、それがあなたのページで実行されます(XSS)。textContent を使うか、適切にエスケープしてください。「相手は信頼できる会社だから大丈夫」ではありません。その会社に登録した第三者の入力が、そのまま流れてくることがあります。

個人情報を扱うときの追加の注意

API連携では、氏名・住所・メールアドレス・購買履歴といった個人情報が動きます。技術の問題である前に、会社の責任の問題です。

  • 取得前に、社内の規程と契約を確認する。相手のAPIの利用規約に、データの保存や二次利用の条件が書かれています
  • 取る項目を最小限にする。「使わないが取れるから取る」は、漏えい時の被害を無用に大きくします
  • 保存期間を決める。不要になったデータは消す。持ち続けることがリスクです
  • 国外への移転に注意。海外のサービスに個人情報を送ることは、法令上の検討が必要になる場合があります
  • テストに本番データを使わない。検証環境に本番の個人情報を入れるのは、事故の典型的な原因です
「試しに叩いてみる」の前に 業務で使うAPIを初めて試すときは、必ず検証環境(sandbox)を使ってください。本番環境で試したPOSTが、実際の注文や請求として処理されてしまう事故は珍しくありません。検証環境が無いAPIの場合は、上長の承認を得て、影響のないデータで、範囲を決めて実施してください。
一問一答
  1. APIキーを置いてよい場所を2つ、置いてはいけない場所を2つ挙げてください。
  2. 鍵をGitにコミットしてしまったと気づいたとき、最初にすべきことは何ですか。
  3. APIから受け取った文字列を画面に出すとき、注意すべきことは何ですか。
解答を見る
  1. よい:環境変数、秘密管理サービス(.env.gitignoreも可)。不可:ソースコードへの直書き、ブラウザのJavaScript(およびチャットでの共有、URLのクエリ)。
  2. ただちにその鍵を無効化し、新しい鍵を再発行する。そのうえで上長と情報システム部門に報告する。履歴の削除だけでは対策にならない。
  3. そのままinnerHTMLに入れないこと。textContentを使うかエスケープする。相手経由で第三者の入力(スクリプト)が流れてくる可能性がある。
STEP 16 実務

連携案件の進め方 ── 依頼を受けてから引き継ぐまで

目安 5日+実践
このステップの到達点 ── 「A社のデータをうちのシステムに取り込みたい」というふわっとした依頼を、実装できる形に分解できる。設計書に何を書くべきかを言え、自分が抜けても回る形に残せる。ここまで来れば、連携案件を任せてもらえます。

依頼を受けたら、最初に確認する10項目

いきなりコードを書き始めてはいけません。この10項目を埋めるだけで、案件の8割は終わったも同然です。埋まらない項目があれば、それが確認すべきことです。

#確認することなぜ聞くのか
1目的(何のために連携するのか)手段が変わる。「手作業をなくしたい」ならCSVで済むかもしれない
2データの向き(取る/送る/双方向)設計がまったく変わる。双方向は難度が跳ね上がる
3頻度とタイミング(毎朝/1時間ごと/即時)即時ならWebhook、定期ならバッチ
4件数(1日何件、初回は何件)初回移行が10万件なら、専用の設計が要る
5項目の対応表(相手の項目 ↔ 自社の項目)ここが実装のほぼすべて。表がないまま始めると必ず手戻りする
6失敗したときどうするか誰に、どう伝えるか。自動で再試行してよいか
7重複したときどうするか上書きか、無視か、エラーか。決めないと必ず揉める
8認証情報を誰が用意するか他社の鍵の発行に、2週間かかることもある
9検証環境はあるか無い場合、試験の進め方を最初に合意しておく
10運用は誰がするか作って終わりではない。止まったとき誰が対応するか
5番の「項目の対応表」が最重要です 表計算ソフトで、相手の項目名/型/必須か/例と、自社の項目名/型/変換ルールを並べた表を作ってください。「相手の status"S" は、自社の「発送済」に対応する」といった値の変換規則まで書きます。この表が、そのまま設計書であり、テスト仕様書であり、引き継ぎ資料になります。

設計書に書くこと(1〜2ページで十分)

  • 全体図:どのシステムからどのシステムへ、何が、いつ流れるか(文字の図で構いません)
  • エンドポイント:使うAPIの一覧と、それぞれの用途
  • 項目の対応表:上記5番の表
  • 実行契機:毎日6時/注文確定時/手動、など
  • 異常時の動作:再試行の回数、諦める条件、通知先
  • 鍵の管理:どこに保管し、誰が更新でき、いつ期限が切れるか
  • 連絡先:相手側の窓口、自社の責任者

相手に問い合わせるときの型

連携の仕事では、相手のサポートに質問する場面が必ず来ます。次の形で送ると、返答の速さと精度が大きく変わります

問い合わせのテンプレート
■ 事象
POST /v1/orders で 422 が返り、注文を登録できません。

■ 発生日時
2026-08-14 10:32:15 JST(複数回発生、直近5回すべて)

■ 環境
検証環境(sandbox)/ クライアント: Python requests 2.32

■ 送信したリクエスト(機密情報は伏せています)
POST https://sandbox.example.com/v1/orders
Headers: Authorization: Bearer eyJh****(末尾4桁 : a1b2)
Body: {"product_id":"A-100","quantity":2,"delivery_date":"2026-08-20"}

■ 返ってきたレスポンス
HTTP 422
X-Request-Id: 7f3a9c22-1b44-4e0d-9f2a-55e1c0d3a8b1
{"error":{"code":"INVALID_FIELD","field":"delivery_date"}}

■ 確認したいこと
delivery_date の受け付け可能な書式と、指定できる日付の範囲をご教示ください。
ドキュメント(v1.4、8ページ)には「YYYY-MM-DD」と記載されています。

X-Request-Id を添えているかどうかで、相手が調べられる範囲がまるで違います。「エラーになります、直してください」だけの問い合わせは、往復が5回増えます。

引き継げる形に残す

連携は、作った人が異動しても動き続けます。だからこそ、次の担当者が読めば分かる状態にしておくのが、実務者の最後の仕事です。

  • READMEを置く:何をする処理か、動かし方、環境変数の一覧、止まったときの確認手順
  • 鍵の期限を、カレンダーに登録する:証明書やトークンの失効は、忘れたころに全体を止めます
  • 再実行の手順を書く:「昨日ぶんをもう一度取り込みたい」は必ず起きます
  • 相手の変更履歴を追える状態にする:APIのお知らせメールを、個人ではなく共有のメールアドレスで受け取る
これから伸ばすなら 次の一歩としては、①自分でAPIを作る側になる(FastAPIやExpressで、STEP 5の作法どおりに作ってみる)、②OpenAPIで仕様を書いてから実装する、③iPaaS(Zapier、Power Automate、n8nなど)を触るの3つがおすすめです。特に③は、「コードを書かずに済ませられる案件」を見分ける力がつきます。実務では、書かない判断ができる人のほうが重宝されます。
一問一答
  1. 連携の依頼を受けたとき、実装より先に作るべき資料は何ですか。
  2. 相手のサポートに問い合わせるとき、必ず添えるべき情報を3つ挙げてください。
  3. 「作って終わり」にしないために、引き継ぎで残すべきものを2つ挙げてください。
解答を見る
  1. 項目の対応表(相手の項目と自社の項目、型、必須、値の変換規則)。これが設計書・テスト仕様書・引き継ぎ資料を兼ねる。
  2. ①送ったリクエスト(URL・ヘッダー・本文。機密は伏せる)、②返ってきたステータスコードと本文、③X-Request-Idと発生日時。
  3. README(動かし方・環境変数・障害時の確認手順)と、鍵や証明書の期限管理(カレンダー登録)。ほかに再実行手順、連絡先も。

手を動かす道具

入力すると、その場でコードとして組み立てます(通信は行いません)

① リクエスト組み立てフォーム

STEP 2・4・6・7・9の内容が、そのまま形になります

叩きたいAPIの条件を入力して「組み立てる」を押すと、curl・JavaScript(fetch)・Python(requests)の3つの書き方を同時に作ります。 3つを見比べると、どの言語でも送っているものは同じだと分かります。入力の検証も行うので、STEP 10で学んだフォームの動きも確認できます。

日本語や空白が入っていても、自動で変換した形で出力します。
Basic認証のときは ID:パスワード の形で入力します。
JSONの書式が誤っている場合は、その場で知らせます(STEP 3の練習)。
本番の鍵は入力しないでください このフォームは、入力された内容をブラウザの中だけで組み立てます(どこにも送信しません)。それでも、本物のトークンやパスワードを画面に入力する習慣は事故のもとです。練習用の文字列を使ってください。

② JSON読み取りの練習

STEP 3の「道すじ」を、手で確かめます

左にJSONを貼り、右に取り出したい道すじ(例:users[0].department.name)を書いて「取り出す」を押します。 APIの返事から目的の値までたどる練習です。実務では、この道すじを口で言えることが、そのまま実装力になります

書き方の例:totalusers[1].nameusers[0].tags[1]
取り出した結果
「取り出す」を押すと、ここに結果が出ます。

実務チートシート

現場でとっさに確認したくなるものを、ここにまとめました

ステータスコード早見表

コード意味悪いのは最初にやること
200 / 201 / 204成功/作成成功/成功(中身なし)204は空でも正常。異常扱いしない
301 / 302転送新しいURLに直す。curlは -L
400頼み方が不正自分JSONの書式、必須項目の抜け
401誰か分からない自分鍵の有無・期限・ヘッダー名の綴り
403権限がない自分権限・プラン・IP制限。鍵の作り直しでは直らない
404その住所は無い自分URL・バージョン・IDの存在
405 / 415メソッド違い/形式違い自分メソッドと Content-Type
409 / 422矛盾/内容が不適切自分重複登録、値の範囲。再試行しない
429叩きすぎ自分Retry-After 秒だけ待つ
500 / 502 / 503 / 504相手の中で失敗相手指数バックオフで再試行。続けば連絡

覚え方:4xxは自分、5xxは相手。この一線が引けるだけで、無駄な調査と無駄な問い合わせが激減します。

つながらないときの5分診断

やること成功したら失敗したら
1いつから・誰が・どの機能で、を確認する調査範囲が絞れる
2curl -v で手で叩く原因はプログラム側と確定次へ
3ステータスコードを見る4xxなら自分、5xxなら相手応答が無い=経路かタイムアウト
4エラー本文と X-Request-Id を読む原因が書いてあることが多い次へ
5鍵の期限・環境(本番/検証)を確認401の多くはここ次へ
6相手の稼働状況ページ・変更履歴を見る相手側の障害/仕様変更と判明証拠をそろえて相手に連絡

この形だけは覚える

Authorization: Bearer <token>

いま最も多い認証の送り方。Bearerの後は半角空白1つ。

Content-Type: application/json

ボディを送るときは必ず付ける。忘れると400か415。

if (!res.ok) throw …

fetchは404でも例外を投げない。自分で確認する。

timeout=(3, 30)

接続3秒・読み取り30秒。付けないと永久に待つ。

1 → 2 → 4 → 8 秒

指数バックオフ。ばらつきを足して殺到を防ぐ。

Idempotency-Key

POSTの再送で二重登録を防ぐ鍵。1依頼=1鍵。

X-Request-Id

問い合わせの決め手。必ずログに残す。

.env は .gitignore へ

鍵の流出は、ここの入れ忘れから始まる。

用語集

意味があいまいなまま進みがちな言葉を集めました
API Application Programming Interface
サービスが公開している、プログラム向けの受付窓口。決まった形で頼むと、決まった形で返ってくる。
エンドポイント endpoint
頼み先の具体的なURL。ふつう1つの機能につき1つ用意される。
リクエスト/レスポンス
頼む側が送るものと、返ってくるもの。どちらも「開始行・ヘッダー・ボディ」の3部品でできている。
ステートレス stateless
サーバーが前回の通信を覚えていない性質。だから毎回、認証情報を付けて送る必要がある。
ペイロード payload
実際に運びたいデータ本体。ボディの中身を指すことが多い。
冪等性 べきとうせい/idempotency
同じ操作を何回繰り返しても結果が1回と同じになる性質。GET・PUT・DELETEは冪等、POSTは冪等でない。
冪等キー Idempotency-Key
POSTの再送による二重登録を防ぐための識別子。1つの業務上の依頼につき1つ発行する。
認証/認可 AuthN/AuthZ
認証は「誰か」を確かめること(失敗は401)、認可は「何をしてよいか」を決めること(失敗は403)。
スコープ scope
その鍵でできることの範囲。orders.read のように機能ごとに指定する。最小限にするのが原則。
アクセストークン access token
APIを叩くときに毎回付ける、期限の短い資格情報。ふつう Authorization: Bearer で送る。
リフレッシュトークン refresh token
アクセストークンを作り直すための引換券。期限が長く、最重要機密として扱う。
JWT JSON Web Token
ピリオドで3つに区切られたトークン形式。中身は誰でも読めるため、秘密の情報を入れてはいけない。
CORS コルス
別サイトのAPIをブラウザから呼ぶことを制限する、ブラウザ側の安全装置。遮断しているのはブラウザ。
プリフライト preflight
本番のリクエストの前に、ブラウザが許可を確かめるために送る OPTIONS リクエスト。
レート制限 rate limit
一定時間あたりに叩ける回数の上限。超えると429が返る。
指数バックオフ exponential backoff
再試行の待ち時間を1→2→4→8秒と倍にしていく方法。ばらつき(ジッター)を足すのが定石。
ページネーション pagination
大量のデータを分割して返す仕組み。ページ番号方式・オフセット方式・カーソル方式がある。
カーソル cursor
「続きはここから」を示す目印。大量データでもずれずに全件取得できる。
Webhook ウェブフック
向きが逆の連携。出来事が起きたとき、相手からこちらのURLに通知が届く。
ポーリング polling
「もう終わった?」と定期的に確認しに行く方式。Webhookより無駄が多く、気づくのが遅い。
署名検証 signature verification
届いた通知が本物かを、共有した秘密の鍵と計算値で確かめること。Webhookには必須。
モック mock
本物のAPIの代わりに、決まった応答を返す偽物。テストで相手を呼ばずに済ませる。
サンドボックス sandbox
本番とは切り離された検証環境。実際の請求や出荷が発生しない。試すときは必ずこちら。
OpenAPI 旧Swagger
APIの仕様をYAML/JSONで書いた設計図。試験画面やコードを自動生成できる。
SDK Software Development Kit
APIを楽に使うための公式ライブラリ。認証やリトライが最初から入っていることが多い。
iPaaS アイパース
コードを書かずにサービス同士をつなぐ仕組み(Zapier、Power Automateなど)。簡単な連携はこれで足りる。

よくある質問

学び始めた人から実際によく出る質問です
プログラミングがまったくできませんが、APIを学べますか?

学べます。STEP 8まではコードを1行も書きません。curlというコマンドを打つだけで、APIの本質のほとんどは理解できます。実際、営業や業務部門の方が「相手先のAPIで何ができるか」を判断できるようになるだけで、仕事の進み方が変わります。

そのうえで実装まで進みたい場合は、PythonかJavaScriptのどちらかを、変数・条件分岐・繰り返し・関数の4つだけ先に学んでください。それ以上は、必要になったときで間に合います。

PythonとJavaScript、どちらから学ぶべきですか?

やりたいことで決めてください。「毎朝データを取り込む」「システム同士をつなぐ」といったバッチ処理が目的ならPython。「Webページに外部の情報を表示する」「フォームから送信する」ならJavaScriptです。

どちらを選んでも、送っているものはまったく同じです。このページの「手を動かす道具」で、同じリクエストが3つの書き方で並ぶのを見比べてください。片方を覚えれば、もう片方は数日で書けるようになります。

「動かない」とき、何から見ればよいですか?

順番が決まっています。①curl -v で手で叩く(プログラムの問題か切り分ける)、②ステータスコードを見る(4xxなら自分、5xxなら相手)、③エラー本文を読む(理由が書いてあることが非常に多い)、④ヘッダーを疑う(認証・形式)、⑤URLを疑う(本番/検証、バージョン)。

この順番を守るだけで、原因究明の時間は大きく短縮できます。逆に、いきなりコードを書き換え始めるのが、いちばん時間を失う進め方です。

用語が覚えられません。どうすればよいですか?

略語のまま覚えようとしないでください。「誰が、何をする役目か」を日本語の一文にするのがこつです。「JSON=データをやり取りする書き方」「OAuth=パスワードを渡さずに許可だけ渡すしくみ」というように。

そのうえで、読み方を必ず声に出して確認してください。読み方があいまいだと、会話でも検索でも使えません。このページのふりがな機能は、まさにそのために付けています。最初のうちはONのまま読み進めてください。

練習できる無料のAPIはありますか?

あります。認証なしで叩けるものとして、httpbin.org(送った内容をそのまま返す。自分の送信内容を確かめる鏡として最適)、jsonplaceholder.typicode.com(架空の投稿・利用者データ。POSTやPATCHも試せる)、worldtimeapi.org(世界の時刻)などがよく使われます。

認証つきの練習をしたい場合は、GitHubやSlackなど、個人で無料の鍵を発行できるサービスが向いています。いずれの場合も、短い間隔で大量に叩かないでください。練習用のサービスは、善意で公開されています。

未経験からAPI連携の仕事に就けますか?

就ける分野です。API連携は、業務システムの現場で恒常的に需要がある領域です。多くの人が、既存の連携の運用・保守から入り、改修、新規の設計へと進んでいきます。

採用の場でよく見られるのは、書けるコードの量ではありません。「動かないときに、原因の場所をどう切り分けるか」が問われます。このページのSTEP 7とSTEP 12を、自分の言葉で説明できるように準備しておいてください。あわせて、自分で作った小さな連携(例:公開APIから毎日データを取ってCSVに保存する)を見せられると、強い材料になります。

実務でいちばん多いトラブルは何ですか?

体感として多い順に、①認証まわり(鍵の期限切れ、本番と検証の取り違え、ヘッダーの書式)、②相手の仕様変更(項目の追加・廃止、URLの変更)、③想定外のデータ(項目が無い、nullが入る、文字数が超える)、④件数の急増によるタイムアウトやレート制限、⑤相手側の障害です。

①が最多である以上、対応の第一手は「鍵は生きているか、環境は合っているか」の確認になります。技術的な調査を始める前に、ここを必ず見てください。半分近くはここで解決します。

これから学ぶ方・指導される方へ

このページは、API連携を初めて学ぶ方が、ライブラリの使い方からではなく「1本のリクエストの往復」から理解できるように構成しています。サンプルコードの暗記から入ると、「動いたけれど、なぜ動いたか分からない」状態になりやすいためです。まずは通読し、二周目でcurlを実行し、三周目で一問一答を使って確認する使い方をおすすめします。

指導される立場の方へ。学習者が詰まる場所は、経験上ほぼ決まっています。①認証(STEP 6)、②非同期処理とfetchのエラー判定(STEP 9)、③エラー処理と再試行の設計(STEP 12)の3か所です。ここに時間を配分し、それ以外は先に進みながら繰り返し戻る形にすると、途中で止まりにくくなります。

掲載しているコマンド・コードは、原則としてご自身の検証環境や、練習用の公開APIで実行してください。業務で使うAPIを、承認を得ずに本番環境で試さないでください。技術的には1行でも、実際の注文・請求・送信が発生することがあります。必ず責任者の許可を得て、検証環境で実施してください。