QuickType을 사용하여 JSON 스키마에서 유형 생성
json-schema-to-typescript
라이브러리에 대한 대체 라이브러리를 살펴봄으로써 이 글을 계속할 것입니다.설정
# From a yarn initialised project
yarn add quicktype-core
# setting up the files
touch index.js book.json
book.json
에 대해 다음을 추가합니다. 이전에 Book에서 사용한 것과 유사한 JSON 스키마를 따르지만 몇 가지 변경 사항이 있으므로 복사하여 붙여넣습니다.{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"author": {
"type": "object",
"properties": {
"name": { "type": "string" },
"preferredName": { "type": "string" },
"age": { "type": "number" },
"gender": { "enum": ["male", "female", "other"] }
},
"required": ["name", "preferredName", "age", "gender"]
},
"title": { "type": "string" },
"publisher": { "type": "string" }
},
"required": ["author", "title", "publisher"]
}
스크립트 작성
index.js
는 다음과 같습니다.const {
quicktype,
InputData,
JSONSchemaInput,
JSONSchemaStore,
} = require("quicktype-core")
const path = require("path")
const fs = require("fs")
async function quicktypeJSONSchema(targetLanguage, typeName, jsonSchemaString) {
const schemaInput = new JSONSchemaInput(new JSONSchemaStore())
// We could add multiple schemas for multiple types,
// but here we're just making one type from JSON schema.
await schemaInput.addSource({ name: typeName, schema: jsonSchemaString })
const inputData = new InputData()
inputData.addInput(schemaInput)
return await quicktype({
inputData,
lang: targetLanguage,
})
}
async function main() {
// read the schema details
const schemaFilepath = path.join(__dirname, "bookWithoutUser.json")
const bookSchema = fs.readFileSync(schemaFilepath, "utf-8")
const { lines: tsPerson } = await quicktypeJSONSchema(
"typescript",
"Book",
bookSchema
)
console.log(tsPerson.join("\n"))
const { lines: pythonPerson } = await quicktypeJSONSchema(
"python",
"Book",
bookSchema
)
console.log(pythonPerson.join("\n"))
}
main()
위의 스크립트에서는 데모를 위해
TypeScript
및 Python
출력을 생성할 것입니다.발전기 실행
실행
node index.js
하면 TypeScript와 Python에 대해 각각 다음과 같은 출력을 얻을 수 있습니다.// To parse this data:
//
// import { Convert, Book } from "./file";
//
// const book = Convert.toBook(json);
//
// These functions will throw an error if the JSON doesn't
// match the expected interface, even if the JSON is valid.
export interface Book {
author: Author
publisher: string
title: string
}
export interface Author {
age: number
gender: Gender
name: string
preferredName: string
}
export enum Gender {
Female = "female",
Male = "male",
Other = "other",
}
// Converts JSON strings to/from your types
// and asserts the results of JSON.parse at runtime
export class Convert {
public static toBook(json: string): Book {
return cast(JSON.parse(json), r("Book"))
}
public static bookToJson(value: Book): string {
return JSON.stringify(uncast(value, r("Book")), null, 2)
}
}
function invalidValue(typ: any, val: any, key: any = ""): never {
if (key) {
throw Error(
`Invalid value for key "${key}". Expected type ${JSON.stringify(
typ
)} but got ${JSON.stringify(val)}`
)
}
throw Error(
`Invalid value ${JSON.stringify(val)} for type ${JSON.stringify(typ)}`
)
}
function jsonToJSProps(typ: any): any {
if (typ.jsonToJS === undefined) {
const map: any = {}
typ.props.forEach((p: any) => (map[p.json] = { key: p.js, typ: p.typ }))
typ.jsonToJS = map
}
return typ.jsonToJS
}
function jsToJSONProps(typ: any): any {
if (typ.jsToJSON === undefined) {
const map: any = {}
typ.props.forEach((p: any) => (map[p.js] = { key: p.json, typ: p.typ }))
typ.jsToJSON = map
}
return typ.jsToJSON
}
function transform(val: any, typ: any, getProps: any, key: any = ""): any {
function transformPrimitive(typ: string, val: any): any {
if (typeof typ === typeof val) return val
return invalidValue(typ, val, key)
}
function transformUnion(typs: any[], val: any): any {
// val must validate against one typ in typs
const l = typs.length
for (let i = 0; i < l; i++) {
const typ = typs[i]
try {
return transform(val, typ, getProps)
} catch (_) {}
}
return invalidValue(typs, val)
}
function transformEnum(cases: string[], val: any): any {
if (cases.indexOf(val) !== -1) return val
return invalidValue(cases, val)
}
function transformArray(typ: any, val: any): any {
// val must be an array with no invalid elements
if (!Array.isArray(val)) return invalidValue("array", val)
return val.map(el => transform(el, typ, getProps))
}
function transformDate(val: any): any {
if (val === null) {
return null
}
const d = new Date(val)
if (isNaN(d.valueOf())) {
return invalidValue("Date", val)
}
return d
}
function transformObject(
props: { [k: string]: any },
additional: any,
val: any
): any {
if (val === null || typeof val !== "object" || Array.isArray(val)) {
return invalidValue("object", val)
}
const result: any = {}
Object.getOwnPropertyNames(props).forEach(key => {
const prop = props[key]
const v = Object.prototype.hasOwnProperty.call(val, key)
? val[key]
: undefined
result[prop.key] = transform(v, prop.typ, getProps, prop.key)
})
Object.getOwnPropertyNames(val).forEach(key => {
if (!Object.prototype.hasOwnProperty.call(props, key)) {
result[key] = transform(val[key], additional, getProps, key)
}
})
return result
}
if (typ === "any") return val
if (typ === null) {
if (val === null) return val
return invalidValue(typ, val)
}
if (typ === false) return invalidValue(typ, val)
while (typeof typ === "object" && typ.ref !== undefined) {
typ = typeMap[typ.ref]
}
if (Array.isArray(typ)) return transformEnum(typ, val)
if (typeof typ === "object") {
return typ.hasOwnProperty("unionMembers")
? transformUnion(typ.unionMembers, val)
: typ.hasOwnProperty("arrayItems")
? transformArray(typ.arrayItems, val)
: typ.hasOwnProperty("props")
? transformObject(getProps(typ), typ.additional, val)
: invalidValue(typ, val)
}
// Numbers can be parsed by Date but shouldn't be.
if (typ === Date && typeof val !== "number") return transformDate(val)
return transformPrimitive(typ, val)
}
function cast<T>(val: any, typ: any): T {
return transform(val, typ, jsonToJSProps)
}
function uncast<T>(val: T, typ: any): any {
return transform(val, typ, jsToJSONProps)
}
function a(typ: any) {
return { arrayItems: typ }
}
function u(...typs: any[]) {
return { unionMembers: typs }
}
function o(props: any[], additional: any) {
return { props, additional }
}
function m(additional: any) {
return { props: [], additional }
}
function r(name: string) {
return { ref: name }
}
const typeMap: any = {
Book: o(
[
{ json: "author", js: "author", typ: r("Author") },
{ json: "publisher", js: "publisher", typ: "" },
{ json: "title", js: "title", typ: "" },
],
"any"
),
Author: o(
[
{ json: "age", js: "age", typ: 3.14 },
{ json: "gender", js: "gender", typ: r("Gender") },
{ json: "name", js: "name", typ: "" },
{ json: "preferredName", js: "preferredName", typ: "" },
],
"any"
),
Gender: ["female", "male", "other"],
}
파이썬 출력:
# To use this code, make sure you
#
# import json
#
# and then, to convert JSON from a string, do
#
# result = book_from_dict(json.loads(json_string))
from enum import Enum
from typing import Any, TypeVar, Type, cast
T = TypeVar("T")
EnumT = TypeVar("EnumT", bound=Enum)
def from_float(x: Any) -> float:
assert isinstance(x, (float, int)) and not isinstance(x, bool)
return float(x)
def from_str(x: Any) -> str:
assert isinstance(x, str)
return x
def to_float(x: Any) -> float:
assert isinstance(x, float)
return x
def to_enum(c: Type[EnumT], x: Any) -> EnumT:
assert isinstance(x, c)
return x.value
def to_class(c: Type[T], x: Any) -> dict:
assert isinstance(x, c)
return cast(Any, x).to_dict()
class Gender(Enum):
FEMALE = "female"
MALE = "male"
OTHER = "other"
class Author:
age: float
gender: Gender
name: str
preferred_name: str
def __init__(self, age: float, gender: Gender, name: str, preferred_name: str) -> None:
self.age = age
self.gender = gender
self.name = name
self.preferred_name = preferred_name
@staticmethod
def from_dict(obj: Any) -> 'Author':
assert isinstance(obj, dict)
age = from_float(obj.get("age"))
gender = Gender(obj.get("gender"))
name = from_str(obj.get("name"))
preferred_name = from_str(obj.get("preferredName"))
return Author(age, gender, name, preferred_name)
def to_dict(self) -> dict:
result: dict = {}
result["age"] = to_float(self.age)
result["gender"] = to_enum(Gender, self.gender)
result["name"] = from_str(self.name)
result["preferredName"] = from_str(self.preferred_name)
return result
class Book:
author: Author
publisher: str
title: str
def __init__(self, author: Author, publisher: str, title: str) -> None:
self.author = author
self.publisher = publisher
self.title = title
@staticmethod
def from_dict(obj: Any) -> 'Book':
assert isinstance(obj, dict)
author = Author.from_dict(obj.get("author"))
publisher = from_str(obj.get("publisher"))
title = from_str(obj.get("title"))
return Book(author, publisher, title)
def to_dict(self) -> dict:
result: dict = {}
result["author"] = to_class(Author, self.author)
result["publisher"] = from_str(self.publisher)
result["title"] = from_str(self.title)
return result
def book_from_dict(s: Any) -> Book:
return Book.from_dict(s)
def book_to_dict(x: Book) -> Any:
return to_class(Book, x)
만세! 우리는 이러한 도우미로 많은 보풀을 줄일 수 있습니다.
리소스 및 추가 읽을거리
이미지 크레디트: Alessio Rinella
원래 내blog에 게시되었습니다. 더 많은 숨겨진 보석을 보려면 Twitter에서 저를 팔로우하십시오.
Reference
이 문제에 관하여(QuickType을 사용하여 JSON 스키마에서 유형 생성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/okeeffed/generating-types-from-json-schema-with-quicktype-1fh2텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)