JSON 은 왜 그모양일까 ?

JSON의 정의와 관련된 ECMA-404 문서를 통해 숫자 문자열 '900101'이 JSON으로 인식되는 이유를 자세히 알아봅니다.

Contents


이것은 JSON 일까 ?

JSON 관련된 코드를 테스트 하다, 예상과 다른 코드의 동작 때문에 장애를 낼 뻔한 적이 있다. 다음의 코드를 살펴보자

const is = {
  jsonString: (str: string) => {
    try {
      JSON.parse(str);
    } catch (e) {
      return false;
    }
    return true;
  }
}

const birthday = '900101';
if(is.jsonString(birthday)) {
  throw new Error(`${birthday} is JSON`);
}

위의 코드를 실행하면 에러가 발생할까 ? 놀랍게도 위의 코드는 에러를 발생시키는 코드이다.

처음에는 자바스크립트는 왜 그 모양일까 ? 책에 나올법한 또다른 자바스크립트의 버그일 것이라 생각했다. 하지만 python의 json 내장 라이브러리, 자바/코틀린의 jackson-databind 라이브러리 모두 동일한 동작을 하는 것을 확인했다. 어떠한 이유로 900101 은 JSON 인 것일까 ?



ECMA-404

json.org 문서를 읽어보다, ECMA-404 문서에 JSON 의 정의가 명시되어 있다는 힌트를 얻었다. ECMA-404 (2nd Edition) 공식문서를 찾았고, 위의 문제에 대한 실마리를 찾을 수 있었다.

핵심적인 내용을 정리하면 다음과 같다.

  1. A JSON text is a sequence of tokens formed from Unicode code points that conforms to the JSON value grammar. The set of tokens includes six structural tokens, strings, numbers, and three literal name tokens.
  2. A JSON value can be an object, array, number, string, true, false, or null. (각 값들의 정의는 ECMA-404 문서에 구체적으로 정의되어 있으니 참고)

위의 정의에 명시된 six structural tokens 은 다음과 같다.

[ U+005B left square bracket
{ U+007B left curly bracket
] U+005D right square bracket
} U+007D right curly bracket
: U+003A colon
, U+002C comma

three literal name tokens 는 다음과 같다.

true U+0074 U+0072 U+0075 U+0065
false U+0066 U+0061 U+006C U+0073 U+0065
null U+006E U+0075 U+006C U+006C

정리해 보면, JSON 은 JSON value 문법을 지키는 문자열(JSON text)을 의미하며, JSON text 는 six structural tokens, numbers, three literal name tokens 이다. 어떠한 문자열이 위의 2가지 정의를 만족한다면, 그 문자열은 JSON 집합에 들어간다.


ECMA-404 요약



다시, 이것은 JSON 일까 ?

ECMA-404 의 정의를 토대로, 다음의 값들을 판별해 보자.

/** true */
is.jsonString(1234);
is.jsonString('"abcd"');
is.jsonString(null);
is.jsonString(true);

/** false */
is.jsonString('abcd');

이때, 가장 마지막 조건인 'abcd' 는 JSON 이 아니다. 이 또한 ECMA-404 에서 그 근거를 찾을 수 있다.

A string is a sequence of Unicode code points wrapped with quotation marks (U+0022). 따라서, '"abcd"' 는 JSON 이지만, 'abcd' 는 올바른 JSON 이 아니다.


이것도 읽어보세요