1. 소개
자, 이미 객체를 JSON으로(또는 그 반대로) 변환할 수 있겠죠. 그런데 프로그램에 뭔가… 이상한 게 들어오면요? 예를 들어, 다음 같은 JSON을 예상했는데:
{
"id": 123,
"name": "Alice",
"email": "alice@example.com"
}
그런데 받은 건:
{
"name": 42,
"id": "not a number"
}
네, C#의 직렬화/역직렬화 도구들은 이런 난장판을 '정직하게' 역직렬화하려 하겠지만, 대개는 런타임 오류, 데이터 손실이나 심지어 비즈니스 중단으로 이어집니다. 데이터를 다른 곳으로 넘기거나 DB에 저장하거나 네트워크로 보내기 전에, 데이터가 유효한지 확인하세요 — 그렇지 않으면 코드가 안전장치 없는 곡예사처럼 됩니다.
그래서 검증이 필요한 거예요: JSON이 규칙 — 값의 타입, 필수 필드, 허용 범위, 구조 등 — 에 맞는지 자동으로 확인하는 과정입니다.
2. JSON을 검증하는 방법들
C#/.NET에서는 주로 세 가지 접근이 있어요:
- 직접 코드로 검증: 객체를 수동으로 파싱하고 검증을 작성해서 에러 시 예외를 던집니다.
- 모델에 검증 어트리뷰트 사용: 예를 들어, [Required], [Range], [EmailAddress]는 System.ComponentModel.DataAnnotations 네임스페이스에서 제공됩니다.
- JSON Schema로 검증 — 오늘의 주인공이에요!
JSON Schema는 유효한 문서가 어떻게 생겼는지 형식적으로 기술할 수 있는 표준입니다. 스키마 자체도 JSON으로 작성되죠. 어떤 필드가 필요한지, 타입은 무엇인지, 어떤 값이 허용되는지 등을 정의할 수 있어요.
스키마로 다음을 설명할 수 있습니다:
- 어떤 필드가 존재해야 하는지.
- 어떤 타입이 예상되는지 (string, array, number, object 등).
- 어떤 필드가 필수이고 어떤 필드가 선택인지.
- 값의 범위(예: 나이 0에서 150 사이).
- 패턴, 길이, 허용값 목록 등.
가장 단순한 스키마 예제
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" }
},
"required": ["id", "name"]
}
3. JSON Schema의 주요 요소
예제를 보면서 주요 키들이 무슨 의미인지 정리해볼게요.
| 키 | 설명 | 예제 |
|---|---|---|
|
JSON Schema 표준 버전 링크 | |
|
값의 타입 (object, array, string, number 등) | |
|
객체의 속성 설명 | |
|
필수 필드의 배열 | |
|
배열 요소의 타입 설명 | |
|
허용 가능한 값들의 목록 | |
, |
숫자에 대한 제약 | |
, |
문자열 길이 제한 | |
|
문자열에 대한 정규식 | |
시각적으로: 사람 배열에 대한 스키마 예제
{
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string", "minLength": 2, "maxLength": 50 },
"email": { "type": "string", "format": "email" }
},
"required": ["id", "name"]
}
}
4. C#에서 JSON을 스키마에 대해 검증하는 방법
현재(.NET 9 기준) .NET에는 JSON Schema에 대한 표준 지원이 없습니다. 실무에서는 외부 라이브러리를 사용해요: NJsonSchema 또는 Newtonsoft.Json.Schema (Json.NET Schema).
Newtonsoft.Json.Schema (Json.NET Schema) 패키지 설치
프로젝트 폴더에서 터미널에 다음을 입력하세요:
dotnet add package Newtonsoft.Json.Schema
중요: Newtonsoft.Json.Schema는 상용 라이브러리지만 비상업적 용도는 무료입니다. 개인 프로젝트에 잘 어울려요.
JSON을 스키마에 맞게 검증하는 예제
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;
string schemaJson = @"{
'type': 'object',
'properties': {
'id': { 'type': 'integer' },
'name': { 'type': 'string' },
'email': { 'type': 'string', 'format': 'email' }
},
'required': ['id', 'name']
}";
// 예를 들어, 이런 JSON이 있다고 가정해보자
string json = @"{
'id': 123,
'name': 'Alice',
'email': 'alice@example.com'
}";
// 먼저 스키마를 파싱
JSchema schema = JSchema.Parse(schemaJson);
// JSON 자체를 JToken으로 파싱
JToken jsonObj = JToken.Parse(json);
// JSON이 스키마에 맞는지 검사
bool valid = jsonObj.IsValid(schema, out IList<string> errors);
if (valid)
{
Console.WriteLine("JSON 유효!");
}
else
{
Console.WriteLine("JSON 유효하지 않음!");
foreach (var error in errors)
Console.WriteLine(error);
}
애플리케이션에서 JSON 검사를 어떻게 사용할까?
보통은: 먼저 검증(IsValid), 그다음 역직렬화(JsonConvert.DeserializeObject<T>), 그리고 비즈니스 로직을 진행합니다. 이렇게 하면 초기에 쓰레기 데이터를 걸러낼 수 있어요.
if (jsonObj.IsValid(schema))
{
// 괜찮다, 역직렬화해도 됨
var person = JsonConvert.DeserializeObject<Person>(json);
}
else
{
// 처리 중단! 데이터가 올바르지 않음.
}
5. JSON Schema의 실제 활용
언제 검증이 필요할까?
- API로 들어오는 데이터(특히 외부 시스템이나 다양한 클라이언트로부터)를 받을 때.
- 마이크로서비스나 데이터베이스 간 데이터 마이그레이션 시.
- 스키마 기반으로 UI 폼을 생성하거나 자동 완성할 때.
- 면접 질문으로도 자주 나옵니다: "잘못된 JSON이 들어오면 어떻게 할래?" 같은 질문.
흥미로운 팁(호기심 있는 사람들을 위해)
- 포맷 검사: "format": "email", "date-time".
- 복합 규칙: anyOf, oneOf, allOf.
- 중첩된 객체와 배열 검증.
- 필요에 맞게 스키마 확장하기.
6. 큰 실전 예제
입력 데이터(유저 목록):
[
{ "id": 1, "name": "Alice", "email": "alice@example.com" },
{ "id": 2, "name": "Bob" },
{ "id": "이게 뭐지?", "name": 123, "email": "not-an-email" }
]
스키마:
{
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string", "minLength": 2, "maxLength": 50 },
"email": { "type": "string", "format": "email" }
},
"required": ["id", "name"]
}
}
.NET에서의 검사:
string jsonArray = @"[ ... ]"; // 위 참조
string schemaJson = @"{ ... }"; // 위 참조
JSchema schema = JSchema.Parse(schemaJson);
JToken arrayToken = JToken.Parse(jsonArray);
bool isValid = arrayToken.IsValid(schema, out IList<string> errs);
if (!isValid)
{
foreach (var error in errs)
Console.WriteLine(error);
// 예시 메시지:
// "String '이게 뭐지?' is not a valid integer."
// "Integer 123 is not a valid string."
// "String 'not-an-email' is not a valid email address."
}
7. JSON 스키마 작업 시 흔한 실수들
오류 #1: 스키마와 실제 데이터 불일치. 모델을 변경한 뒤 스키마 업데이트를 잊는 경우가 많습니다. 그러면 검증이 오류를 놓치거나 정상 데이터를 차단할 수 있어요.
오류 #2: 스키마와 모델의 타입 불일치. 예를 들어 모델의 필드 타입이 바뀌었는데(예: id가 문자열로 바뀜) 스키마에는 여전히 integer로 남아 있으면 밸리데이터가 에러를 냅니다.
오류 #3: 비즈니스상 필수 필드 누락. 필드가 required로 표시되지 않았다 하더라도 비즈니스 로직이 그 필드에 의존하면, 누락 시 장애가 발생합니다.
오류 #4: 잘못된 데이터 포맷. email이나 날짜 같은 string 필드는 겉보기엔 문자열이지만 유효하지 않을 수 있습니다. format이나 추가 검증을 사용하세요.
오류 #5: 라이브러리 구현이 표준을 따라가지 못함. 표준은 발전하는데 라이브러리는 항상 따라오지 못합니다. 일부 검사가 없거나 다르게 동작할 수 있어요.
GO TO FULL VERSION