최근 수정 시각 : 2024-03-12 16:35:57

JSON


1. 개요2. 구조3. 특징4. 단점5. JSONP6. 관련 문서


파일:홈페이지 아이콘.svg

JavaScript Object Notation

1. 개요

JSON은 일반적으로 서버에서 클라이언트로 데이터를 보낼 때 사용하는 양식으로, '제이슨'으로 읽는다. 클라이언트가 사용하는 언어에 관계 없이 통일된 데이터를 주고받을 수 있도록, 일정한 패턴을 지닌 문자열을 생성해 내보내면 클라이언트는 그를 해석해 데이터를 자기만의 방식으로 온전히 저장, 표시할 수 있게 된다.

과거 웹 초기 시절부터 사용된 XML은 헤더와 태그 등의 여러 요소로 가독성이 떨어지고, 쓸데없이 용량을 잡아먹는다는 단점을 항상 지적받았다. 이에 대응해 간결하고 통일된 양식으로 각광을 받고 있는 것이 JSON이다.

2. 구조

#!syntax json
{
  "이름공간(키)": "값",
  "값 구분자": "각각의 값들은 ',' (콤마)로 구분되어야 합니다.",
  "이스케이프": "키나 값에서 큰따옴표를 쓰고 싶으면-특정 문자를 이스케이프 하려면- \" 처럼 문자 앞에 역슬래시를 붙입니다.",
  "자료형": "표현 가능한 자료형은 문자열, 숫자, 불리언, 널, 객체, 배열 6개입니다.",
  "문자열 값": "나무위키, 여러분이 가꾸어 나가는 지식의 나무",
  "숫자 값": 19721121,
  "불리언 값": true,
  "널 값": null,
  "객체 값": {
    "값1": 3.14159265358979323846264338,
    "값2": false,
    "값3": {
      "객체 안에": "객체를 넣는것도 가능하지요",
      "구분자": "또한 키와 값은 ':' 로 구분됩니다"
    }
  },
  "배열 값": [
    "이것은 배열입니다.",
    {
      "현재 값의 인덱스": 1,
      "이런 식으로": "배열 안에 여러 값을 넣을 수 있습니다."
    },
    [ "배열", "안에", "배열을", "넣는것도", "가능하지요" ]
  ],
  "값의 개수가 적을때는": "다음과 같이 한 줄로도 객체와 배열 표현이 가능합니다.",
  "한 줄 객체": { "김두한": "나 김두한이다", "심영": "내가 고자라니", "의사양반": "병신을 만들어주마" ,  "이근": "4번은 개인주의야" },
  "한 줄 배열": [ "나무위키는", "누구나", "기여할", "수", "있는", "위키입니다." ]
}

{ }​ 안의 것은 속성명(혹은 키, 이름공간)이 있는 객체를 의미하며, [ ] 안의 것은 순서가 있는 배열[1], 객체 안에 객체를 넣을 수도 있어서 XML처럼 복잡한 구조 또한 표현이 가능하다. 표현할 수 있는 값의 자료형은 { }​로 표기되는 객체, [ ]로 표기되는 배열, 문자열, 숫자, 불리언, null의 6가지가 전부다. 또한 null의 존재에서 알 수 있듯, JSON은 JavaScript 이외의 언어에서 사용될 상황을 다분히 고려하고 있다.[2]

root 값은 객체 뿐만 아니라 배열로도 표현 가능하다. 사실 문자열이나 숫자, null등 모든 json값으로 쓰일 수 있는 자료형은 그 자체로도 유효한 json이다. 즉 "문자열" 또한 유효한 json형식이며, .json파일에 이 내용만 담겨져 있거나 이 상태로 요청을 보낼 수 있다는 뜻이다. 다만 실용성이 없기 때문에 쓰이지 않을 뿐이다.
#!syntax json
[
  { "나무위키": "여러분이 가꾸어 나가는 지식의 나무" },
  { "위키백과": "우리 모두의 백과사전" },
  { "백과사전": "너희 모두의 백과사전" },
  { "위키낱말사전": "말과 글의 누리" }
]


===# 문법 #===
json은 현재까지 알려진 데이터 직렬화 형식중에서 CSV만큼 간단하면서, 복잡한 데이터를 표현 가능한 포맷 중 하나이다. 문법이 간단하다는 것은 사람이 배우고 쓰기 쉬운 것뿐만 아니라, 기계가 읽고(파싱) 처리하기도 매우 쉽다는 것을 의미한다.

json의 문법 표준은 ECMA[3]와 IETF에 각각 ECMA-404 RFC 8259로 등록되어 있으며, 이 내용은 ECMA를 기준으로 하지만 RFC 표준안과의 차이점은 없다.

본격적으로 문법을 설명하기 전에 유의해야 할 점은, json은 공백에 영향을 받지 않는다는 점이다. 정확히 말하면, json의 토큰은 6개의 사전 정의된 문자({, \}, \[, ], :, ,)와 3개의 리터럴(true, false, null)로 이루어지며, 각 토큰 사이에 들어간 모든 공백은 무시된다.

