JSON Schema의 활용
42953 단어 JSON schemaJSON schema
JSON Schema의 활용
- JSON Schema를 활용하기 위해서는 여러 라이브러리들이 필요합니다.
- JSON Schema를 활용한 Validator 자동화
- Ajv 라이브러리
- 자동 타입 변환 및 생성
- Json-schema-to-ts 라이브러리
- 국내에서는 JSON Schema와 타입스크립트를 활용하는 정보를 찾아볼 수 없었습니다.
Ajv 라이브러리
1. Ajv란?
- Node.js / 브라우저를 위한 JSON Validator를 생성해주는 라이브러리 입니다.
- 최신 JSON Type Definition RFC8927 지원 ( Multi Standard 지원 )
- JSON Schema 공식문서에도 JS를 활용할 때 Ajv 라이브러리를 추천하고 있습니다.
- JSON Schema를 v8 엔진 최적화를 통해 초고속으로 Validator를 생성합니다.
- JSON Schema를 활용한 Validator 자동화
- Ajv 라이브러리
- 자동 타입 변환 및 생성
- Json-schema-to-ts 라이브러리
- 최신 JSON Type Definition RFC8927 지원 ( Multi Standard 지원 )
- 타입스크립트를 지원하며 타입가드 형태로 활용할 수 있습니다.
- MIT 라이센스이며 주간 다운로드 수는 약 68,000,000로 엄청난 인기를 받고 있습니다.
- 약 2달전에 업데이트를 진행하였고 꾸준하게 릴리즈 되고 있습니다.
- 참고
- v8 기준으로 문서 작성
- 공식문서
2. Ajv 사용해보기
- 설치
npm install ajv
활용 예시 ( 크게 2가지 )
-
JSON Schema / JSON Type Definition
-
Ajv는 스키마를 함수로 컴파일하고 모든 경우를 캐시 합니다.
- 동일한 스키마 객체가 사용될 때 다시 컴파일 되지 않습니다.
- 즉 이 기능을 활용하려면 validater 함수를 재사용해야 합니다. ( 권장 )
- 캐시 활용법
-
JSON Schema 예시
const Ajv = require("ajv");
const ajv = new Ajv();
const schema = {
type: "object",
properties: {
name: { type: "string" },
age: { type: "integer" },
},
required: ["name"],
additionalProperties: false,
};
// create Validation Function
const validate = ajv.compile(schema);
// Test Success Data
const successed_data = {
name: "woodong",
age: 3,
};
// Test Fail Data
const failed_data = {
name: "woodong",
age: "3",
};
const valid_1 = validate(successed_data);
const valid_2 = validate(failed_data);
// 검증
if (!valid_1) {
console.log(validate.errors);
}
if (!valid_2) {
console.log(validate.errors);
}
// 실패 Log
[
{
instancePath: '/age',
schemaPath: '#/properties/age/type',
keyword: 'type',
params: { type: 'integer' },
message: 'must be integer'
}
]
- JSON Type Definition 예시
const Ajv = require("ajv/dist/jtd");
const ajv = new Ajv();
const schema = {
properties: {
name: { type: "string" },
},
optionalProperties: {
age: { type: "int32" },
},
};
const validate = ajv.compile(schema);
const data = {
name: "woodong",
age: 28,
};
const valid = validate(data);
if (!valid) console.log(validate.errors);
- JSON Tpye Definition의 Parsing and Serializing 기능
- 기존
JSON.stringify
( JS 코드를 JSON 문자열로 변환 )보다 10배 이상 빠릅니다. - 기존
JSON.parse
( JSON 문자열의 구문을 분석하고 JS 객체 형태로 변환)와 속도가 비슷합니다.- JSON이 유효하지 않을 경우
JSON.parse
보다 더 빨리 실패함으로 더 효율적일 수 있습니다. - 빈 스키마일 경우({}) 성능은
JSON.parse
가 더 좋습니다.
- JSON이 유효하지 않을 경우
- 기존
const Ajv = require("ajv/dist/jtd");
const ajv = new Ajv();
const schema = {
properties: {
name: { type: "string" },
},
optionalProperties: {
age: { type: "int32" },
},
};
// create serialize function
const serialize = ajv.compileSerializer(schema);
const data = {
name: "woodong",
age: 28,
};
// result: {"name":"woodong","age":32}
console.log(serialize(data));
// create parse function
const parse = ajv.compileParser(schema);
const json = '{"name": "woodong", "age": 28}';
const invalidJson = '{"unknown": "abc"}';
// result: { name: 'woodong', age: 28 }
console.log(parse(json));
// result: undefind => 예외 처리 제공하지 않음 ( parse 함수 자체 내장 )
console.log(parse(invalidJson));
// parseAndLog 함수 ( 따로 구현 필요 )
function parseAndLog(json) {
const data = parse(json);
if (data === undefined) {
console.log(parse.message); // error message from the last parse call
console.log(parse.position); // error position in string
} else {
console.log(data);
}
}
// property unknown not allowed
// 11
console.log(parseAndLog(invalidJson));
3. 타입스크립트 적용 ( 미리 선언해야 가능 )
-
tsconfig.json
옵션에strictNullChecks: true
추가해야함strictNullChecks
: 개발자가null
/undefinded
값을 참조하는 것을 방지
-
JSON Schema 예시
import Ajv, { JSONSchemaType } from "ajv";
const ajv = new Ajv();
interface userType {
name: string;
age?: number;
}
const schema: JSONSchemaType<userType> = {
type: "object",
properties: {
name: { type: "string" },
age: { type: "integer", nullable: true },
},
required: ["name"],
additionalProperties: false,
};
// create Validation Function
const validate = ajv.compile(schema);
// Test Success Data
const successed_data = {
name: "woodong",
age: 3,
};
// Test Fail Data
const failed_data = {
name: "woodong",
age: "3",
};
const valid_1 = validate(successed_data);
const valid_2 = validate(failed_data);
// 검증
if (!valid_1) {
console.log(validate.errors);
}
if (!valid_2) {
console.log(validate.errors);
}
- JSON Type Definition 예시
import Ajv, { JTDSchemaType } from "ajv/dist/jtd";
const ajv = new Ajv();
interface userType {
name: string;
age?: number;
}
const schema: JTDSchemaType<userType> = {
properties: {
name: { type: "string" },
},
optionalProperties: {
age: { type: "int32" },
},
};
const validate = ajv.compile(schema);
const data = {
name: "woodong",
age: 28,
};
const valid = validate(data);
if (!valid) console.log(validate.errors);
- JSON Type Definition에서 Type 추출
- 완벽하게 Type / Interface를 생성해주지는 않습니다.
import Ajv, { JTDDataType } from "ajv/dist/jtd";
const ajv = new Ajv();
const schema = {
properties: {
name: { type: "string" },
},
optionalProperties: {
age: { type: "int32" },
},
} as const;
type userType = JTDDataType<typeof schema>;
const validate = ajv.compile<userType>(schema)
/* 예상 Type
type userType2 = {
name: string;
age?: number;
};
*/
/* 변경된 type
type userType = {
name: string;
} & {
age?: number | undefined;
}
*/
- union 형태 지원
import Ajv, { JSONSchemaType } from "ajv";
const ajv = new Ajv();
type MyUnion = { prop: boolean } | string | number;
const schema: JSONSchemaType<MyUnion> = {
anyOf: [
{
type: "object",
properties: { prop: { type: "boolean" } },
required: ["prop"],
},
{
type: ["string", "number"],
},
],
};
- Generic 적용
- 공식문서에는 언급하고 있지 않습니다.
- 개인적으로 적용한 결과 지원하는 것 같습니다.
- 문제점
- JSON Shema 특성상 여러가지 Type을 모두 선언할 수 없습니다.
- 즉 Generic Type을 활용해 유동적인 스키마를 만들 수 없습니다.
- 해결방법을 아직도 못찾는 중...
import Ajv, { JSONSchemaType } from "ajv";
const ajv = new Ajv();
interface userType<T> {
name: T;
age?: number;
}
const schema: JSONSchemaType<userType<string>> = {
type: "object",
properties: {
name: { type: "string" },
age: { type: "integer", nullable: true },
},
required: ["name"],
additionalProperties: false,
};
json-schema-to-ts 라이브러리
1. json-schema-to-ts 라이브러리란?
- Json Schema로 정의된 문서를 Type 형태로 변환해주는 라이브러리 입니다.
- 주간 다운로드 수는 약 30,000으로 많이 사용하지 않지만 2달전에 업데이트가 되었으며 꾸준하게 개선하고 있습니다.
- MIT 라이센스
- 특히 널리 사용되는 Ajv라이브러리와 같이 사용할 수 있도록 테스트를 완료하였고 타입스크립트의 대부분의 케이스를 지원합니다.
- 타입스크립티의 모든 최신 버전을 지원하는 것은 아닙니다.
- 참고
2. 사용해보기
- 설치
npm i json-schema-to-ts
- Object 활용
import { FromSchema } from "json-schema-to-ts";
const schema = {
type: "object",
properties: {
name: { type: "string" },
age: { type: "integer", nullable: true },
},
required: ["name"],
additionalProperties: false,
} as const;
type userType = FromSchema<typeof schema>;
// 생성된 Type
// type userType = {
// name: string;
// age?: number | undefined;
// }
- Enum 활용
- 비슷하게 type 형태로 구현
const enumSchema = {
enum: [true, 42, { foo: "bar" }],
} as const;
// => true | 42 | { foo: "bar"}
type Enum = FromSchema<typeof enumSchema>;
- 더 많은 활용을 보시려면 공식문서 참고
JSON Schema와 라이브러리의 활용성
- 장점
- Data Model를 정의할 때 타입스크립트보다 더 많은 표현이 가능합니다.
- 라이브러리를 통해 Validation을 손쉽게 활용할 수 있습니다.
- 단점
- JSON Schema 특성상 유동적인 데이터 타입을 지원하지 않기 때문에 라이브러리들이 Generic를 활용하지 않고 있습니다.
- 여러 타입을 지원해야 할 경우 JSON Schema는
type: ["string", "number"]
/ TS는 Union을 통해 타입을 제한시켜야 합니다.
- 여러 타입을 지원해야 할 경우 JSON Schema는
- 만약 JSON Schema를 활용하여 Data Model를 정의한다면 타입이 명확한 Model만 사용해야 합니다.
- Type을 활용한 Data Model 정의 방식보다는 러닝커브가 훨씬 크고 복잡하며 여러 라이브러리의 도움을 받아야 합니다.
- 타입스크립트의 Interface 활용도가 떨어집니다.
- 직접 Interface를 생성해서 활용할 수는 있지만 JSON Schema를 Interface로 변화할 수 없습니다.
- JSON Schema 특성상 유동적인 데이터 타입을 지원하지 않기 때문에 라이브러리들이 Generic를 활용하지 않고 있습니다.
Author And Source
이 문제에 관하여(JSON Schema의 활용), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@woodong/JSON-Schema의-활용저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)