JSONに関する基礎知識|Webアプリケーションを学んだ新人エンジニア向けにやさしく解説

こんにちは。ゆうせいです。

今回は、JSONに関する基礎知識を、新人エンジニア向けに解説します。

Spring Bootで@RestControllerを学んだり、JavaScriptのfetch()を使ったりすると、必ずJSONという言葉が出てきます。

JSONは、WebアプリケーションやAPI開発では避けて通れない重要なデータ形式です。

ただ、最初はこう思いませんか?

JSONってJavaScriptのコードなの?
JavaのDTOとは何が関係あるの?
なぜfetch()ではJSON.stringify()を使うの?
@RequestBodyはJSONとどう関係しているの?





結論から言うと、JSONは「システム同士でデータをやり取りするための文字列形式」です。

たとえるなら、JSONは「データを運ぶための共通の伝票」です。

JavaScript、Java、Python、PHP、スマホアプリなど、いろいろな言語やシステムが同じ伝票を読めるようにするための形式です。

JSONとは何か

JSONは、JavaScript Object Notationの略です。

日本語にすると、「JavaScriptのオブジェクト表記法」という意味です。

ただし、現在ではJavaScript専用ではありません。

Java、Python、PHP、Ruby、Go、スマホアプリ、外部APIなど、さまざまな環境で使われています。

たとえば、ユーザー情報をJSONで表すと次のようになります。

{
    "userId": 1,
    "name": "山田太郎",
    "email": "yamada@example.com"
}




このJSONは、次の情報を表しています。

キー意味
userId1ユーザーID
name山田太郎ユーザー名
emailyamada@example.comメールアドレス

JSONは、キーと値の組み合わせでデータを表します。

キーは項目名、値は中身です。

学校の名簿でたとえるなら、「名前:山田太郎」「出席番号:1」「メール:yamada@example.com」のような項目表です。

JSONは文字列である

まず大事なのは、JSONは通信上では文字列として送られるという点です。

JavaScriptのオブジェクトやJavaのDTOが、そのまま電波のように飛んでいくわけではありません。

通信するときには、JSON形式の文字列に変換して送ります。

{
    "name": "山田太郎",
    "email": "yamada@example.com"
}




この見た目はオブジェクトに似ていますが、HTTP通信ではテキストデータとして扱われます。

宅配便でたとえるなら、JavaScriptオブジェクトやJavaオブジェクトは「中身の商品」です。

JSONは「配送用の箱に入れてラベルを貼った状態」です。

配送するときは、箱に入れた形、つまりJSON文字列にして送ります。

JSONの基本構造

JSONの基本は、キーと値の組み合わせです。

{
"キー": 値
}





具体例です。

{
    "name": "山田太郎"
}




nameがキーです。

山田太郎が値です。

キーは必ずダブルクォーテーションで囲みます。

シングルクォーテーションではありません。

書き方正しいか理由
"name"正しいJSONのキーはダブルクォーテーションで囲む
'name'誤りJSONではシングルクォーテーションを使わない
name誤りキーをクォーテーションなしで書けない

JSONで使える値の種類

JSONでは、値として次の種類を使えます。

種類説明
文字列"山田太郎"文字データ
数値100整数や小数
真偽値true、false正しいかどうか
nullnull値がないこと
オブジェクト{ "name": "山田" }キーと値のまとまり
配列[ "Java", "SQL" ]複数の値の並び

いろいろ出てきましたが、最初は「文字列、数値、true/false、null、オブジェクト、配列」が使えると覚えてください。

文字列

文字列は、ダブルクォーテーションで囲みます。

{
    "name": "山田太郎",
    "email": "yamada@example.com"
}




JavaScriptではシングルクォーテーションも使えますが、JSONでは使えません。

次の書き方はJSONとしては誤りです。

{
    "name": '山田太郎'
}




JSONでは、文字列は必ずダブルクォーテーションで囲む!

このルールは最初に覚えてください。

数値

数値は、クォーテーションで囲みません。

{
    "userId": 1,
    "price": 2500000,
    "rate": 0.08
}




ただし、次のように書くと文字列になります。

{
    "userId": "1"
}




"1"は数値ではなく文字列です。

Java側でIntegerやintとして受け取る場合、Spring Bootが変換できれば受け取れますが、基本的には数値は数値として送るほうが自然です。

JSON意味Javaでの例
1数値Integer、int、Long
"1"文字列String

