JSON 스키마

XML의 DTD나 스키마와 유사하게 json에도 스키마에 대한 표준적인 부분이 존재하고 있는데요(http://json-schema.org/), 스키마 포맷도 json 포맷입니다.


  • {  
  •   "contentsId""123456",  
  •   "title""꽹과리",  
  •   "metadata": [  
  •     {  
  •       "propertyName""category",  
  •       "propertyContent""타악기"  
  •     },  
  •     {  
  •       "propertyName""category",  
  •       "propertyContent""동양악기"  
  •     }  
  •   ]  
  • }  

  • 위의 예제 데이터에 대한 스키마를 작성하면 다음과 같이 작성할 수 있습니다.


    스키마 포맷

    1. {  
    2.   "type""object"// 루트 타입은 객체  
    3.   "properties": { // 속성 정의  
    4.     "contentsId": {  
    5.       "type""string",  
    6.       "minLength"1  
    7.     },  
    8.     "title": {  
    9.       "type""string"  
    10.     },  
    11.     "metadata": {  
    12.       "type""array",  
    13.       "items": {  
    14.         "$ref""#/definitions/metadataItem" // definitions내의 정의 참조  
    15.       }  
    16.     }  
    17.   },  
    18.   "required": [ // 필수 속성  
    19.     "contentsId"  
    20.   ],  
    21.   "definitions": { // 루트 타입 외 타입 별도 정의  
    22.     "metadataItem": {  
    23.       "type""object",  
    24.       "properties": {  
    25.         "propertyName": {  
    26.           "type""string"  
    27.         },  
    28.         "propertyContent": {  
    29.           "type""string"  
    30.         }  
    31.       },  
    32.       "required": [  
    33.         "propertyName",  
    34.         "propertyContent"  
    35.       ]  
    36.     }  
    37.   }  
    38. }  



    위에 사용한 규칙 외에도 많은 규칙들이 있는데 몇 가지 예로 다음과 같은 것들이 있습니다.

    - 값 pattern 체크 (pattern)

    - 배열 내의 아이템 갯수 (minItems, maxItems)

    - enum을 통한 값체크

    - 여러 규칙 중 하나를 만족하는 경우 체크 (oneOf)

    - 여러 규칙 중 적어도 하나를 만족하는 경우 체크 (anyOf)


    더 상세한 내용은 json schema 사이트 내의 문서(http://json-schema.org/latest/json-schema-validation.html)에서 확인하실 수 있습니다.


    항상 스키마를 통해서 유효성을 체크하는게 좋은 선택은 아니겠지만, 어느 정도 세세한 체크가 필요하다면

    그 부분에 대한 로직을 작성하는 것보다 스키마를 활용하는게 좋을 선택이 될 수 있을 것 같습니다.


    validator 라이브러리

    jackson이나 Gson 라이브러리에 스키마를 통한 유효성 검증 기능이 있으면 좋겠지만

    그렇지 않아서 외부 라이브러리를 사용해야합니다.


    언어 별로 여러 구현 라이브러리들이 있는데

    자바에서는 json-schema-validator(https://github.com/java-json-tools/json-schema-validator)가 많이 사용되는 것 같습니다.


    json-schema-validator 사용 예제


    1. import java.io.IOException;  
    2.   
    3. import org.springframework.core.io.ClassPathResource;  
    4.   
    5. import com.fasterxml.jackson.databind.JsonNode;  
    6. import com.fasterxml.jackson.databind.ObjectMapper;  
    7. import com.github.fge.jsonschema.core.exceptions.ProcessingException;  
    8. import com.github.fge.jsonschema.core.report.ProcessingReport;  
    9. import com.github.fge.jsonschema.main.JsonSchema;  
    10. import com.github.fge.jsonschema.main.JsonSchemaFactory;  
    11.   
    12. public class JsonValidation {  
    13.     private static ObjectMapper objectMapper = new ObjectMapper();  
    14.   
    15.     public static void main(String[] args) throws IOException, ProcessingException {  
    16.         ClassPathResource jsonSchemaResource = new ClassPathResource("schema.json"); // schema 파일  
    17.         JsonNode schemaNode = objectMapper.readTree(jsonSchemaResource.getInputStream());  
    18.   
    19.         ClassPathResource jsonResource = new ClassPathResource("sample.json"); // json 파일  
    20.         JsonNode jsonNode = objectMapper.readTree(jsonResource.getInputStream());  
    21.   
    22.         JsonSchemaFactory factory = JsonSchemaFactory.byDefault();  
    23.         JsonSchema schema = factory.getJsonSchema(schemaNode);  
    24.         ProcessingReport report = schema.validate(jsonNode); // validation 체크  
    25.   
    26.         if (report.isSuccess()) {  
    27.             System.out.println("json is valid.");  
    28.         } else {  
    29.             System.out.println("json is not valid.");  
    30.             System.out.println("report : " + report);  
    31.         }  
    32.     }  
    33. }  



    다른 예제 코드들도 프로젝트 페이지(https://github.com/java-json-tools/json-schema-validator/tree/master/src/main/java/com/github/fge/jsonschema/examples)에서 확인할 수 있습니다.


    validate 메소드를 호출하려면, validate할 jsonNode를 파서로 먼저 읽어와야 하기 때문에

    만약 한번에 validate할 범위가 너무 크다면 메모리를 많이 사용할 수 있어서 주의가 필요한 부분입니다.


    처리해야할 json 데이터양이 많다면 위 예제처럼 한번에 처리하는 방식 대신에

    스키마 파일에는 반복되는 데이터 구조 부분만 정의해두고

    streaming api로 부분부분 읽어와서 validate하는 방식으로 개발하는 방법을 활용해볼 수 있을 것 같습니다.