← ブログに戻る

JSON、API、RESTサービス

REST APIでJSONを使用する方法。APIデザイン、HTTP メソッド、ステータスコード、認証、ベストプラクティス。

Big JSON Team15 分で読めますapi
B

Big JSON Team

Technical Writer

Expert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.

15 分読む

# JSON、API、RESTサービス

JSONはREST APIのデータ交換フォーマットとして業界標準になっています。

REST APIとは

REST(Representational State Transfer)は、Webサービスを構築するためのアーキテクチャスタイルです。

REST の原則

  • クライアント-サーバー - 関心の分離
  • ステートレス - 各リクエストは独立
  • キャッシュ可能 - レスポンスのキャッシュ
  • 統一インターフェース - 標準化されたインターフェース
  • 階層システム - レイヤー構造
  • HTTPメソッド

    CRUD操作

    | メソッド | 操作 | 説明 |

    |---------|------|------|

    | GET | Read | リソースの取得 |

    | POST | Create | 新しいリソースの作成 |

    | PUT | Update | リソース全体の更新 |

    | PATCH | Update | リソースの部分更新 |

    | DELETE | Delete | リソースの削除 |

    GET - データの取得

    GET /api/users
    

    GET /api/users/123

    GET /api/users?role=admin&limit=10

    レスポンス:
    {
    

    "data": [

    {

    "id": 1,

    "name": "田中太郎",

    "email": "tanaka@example.com"

    }

    ],

    "total": 1,

    "page": 1

    }

    POST - データの作成

    POST /api/users
    

    Content-Type: application/json

    {

    "name": "田中太郎",

    "email": "tanaka@example.com",

    "role": "user"

    }

    レスポンス:
    {
    

    "success": true,

    "data": {

    "id": 123,

    "name": "田中太郎",

    "email": "tanaka@example.com",

    "role": "user",

    "created": "2026-01-16T10:00:00Z"

    }

    }

    PUT - 完全な更新

    PUT /api/users/123
    

    Content-Type: application/json

    {

    "name": "田中太郎",

    "email": "newemail@example.com",

    "role": "admin"

    }

    PATCH - 部分的な更新

    PATCH /api/users/123
    

    Content-Type: application/json

    {

    "role": "admin"

    }

    DELETE - 削除

    DELETE /api/users/123
    レスポンス:
    {
    

    "success": true,

    "message": "ユーザーが削除されました"

    }

    HTTPステータスコード

    成功レスポンス (2xx)

    • 200 OK - 成功(GET、PUT、PATCH)
    • 201 Created - リソースが作成された(POST)
    • 204 No Content - 成功、コンテンツなし(DELETE)

    クライアントエラー (4xx)

    • 400 Bad Request - 無効なリクエスト
    • 401 Unauthorized - 認証が必要
    • 403 Forbidden - アクセス拒否
    • 404 Not Found - リソースが見つからない
    • 422 Unprocessable Entity - 検証エラー

    サーバーエラー (5xx)

    • 500 Internal Server Error - サーバーエラー
    • 502 Bad Gateway - ゲートウェイエラー
    • 503 Service Unavailable - サービス利用不可

    レスポンス構造

    成功レスポンス

    {
    

    "success": true,

    "data": {

    "id": 123,

    "name": "田中太郎"

    },

    "message": "操作が成功しました"

    }

    エラーレスポンス

    {
    

    "success": false,

    "error": {

    "code": "VALIDATION_ERROR",

    "message": "入力データが無効です",

    "details": [

    {

    "field": "email",

    "message": "有効なメールアドレスを入力してください"

    }

    ]

    }

    }

    ページネーション

    {
    

    "data": [...],

    "pagination": {

    "page": 1,

    "limit": 10,

    "total": 100,

    "pages": 10

    }

    }

    JavaScriptでのAPI使用

    Fetch API

    // GET リクエスト
    

    async function getUsers() {

    try {

    const response = await fetch('https://api.example.com/users');

    if (!response.ok) {

    throw new Error(HTTP error! status: ${response.status});

    }

    const data = await response.json();

    return data;

    } catch (error) {

    console.error('エラー:', error);

    throw error;

    }

    }

    // 使用

    const users = await getUsers();

    console.log(users);

    POST リクエスト

    async function createUser(userData) {
    

    try {

    const response = await fetch('https://api.example.com/users', {

    method: 'POST',

    headers: {

    'Content-Type': 'application/json',

    'Authorization': Bearer ${token}

    },

    body: JSON.stringify(userData)

    });

    const data = await response.json();

    if (!response.ok) {

    throw new Error(data.error.message);

    }

    return data;

    } catch (error) {

    console.error('作成エラー:', error);

    throw error;

    }

    }

    // 使用

    const newUser = {

    name: '田中太郎',

    email: 'tanaka@example.com'

    };

    const result = await createUser(newUser);

    PUT/PATCH リクエスト

    async function updateUser(userId, updates) {
    

    const response = await fetch(https://api.example.com/users/${userId}, {

    method: 'PATCH',

    headers: {

    'Content-Type': 'application/json'

    },

    body: JSON.stringify(updates)

    });

    return await response.json();

    }

    // 使用

    await updateUser(123, { role: 'admin' });

    DELETE リクエスト

    async function deleteUser(userId) {
    

    const response = await fetch(https://api.example.com/users/${userId}, {

    method: 'DELETE'

    });

    if (response.status === 204) {

    return { success: true };

    }

    return await response.json();

    }

    Node.js/Express での API作成

    基本的なセットアップ

    const express = require('express');
    

    const app = express();

    app.use(express.json()); // JSONパース

    // データベース(例)

    let users = [

    { id: 1, name: '田中太郎', email: 'tanaka@example.com' },

    { id: 2, name: '佐藤花子', email: 'sato@example.com' }

    ];

    // GET - すべてのユーザー

    app.get('/api/users', (req, res) => {

    res.json({

    success: true,

    data: users

    });

    });

    // GET - 特定のユーザー

    app.get('/api/users/:id', (req, res) => {

    const user = users.find(u => u.id === parseInt(req.params.id));

    if (!user) {

    return res.status(404).json({

    success: false,

    error: { message: 'ユーザーが見つかりません' }

    });

    }

    res.json({

    success: true,

    data: user

    });

    });

    // POST - ユーザー作成

    app.post('/api/users', (req, res) => {

    const { name, email } = req.body;

    // バリデーション

    if (!name || !email) {

    return res.status(400).json({

    success: false,

    error: { message: '名前とメールは必須です' }

    });

    }

    const newUser = {

    id: users.length + 1,

    name,

    email

    };

    users.push(newUser);

    res.status(201).json({

    success: true,

    data: newUser

    });

    });

    // PUT - ユーザー更新

    app.put('/api/users/:id', (req, res) => {

    const userId = parseInt(req.params.id);

    const index = users.findIndex(u => u.id === userId);

    if (index === -1) {

    return res.status(404).json({

    success: false,

    error: { message: 'ユーザーが見つかりません' }

    });

    }

    users[index] = {

    id: userId,

    ...req.body

    };

    res.json({

    success: true,

    data: users[index]

    });

    });

    // DELETE - ユーザー削除

    app.delete('/api/users/:id', (req, res) => {

    const userId = parseInt(req.params.id);

    const index = users.findIndex(u => u.id === userId);

    if (index === -1) {

    return res.status(404).json({

    success: false,

    error: { message: 'ユーザーが見つかりません' }

    });

    }

    users.splice(index, 1);

    res.status(204).send();

    });

    app.listen(3000, () => {

    console.log('サーバーがポート3000で起動しました');

    });

    認証と認可

    JWT (JSON Web Token)

    const jwt = require('jsonwebtoken');
    
    

    // トークン生成

    function generateToken(user) {

    return jwt.sign(

    { id: user.id, email: user.email },

    'your-secret-key',

    { expiresIn: '24h' }

    );

    }

    // ログイン

    app.post('/api/auth/login', async (req, res) => {

    const { email, password } = req.body;

    // ユーザー検証(例)

    const user = await findUser(email, password);

    if (!user) {

    return res.status(401).json({

    success: false,

    error: { message: '認証に失敗しました' }

    });

    }

    const token = generateToken(user);

    res.json({

    success: true,

    data: {

    token,

    user: {

    id: user.id,

    name: user.name,

    email: user.email

    }

    }

    });

    });

    // 認証ミドルウェア

    function authenticate(req, res, next) {

    const token = req.headers.authorization?.split(' ')[1];

    if (!token) {

    return res.status(401).json({

    success: false,

    error: { message: 'トークンが必要です' }

    });

    }

    try {

    const decoded = jwt.verify(token, 'your-secret-key');

    req.user = decoded;

    next();

    } catch (error) {

    res.status(401).json({

    success: false,

    error: { message: '無効なトークンです' }

    });

    }

    }

    // 保護されたルート

    app.get('/api/profile', authenticate, (req, res) => {

    res.json({

    success: true,

    data: req.user

    });

    });

    エラーハンドリング

    グローバルエラーハンドラー

    // エラーハンドリングミドルウェア
    

    app.use((err, req, res, next) => {

    console.error(err.stack);

    res.status(err.status || 500).json({

    success: false,

    error: {

    message: err.message || '内部サーバーエラー',

    ...(process.env.NODE_ENV === 'development' && { stack: err.stack })

    }

    });

    });

    カスタムエラークラス

    class ApiError extends Error {
    

    constructor(message, status = 500) {

    super(message);

    this.status = status;

    }

    }

    // 使用

    app.get('/api/users/:id', async (req, res, next) => {

    try {

    const user = await findUserById(req.params.id);

    if (!user) {

    throw new ApiError('ユーザーが見つかりません', 404);

    }

    res.json({ success: true, data: user });

    } catch (error) {

    next(error);

    }

    });

    CORS(クロスオリジンリソース共有)

    const cors = require('cors');
    
    

    // すべてのオリジンを許可

    app.use(cors());

    // 特定のオリジンのみ許可

    app.use(cors({

    origin: 'https://example.com',

    methods: ['GET', 'POST', 'PUT', 'DELETE'],

    credentials: true

    }));

    レート制限

    const rateLimit = require('express-rate-limit');
    
    

    const limiter = rateLimit({

    windowMs: 15 60 1000, // 15分

    max: 100, // 最大100リクエスト

    message: {

    success: false,

    error: { message: 'リクエストが多すぎます' }

    }

    });

    app.use('/api/', limiter);

    API のバージョニング

    URLバージョニング

    app.use('/api/v1/users', usersV1Router);
    

    app.use('/api/v2/users', usersV2Router);

    ヘッダーバージョニング

    app.use((req, res, next) => {
    

    const version = req.headers['api-version'] || '1';

    req.apiVersion = version;

    next();

    });

    ベストプラクティス

    1. 一貫したレスポンス構造

    // 良い
    

    {

    "success": true,

    "data": {...}

    }

    // 悪い(不整合)

    // 時々 { "data": ... }

    // 時々 { "result": ... }

    2. 適切なHTTPメソッド使用

    // 良い
    

    GET /api/users - ユーザーリスト取得

    POST /api/users - ユーザー作成

    // 悪い

    GET /api/createUser - GETで作成は不適切

    3. リソース名は複数形

    // 良い
    

    GET /api/users

    GET /api/users/123

    // 悪い

    GET /api/user

    GET /api/getUser/123

    4. クエリパラメータでフィルタリング

    GET /api/users?role=admin&status=active&limit=10&page=1

    5. 適切なステータスコード

    app.post('/api/users', (req, res) => {
    

    const user = createUser(req.body);

    res.status(201).json({ success: true, data: user }); // 201 Created

    });

    app.delete('/api/users/:id', (req, res) => {

    deleteUser(req.params.id);

    res.status(204).send(); // 204 No Content

    });

    6. ドキュメント化

    Swagger/OpenAPIでAPIをドキュメント化:

    openapi: 3.0.0
    

    info:

    title: User API

    version: 1.0.0

    paths:

    /users:

    get:

    summary: ユーザーリスト取得

    responses:

    '200':

    description: 成功

    content:

    application/json:

    schema:

    type: object

    properties:

    success:

    type: boolean

    data:

    type: array

    items:

    $ref: '#/components/schemas/User'

    テスト

    Jest でのAPI テスト

    const request = require('supertest');
    

    const app = require('./app');

    describe('User API', () => {

    test('GET /api/users should return users', async () => {

    const response = await request(app)

    .get('/api/users')

    .expect(200)

    .expect('Content-Type', /json/);

    expect(response.body.success).toBe(true);

    expect(Array.isArray(response.body.data)).toBe(true);

    });

    test('POST /api/users should create user', async () => {

    const newUser = {

    name: '田中太郎',

    email: 'tanaka@example.com'

    };

    const response = await request(app)

    .post('/api/users')

    .send(newUser)

    .expect(201);

    expect(response.body.success).toBe(true);

    expect(response.body.data.name).toBe(newUser.name);

    });

    });

    まとめ

    クイックリファレンス

    // GET
    

    fetch('/api/users')

    .then(r => r.json())

    .then(data => console.log(data));

    // POST

    fetch('/api/users', {

    method: 'POST',

    headers: { 'Content-Type': 'application/json' },

    body: JSON.stringify({ name: '田中太郎' })

    });

    // Express API

    app.get('/api/users', (req, res) => {

    res.json({ success: true, data: users });

    });

    app.post('/api/users', (req, res) => {

    const user = createUser(req.body);

    res.status(201).json({ success: true, data: user });

    });

    REST APIとJSONで、スケーラブルなWebサービスを構築しましょう!

    Share:

    関連記事

    Read in English