trueとfalse

真偽値はtrueまたはfalseで表します。

{
    "active": true,
    "deleted": false
}




trueとfalseはクォーテーションで囲みません。

次のように書くと、文字列になってしまいます。

{
    "active": "true"
}




Booleanとして扱いたいなら、クォーテーションなしでtrueまたはfalseを書きます。

null

nullは、値がないことを表します。

{
    "deletedAt": null
}




たとえば、論理削除されていないデータではdeletedAtがnullになることがあります。

Javaでは、nullを受け取れる型と受け取れない型に注意が必要です。

Javaの型nullを持てるか
String持てる
Integer持てる
Long持てる
Boolean持てる
int持てない
long持てない
boolean持てない

JSONでnullが来る可能性がある項目は、Java側でIntegerやLongなどのラッパークラスを使うと扱いやすいです。

配列

JSONでは、複数の値を配列で表せます。

{
    "skills": [
        "Java",
        "SQL",
        "Spring Boot"
    ]
}




skillsには、複数の文字列が入っています。

JavaScriptでは配列として扱えます。

JavaではList<String>として受け取ることが多いです。

private List<String> skills;

配列は、買い物リストのようなものです。

1つではなく、複数の値を順番に並べたいときに使います。

オブジェクトの入れ子

JSONでは、オブジェクトの中にさらにオブジェクトを入れられます。

{
    "userId": 1,
    "name": "山田太郎",
    "address": {
        "postalCode": "100-0005",
        "prefecture": "東京都",
        "city": "千代田区"
    }
}




addressの中に、postalCode、prefecture、cityがあります。

このような構造を、入れ子、またはネストと呼びます。

ロッカーの中に小さな箱があり、その箱の中にさらに封筒が入っているイメージです。

Javaで受け取るなら、次のようにクラスを分けます。

public class UserRequest {

    private int userId;
    private String name;
    private AddressRequest address;

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public AddressRequest getAddress() {
        return address;
    }

    public void setAddress(AddressRequest address) {
        this.address = address;
    }
}

public class AddressRequest {

    private String postalCode;
    private String prefecture;
    private String city;

    public String getPostalCode() {
        return postalCode;
    }

    public void setPostalCode(String postalCode) {
        this.postalCode = postalCode;
    }

    public String getPrefecture() {
        return prefecture;
    }

    public void setPrefecture(String prefecture) {
        this.prefecture = prefecture;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }
}


JSONの構造とJavaクラスの構造を合わせると、Spring Bootで受け取りやすくなります。

JSONとJavaScriptオブジェクトの違い

JSONとJavaScriptオブジェクトは見た目が似ています。

しかし、厳密には違います。

JavaScriptオブジェクトの例です。

const user = {
    userId: 1,
    name: "山田太郎",
    email: "yamada@example.com"
};




JSONの例です。

{
    "userId": 1,
    "name": "山田太郎",
    "email": "yamada@example.com"
}




比較JavaScriptオブジェクトJSON
キーの書き方クォーテーションなしでもよいダブルクォーテーション必須
変数に代入できるJSONそのものはデータ形式
関数持てる持てない
コメント書ける場合がある書けない

JavaScriptオブジェクトは、JavaScriptの中で使うデータです。

JSONは、通信や保存のための文字列形式です。

似ているけれど同じではありません。

JSON.stringifyとは何か

JavaScriptオブジェクトをJSON文字列に変換するには、JSON.stringify()を使います。

const user = {
    name: "山田太郎",
    email: "yamada@example.com"
};

const jsonText = JSON.stringify(user);

console.log(jsonText);




出力イメージです。

{"name":"山田太郎","email":"yamada@example.com"}

fetch()でSpring Boot APIへJSONを送るときによく使います。

fetch("/api/users", {
    method: "POST",
    headers: {
        "Content-Type": "application/json"
    },
    body: JSON.stringify(user)
});




JSON.stringify()は、「JavaScriptのデータを通信できるJSON文字列に変換する作業」です。

弁当箱に詰めるイメージで覚えてください。

JSON.parseとは何か

JSON文字列をJavaScriptオブジェクトに戻すには、JSON.parse()を使います。

const jsonText = '{"name":"山田太郎","email":"yamada@example.com"}';

const user = JSON.parse(jsonText);

console.log(user.name);
console.log(user.email);




出力イメージです。

山田太郎
yamada@example.com