또한 숫자도 다양하게 표현할 수 있는데, 이는 정수와 부동소수점을 구분하지 않는 자바스크립트에서 유래된 특징이다. 따라서 음수(-123)나 소수(3.1215), 정규화 표현(-12.34e56) 등을 섞어서 사용할 수 있다. 단, JS만의 고유 숫자 값인 NaN(IEEE 표준)이나 Infinity, -Infinity등은 사용이 불가능하다.

많은 사람들이 모르고 지나치는 것 중 하나이지만, 유효한 json값은 모두 유효한 json문서이기도 하다. 예를 들어 false[1, "a"]등(중괄호로 감싸지지 않은 값들)도 모두 하나의 json문서로 인식되며, 따라서 .json파일에 저 값만 저장하거나 API응답으로 저 값만 보내도 유효한 application/json으로 인식된다. 이 장점은 실제로 거의 쓸 일은 없지만 문서 하나에 배열만 저장하는 등의 경우는 생각보다 많으며, 이를 극대화시킨 것이 바로 YAML이다.
#!syntax yaml
- key: value
- name: "object in array!"
위 예제는 괄호 하나 없이 '객체의 배열'을 yaml문서로 사용한다.

더욱 정확한 문법은 아래를 참고하자. 아래는 ECMA표준안을 기반으로 하여 EBNF 표기법으로 나타낸 완전한 json문법이다.
<json> ::= <value>
<value> ::= <object> | <array> | <number> | <string> | <bool> | null
<object> ::= '{' [ <string> : <value> , { <string> : <value> } ] '}'
<array> ::= '[' [ <value> , { <value> } ] ']'
<number> ::= [ - ] (0 | <digit 1-9> { <digit> }) [ . { <digit> } ] [ (e | E) [ (+ | -) ] { <digit> } ]
<digit> ::= 0 | <digit 1-9>
<digit 1-9> ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<string> ::= " { (<"또는 \또는 제어 문자를 제외한 모든 문자> | \(" | \ | / | b | f | n | r | t | u <hex><hex><hex><hex>)) } "
<hex> ::= a | b | c | d | e | f | A | B | C | D | E | F | <digit>
<bool> ::= true | false

실제로는 bool이라는 항목이 없고 truefalse가 개별 토큰으로 존재하지만, 여기서는 편의를 위해 NTC로 표시한다. 또 string의 경우 특정 제어 문자를 제외한 문자 집합으로 정의되는데, 설명이 다소 장황하지만 정규표현식[^]와 같은 개념이라고 이해하면 편하다.

더 알아보고 싶다면 json.org ECMA 스펙을 참고하자.

3. 특징

그래도 표면적으로 W3C 표준 XML인데, 그것과는 무관하게 JSON은 2009년 말 Ecma에 의해 ECMAScript5에서 스크립트 엔진의 기본 기능으로 내장되어 버렸기 때문에 새롭게 출시되는 브라우저들 기준에서는 DOM을 통해 XML 파싱하는 것보다 JavaScript 엔진에서 JSON을 메모리로 받는 쪽이 성능으로 보나 트래픽으로 보나 훨씬 더 나은 선택이 되어버렸다. 그런 관계로 웹에서 XML은 본격 계륵화가 진행중...

기본적으로 JavaScript 객체 표기법의 부분집합이기 때문에 웹 브라우저 레벨에서 쉽게 해석할 수 있으며, 모양과 규칙 자체가 단순한 관계로 다른 언어에서 구현하기도 쉽다. 그래서 오늘날 사용되는 거의 모든 프로그래밍 언어에서 사용가능하다. 이러한 지원에 힘입어 AJAX 구현에도 상당히 빈번하게 쓰인다.

엄청나게 단순하지만 유연한 표기법이기 때문에 언어와 독립된 표준적인 데이터 표기법으로 확산되고 있다. 본래의 범위를 넘어서 바이너리 데이터 표기용으로 마개조한 BSON(MongoDB에서 이용)도 있으며, NoSQL DB중 DocumentDB들에서는 그냥 표준 표기법으로 취급되고 있다. 최근에는 NoSQL뿐만 아니라 관계형DB인 PostgreSQL에서도 지원하기 시작. MySQL에서도 5.7에서 공식 지원한다.

그러나 확산되고 있다고 해도 어디까지나 웹 브라우저가 주가 되는 환경, 특히 사용자에게 보여주는 HTML 과 이를 실시간으로 가공하는 JavaScript가 연동하는 환경 위주로 퍼지고 있으며, 그렇지 않은 곳에서는 여전히 XML을 사용하는데 문제가없다. XML 파서도 다양한 플랫폼에 구현돼있고 XML이란 놈이 딱히 무슨 결함이 있는 것도 아니며 결정적으로 XML에는 스키마(Schema)가 있어서 데이터의 무결성을 검증할 수 있다. JSON도 데이터의 무결성을 검증하는 역할을 전적으로 그걸 스키마측에 떠맡긴다. 다만 JSON이 웹을 시작으로 편의성이 널리 알려지면서 최근 들어 다양한분야로 많이 쓰이는중이다.

그리고 JSON도 적용되는 곳이 늘어남에 따라 XML과 같이 valid한 검증이 필요해졌으며, Namespace 문제가 발생하는 경우가 늘고 있다. 이를 극복하기 위해 JSON-Schema, JSON-LD(JSON Linking Data) 같은 것이 등장하고 있다.

Unity3D 엔진에서 플러그인으로 시리얼라이저와 디시리얼라이저를 제공하기 시작하면서 모바일 플랫폼에서도 대거 사용되기 시작한다. CSV 등 기존 포멧에 비해 태그에 의한 데이타 확장과 변형이 용이하고 과거에 비해 데이타 사용량이 자유롭기 때문에 이런 현상이 가속화 되고 있다. (단적인 예로 많은 게임 데이터들이 제이슨으로 되어있다.)

Sublime Text, Visual Studio Code, Visual Studio에서는 환경 설정 파일에 JSON을 사용하고 있다.

ECMAScript는 5부터 Trailing comma(후행 쉼표)를 지원하지만 JSON은 그 이전에 규격이 정해졌기 때문에 Trailing comma를 지원하지 않는다.

http://www.json.org에서 표기법과 언어별 지원 라이브러리를 볼 수 있다.

참고

4. 단점

XML이나 다른 데이터 기술 형식에 비해 아래와 같은 단점이 있다.
  • 주석을 지원하지 않는다. 그래서 설정 파일을 JSON으로 작성할 때 어려움이 있다.[4]
  • 데이터 타입을 강제하려면 JSON 스키마로 보완해야 한다.
  • 날짜, 시간 데이터를 지원하지 않는다.[5]

위와 같은 단점을 보완하고자 YAML 등의 대체 포맷을 쓰기도 하지만, 위의 단점은 큰 문제가 아니라서 JSON은 2017년 11월 현재도 XML과 대등하게 널리 쓰이고 있다.

5. JSONP

OpenAPI 서비스 중 도메인이 서로 다른 곳끼리의 통신을 위한 규약인 CORS가 설정되지 않은 구형 서비스에서 JSON 데이터를 돌려줄 때 사용하는 데이터 형식이다. P는 패딩(Padding)의 약어로, HTML script 태그를 이용하면 CORS를 우회하여 외부 스크립트를 실행할 수 있다는 점을 이용해 JSON 데이터 객체를 클라이언트가 지정한 callback 함수를 호출하는 유효한 JavaScript 스크립트 형식으로 패딩하여 돌려준다. callback 함수의 이름은 요청자가 정해서 서버에 넘겨준다. 예로 jQuery의 jsonp는 jQuery89034758903475같은 난수 이름을 자동으로 생성한다.

예를 들어 https://jsonplaceholder.typicode.com/posts/1?callback=__cb12345를 호출하면 아래와 같은 응답이 돌아온다.

#!syntax javascript
/**/ typeof __cb12345 === 'function' && __cb12345({
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
});

기본적으로 이 JSONP의 목적은 웹 브라우저 내에서의 CORS가 설정되지 않은 호스트와의 통신을 위한 것으로, 웹 브라우저 밖에서는 Same Origin 정책이 적용되지 않기 때문에 JSONP를 이용할 필요가 없다. 또한 API를 직접 건드릴 수 있다면 CORS 정책을 직접 설정하는 것이 좋다.

6. 관련 문서


[1] 내부적으로 0, 1, 2, ... 와 같은 숫자로 된 이름표(인덱스)가 자동으로 주어진다. 위 예제에 의하면 "0": "나무위키는", "1": "누구나", ... 의 순서로 이름표가 매겨진다. [2] JavaScript에서는 값이 없다는 뜻으로 undefined 키워드가 쓰이고 있다. null은 주로 프로그래머가 의도적으로 비워놓은 값을 표현하는데 쓴다. [3] ECMAScript(자바스크립트)를 표준화한 곳이다. [4] 키의 이름을 _comment 등으로 하고 값에 주석을 작성하는 경우도 있으나, 이 경우 JSON을 파싱할 때 주석도 같이 파싱된다. [5] 주로 AJAX로 시간 데이터가 포함된 데이터를 가져오는 경우 문제가 생긴다. (블로그 글을 보면 해당 글을 포스트한 시간, 가장 최근 수정한 시간 등이 있음을 떠올려 보자.) 은근히 자주 겪게 되는 문제이기 때문에 비표준이긴 하지만 나름대로의 패턴이 생겨서, 문자열로 저장할 때 RFC3339yyyymmdd등 흔히 쓰이는 형식으로 포맷하면 웬만큼 똑똑한 파서는 알아서 인식해서 처리해 주거나 별도의 옵션이 있는 경우가 많다. 데이터 크기를 최대한 줄여야 할 때는 유닉스 시간으로 바꿔서 숫자로 보내는 편이다.