JSON.parse()は、JSON文字列をJavaScriptで扱えるオブジェクトに変換します。

弁当箱を開けて、中身を取り出すイメージです。

fetch()とJSON

JavaScriptのfetch()では、JSONを送ったり受け取ったりすることがよくあります。

送信側の例です。

const requestData = {
    name: "山田太郎",
    email: "yamada@example.com"
};

fetch("/api/users", {
    method: "POST",
    headers: {
        "Content-Type": "application/json"
    },
    body: JSON.stringify(requestData)
});




受信側の例です。

fetch("/api/users/1")
    .then(function (response) {
        return response.json();
    })
    .then(function (data) {
        console.log(data.name);
    });




処理使うもの意味
JavaScriptからJSONを送るJSON.stringify()オブジェクトをJSON文字列にする
APIからJSONを受け取るresponse.json()レスポンスをJavaScriptオブジェクトにする

Spring BootとJSON

Spring Bootでは、@RestControllerと@RequestBodyを使うとJSONを扱いやすくなります。

JSONを返すAPIの例です。

@RestController
public class UserApiController {

    @GetMapping("/api/users/1")
    public UserDto getUser() {
        return new UserDto(1, "山田太郎", "yamada@example.com");
    }
}

UserDtoです。

public class UserDto {

    private int userId;
    private String name;
    private String email;

    public UserDto(int userId, String name, String email) {
        this.userId = userId;
        this.name = name;
        this.email = email;
    }

    public int getUserId() {
        return userId;
    }

    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }
}


返ってくるJSONです。

{
    "userId": 1,
    "name": "山田太郎",
    "email": "yamada@example.com"
}




@RestControllerでDTOを返すと、Spring Bootが自動的にJSONへ変換してくれます。

新人エンジニア向けに言うと、JavaのDTOをそのままreturnすれば、Spring BootがJSONに梱包して返してくれるイメージです。

@RequestBodyでJSONを受け取る

JavaScriptからJSONをPOST送信し、Spring Bootで受け取る例です。

送るJSONです。

{
    "name": "山田太郎",
    "email": "yamada@example.com"
}




受け取るJavaクラスです。

public class UserCreateRequest {

    private String name;
    private String email;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

     public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

Controllerです。

@RestController
public class UserApiController {

    @PostMapping("/api/users")
    public UserDto createUser(@RequestBody UserCreateRequest request) {

        return new UserDto(
                1,
                request.getName(),
                request.getEmail()
        );
    }
}


@RequestBodyは、リクエスト本文に入っているJSONをJavaオブジェクトに変換します。

JSONJava
"name": "山田太郎"request.getName()
"email": "yamada@example.com"request.getEmail()

JSONのキー名とJavaのプロパティ名が合っていれば、自動的に値が入ります。

Content-Typeとは何か

fetch()でJSONを送るときは、Content-Typeを指定します。

headers: {
    "Content-Type": "application/json"
}




Content-Typeは、「送っているデータの種類」をサーバーに伝えるヘッダーです。

application/jsonは、「JSONを送っています」という意味です。

たとえるなら、宅配便の箱に「冷蔵」「割れ物」「書類」とラベルを貼るようなものです。

Spring BootはContent-Typeを見て、「JSONとして読み取ればよいのだな」と判断します。

Content-Typeを付け忘れると、@RequestBodyでうまく受け取れなかったり、415 Unsupported Media Typeになることがあります。

JSONとDTOの対応

JSONとDTOは、API開発ではかなり密接に関係します。

次のJSONを考えます。

{
    "carId": 1,
    "name": "プリウス",
    "price": 2500000
}




対応するDTOです。

public class CarDto {

    private int carId;
    private String name;
    private int price;

    public int getCarId() {
        return carId;
    }

    public void setCarId(int carId) {
        this.carId = carId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

     public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}




JSONキーJavaプロパティgettersetter
carIdcarIdgetCarId()setCarId()
namenamegetName()setName()
pricepricegetPrice()setPrice()

Spring Bootは、JSONのキー名を見て、Javaのsetterへ値を入れます。

そのため、getterとsetterはとても重要です。

JSONの配列とJavaのList

JSONの配列は、JavaではListとして扱うことが多いです。

JSONの例です。

[
    {
        "carId": 1,
        "name": "プリウス",
        "price": 2500000
    },
    {
        "carId": 2,
        "name": "アクア",
        "price": 1800000
    }
]




Spring BootのControllerでは、List<CarDto>を返せます。

@GetMapping("/api/cars")
public List<CarDto> getCars() {

    List<CarDto> carList = new ArrayList<>();

    carList.add(new CarDto(1, "プリウス", 2500000));
    carList.add(new CarDto(2, "アクア", 1800000));

    return carList;
}




JavaのListがJSON配列になります。

JavaJSON
CarDto{ "carId": 1, "name": "プリウス" }
List<CarDto>[ { ... }, { ... } ]

JSONでよくあるエラー

JSONでは、文法ミスがあると正しく読み取れません。

よくあるミスを見てみましょう。

キーをダブルクォーテーションで囲んでいない

悪い例です。

{
    name: "山田太郎"
}




正しい例です。

{
    "name": "山田太郎"
}




シングルクォーテーションを使っている

悪い例です。

{
    "name": '山田太郎'
}




正しい例です。

{
    "name": "山田太郎"
}




最後に余計なカンマがある

悪い例です。

{
    "name": "山田太郎",
    "email": "yamada@example.com",
}




正しい例です。

{
    "name": "山田太郎",
    "email": "yamada@example.com"
}




JSONでは、最後の項目の後ろにカンマを付けません。

コメントを書いている

悪い例です。

{
    "name": "山田太郎",
    // メールアドレス
    "email": "yamada@example.com"
}




JSONにはコメントを書けません。

JavaScriptやJavaではコメントを書けますが、JSONでは不可です。

Spring BootでJSONがnullになる原因

fetch()でJSONを送ったのに、Spring Boot側の値がnullになることがあります。

よくある原因は次のとおりです。

原因対策
JSONキー名とJavaプロパティ名が違う"user_name" と userName名前を合わせる、または変換設定を使う
setterがないsetName()がないgetterとsetterを作る
@RequestBodyがない引数だけ書いている@RequestBodyを付ける
Content-Typeがないapplication/json未指定headersを指定する
JSON.stringifyしていないbodyにオブジェクトを直接入れるJSON.stringify()を使う

JSON連携で値が入らないときは、まず「JSONのキー名」「DTOのプロパティ名」「setter」「@RequestBody」「Content-Type」を確認してください。

JSONとHTTPメソッド

APIでは、HTTPメソッドとJSONを組み合わせて使います。

HTTPメソッド主な用途JSONを送るか
GETデータ取得通常は送らない
POST新規作成送ることが多い
PUT全体更新送ることが多い
PATCH一部更新送ることが多い
DELETE削除送らないことも多い

たとえば、ユーザー登録ではPOSTでJSONを送ります。

POST /api/users
{
    "name": "山田太郎",
    "email": "yamada@example.com"
}

ユーザー一覧取得ではGETでJSONを受け取ります。

GET /api/users

返ってくるJSONです。

[
    {
        "userId": 1,
        "name": "山田太郎"
    },
    {
        "userId": 2,
        "name": "鈴木花子"
    }
]




JSONにパスワードを含めるときの注意

ユーザー登録APIでは、JSONにパスワードを含めることがあります。

{
    "name": "山田太郎",
    "email": "yamada@example.com",
    "password": "password123"
}




この場合、Spring Boot側では受け取ったあと、必ずハッシュ化して保存してください。

パスワードをそのままDBに保存してはいけません。

また、レスポンスJSONにパスワードやpasswordHashを含めないようにします。

悪い例です。

{
    "userId": 1,
    "name": "山田太郎",
    "email": "yamada@example.com",
    "passwordHash": "{bcrypt}xxxxx"
}




良い例です。

{
    "userId": 1,
    "name": "山田太郎",
    "email": "yamada@example.com"
}




APIは外部にデータを返す窓口です。

外に出してよい情報だけをJSONに含めましょう。

JSONとバリデーション

JSONで送られてくる値も、サーバー側でバリデーションが必要です。

Request DTOにアノテーションを書きます。

public class UserCreateRequest {

    @NotBlank(message = "名前を入力してください。")
    private String name;

    @NotBlank(message = "メールアドレスを入力してください。")
    @Email(message = "メールアドレスの形式で入力してください。")
    private String email;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

     public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}




Controllerでは@Validを付けます。

@PostMapping("/api/users")
public UserDto createUser(@Valid @RequestBody UserCreateRequest request) {
    return new UserDto(1, request.getName(), request.getEmail());
}




JavaScript側で入力チェックしていても、サーバー側バリデーションは必須です。

ブラウザのチェックは回避できるからです。

JSON APIでは、受け取った値を信用しすぎないでください!

JSONとXMLの違い

昔からあるデータ形式にXMLがあります。

XMLの例です。

<user>
    <userId>1</userId>
    <name>山田太郎</name>
    <email>yamada@example.com</email>
</user>




JSONの例です。

{
    "userId": 1,
    "name": "山田太郎",
    "email": "yamada@example.com"
}




比較JSONXML
見た目短く書きやすいタグが多い
Web APIよく使われる使われる場面もある
JavaScriptとの相性良いやや扱いが重い
学習のしやすさ比較的わかりやすいタグ構造の理解が必要

現在のWeb APIではJSONがよく使われます。

ただし、金融、公共、古いシステム連携などではXMLも使われることがあります。

新人エンジニアが最初に覚えるべきJSONのルール

ルール
キーはダブルクォーテーションで囲む"name"
文字列もダブルクォーテーションで囲む"山田太郎"
数値はクォーテーションで囲まない100
true、falseはクォーテーションで囲まないtrue
nullはクォーテーションで囲まないnull
最後のカンマは書かない"email": "x@example.com"
コメントは書けない// コメント は不可
配列は角括弧を使う[1, 2, 3]
オブジェクトは波括弧を使う{ "name": "山田" }

まずは、このルールを暗記するくらいでちょうどよいです。

JSONは少しでも文法が崩れると、読み取りに失敗します。

JSONを読む練習

次のJSONを読んでみましょう。

{
    "orderId": 1001,
    "customer": {
        "customerId": 5,
        "name": "山田太郎"
    },
    "items": [
        {
            "itemId": 1,
            "name": "ノート",
            "price": 120
        },
        {
            "itemId": 2,
            "name": "ペン",
            "price": 80
        }
    ],
    "paid": true,
    "canceledAt": null
}




このJSONは、注文情報を表しています。

項目意味
orderId注文ID
customer顧客情報のオブジェクト
items注文商品の配列
paid支払い済みかどうか
canceledAtキャンセル日時。nullなので未キャンセル

JSONを読むときは、まず波括弧と角括弧に注目してください。

波括弧はオブジェクト。

角括弧は配列。

この2つが見えるようになると、複雑なJSONも読めるようになります。

まとめ

JSONは、Web APIでデータをやり取りするためによく使われる形式です。

JavaScriptのfetch()、Spring Bootの@RestController、@RequestBody、DTOなどと深く関係しています。

用語意味
JSONデータをやり取りするための文字列形式
キー項目名
項目の中身
JSON.stringify()JavaScriptオブジェクトをJSON文字列に変換する
JSON.parse()JSON文字列をJavaScriptオブジェクトに変換する
response.json()fetch()のレスポンスをJSONとして読み取る
@RequestBodyJSONをJavaオブジェクトとして受け取る
@RestControllerJSONなどのデータを返すController

一言でまとめるなら、JSONは「JavaScriptとSpring Bootなど、システム同士がデータをやり取りするための共通言語」です。

新人エンジニアは、まず次の流れを覚えてください。

JavaScriptオブジェクト
        ↓
JSON.stringify()
        ↓
JSON文字列
        ↓
fetch()で送信
        ↓
Spring Bootの@RequestBody
        ↓
Java DTO

逆方向は次の流れです。

Java DTO
        ↓
Spring BootがJSONへ変換
        ↓
HTTPレスポンス
        ↓
response.json()
        ↓
JavaScriptオブジェクト

今後の学習では、JSONの文法、JSON.stringify、JSON.parse、fetch、response.json、@RequestBody、@RestController、DTO、バリデーション、APIエラー形式を順番に学ぶとよいです。まずは小さなJSONを書き、自分でJavaScriptからSpring Boot APIへ送って、DTOに値が入るか確認してみましょう!

セイ・コンサルティング・グループでは新人エンジニア研修のアシスタント講師を募集しています。

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。

学生時代は趣味と実益を兼ねてリゾートバイトにいそしむ。長野県白馬村に始まり、志賀高原でのスキーインストラクター、沖縄石垣島、北海道トマム。高じてオーストラリアのゴールドコーストでツアーガイドなど。現在は野菜作りにはまっている。