ToolHub
View All Posts

Hướng Dẫn Xác Thực JSON Schema: Xác Minh Cấu Trúc Dữ Liệu

Mọi ứng dụng nhận dữ liệu từ nguồn bên ngoài đều đối mặt với cùng một vấn đề cơ bản: tôi có thể tin tưởng dữ liệu này không? Cho dù là API request body, file cấu hình, queue message hay import dữ liệu, dữ liệu không đáng tin cậy phải được xác thực trước khi vào hệ thống. JSON Schema cung cấp cách chuẩn hóa, độc lập ngôn ngữ để định nghĩa dữ liệu hợp lệ trông như thế nào và xác thực dữ liệu đầu vào có tuân thủ định nghĩa đó không. Hướng dẫn này bao gồm mọi thứ từ viết Schema đầu tiên đến các mẫu nâng cao cho xác thực phức tạp, với ví dụ thực tế bạn có thể áp dụng ngay.

JSON Schema Là Gì?

JSON Schema là một tài liệu JSON mô tả cấu trúc và ràng buộc của các tài liệu JSON khác. Nó là từ vựng cho phép bạn chú thích và xác thực dữ liệu JSON, được chuẩn hóa bởi IETF. JSON Schema định nghĩa các quy tắc về những trường nào phải tồn tại, chúng phải thuộc kiểu gì, giá trị nào được chấp nhận và đối tượng và mảng nên được cấu trúc như thế nào.

Hãy nghĩ về JSON Schema như hợp đồng dữ liệu của bạn. Giống như database schema định nghĩa cột, kiểu và ràng buộc của bảng, JSON Schema định nghĩa thuộc tính, kiểu và ràng buộc của tài liệu JSON. Bất kỳ dữ liệu JSON nào thỏa mãn tất cả ràng buộc trong Schema được gọi là instance hợp lệ, trong khi dữ liệu vi phạm bất kỳ ràng buộc nào là không hợp lệ.

JSON Schema Không Phải Là Gì

Phiên Bản JSON Schema

JSON Schema đã phát triển qua nhiều bản draft, mỗi bản thêm tính năng và hoàn thiện từ vựng. Hiểu các phiên bản này giúp bạn chọn phiên bản phù hợp cho dự án và tránh vấn đề tương thích.

Phiên Bản$schema URITrạng TháiTính Năng Chính
Draft 2020-12https://json-schema.org/draft/2020-12/schemaHiện tạiprefixItems, dynamicRef, hỗ trợ từ vựng
Draft 2019-09https://json-schema.org/draft/2019-09/schemaỔn địnhunevaluatedProperties, $recursiveRef
Draft 7http://json-schema.org/draft-07/schema#Hỗ trợ rộng rãiif/then/else, contentEncoding
Draft 6http://json-schema.org/draft-06/schema#propertyNames, contains
Draft 4http://json-schema.org/draft-04/schema#Đã lỗi thờiPhiên bản được áp dụng rộng rãi đầu tiên
Mẹo chuyên nghiệp: Luôn bao gồm $schema trong Schema của bạn để khai báo phiên bản draft. Điều này ngăn trình xác thực đoán và đảm bảo Schema của bạn được diễn giải nhất quán trên các công cụ và ngôn ngữ lập trình khác nhau.

Viết Schema Đầu Tiên

Hãy bắt đầu với một ví dụ đơn giản: Schema cho đối tượng người dùng chứa tên, email và tuổi.

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "https://example.com/schemas/user.json",
    "title": "User",
    "description": "A user account in the system",
    "type": "object",
    "properties": {
        "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "The user's full name"
        },
        "email": {
            "type": "string",
            "format": "email",
            "description": "The user's email address"
        },
        "age": {
            "type": "integer",
            "minimum": 0,
            "maximum": 150,
            "description": "The user's age in years"
        }
    },
    "required": ["name", "email"],
    "additionalProperties": false
}

Schema này khai báo rằng một người dùng hợp lệ phải là một đối tượng với name và email là thuộc tính chuỗi bắt buộc. Thuộc tính age là tùy chọn, nhưng nếu tồn tại phải là số nguyên từ 0 đến 150. additionalProperties: false ngăn chặn bất kỳ thuộc tính nào không được định nghĩa trong Schema, giúp phát hiện lỗi chính tả và trường không mong đợi.

Tham Khảo Từ Khóa Cốt Lõi

JSON Schema cung cấp từ vựng phong phú các từ khóa để định nghĩa ràng buộc. Dưới đây là các từ khóa quan trọng nhất được tổ chức theo danh mục.

Từ Khóa Kiểu

Từ KhóaMô TảVí Dụ
typeKiểu dữ liệu mong đợi"type": "string" hoặc "type": ["string", "null"]
enumDanh sách giá trị được phép"enum": ["active", "inactive", "pending"]
constPhải bằng chính xác giá trị này"const": "v2"

Ràng Buộc Số

Định DạngMô Tả Example
minimumGiá trị tối thiểu (bao gồm)"minimum": 0
exclusiveMinimumGiá trị tối thiểu (không bao gồm)"exclusiveMinimum": 0
maximumGiá trị tối đa (bao gồm)"maximum": 100
exclusiveMaximumGiá trị tối đa (không bao gồm)"exclusiveMaximum": 100
multipleOfPhải là bội số của giá trị này"multipleOf": 0.01

Ràng Buộc Chuỗi

Keyword Description Example
minLengthĐộ dài chuỗi tối thiểu"minLength": 1
maxLengthĐộ dài chuỗi tối đa"maxLength": 255
patternRegex mà chuỗi phải khớp"pattern": "^[A-Z]{2}\\d{4}$"
formatĐịnh dạng ngữ nghĩa (email, uri, date-time, v.v.)"format": "email"

Ràng Buộc Đối Tượng

Keyword Description Example
propertiesSchema cho mỗi thuộc tính đã biết"properties": {"name": {"type": "string"}}
requiredDanh sách thuộc tính bắt buộc"required": ["name", "email"]
additionalPropertiesCó cho phép thuộc tính bổ sung không"additionalProperties": false
minPropertiesSố lượng thuộc tính tối thiểu"minProperties": 1
maxPropertiesSố lượng thuộc tính tối đa"maxProperties": 10
patternPropertiesSchema cho thuộc tính khớp regex"patternProperties": {"^S_": {"type": "string"}}

Ràng Buộc Mảng

Keyword Description Example
itemsSchema cho tất cả mục mảng"items": {"type": "string"}
prefixItemsSchema cho mục theo vị trí (Draft 2020-12)"prefixItems": [{"type": "string"}, {"type": "number"}]
minItemsSố lượng mục tối thiểu"minItems": 1
maxItemsSố lượng mục tối đa"maxItems": 100
uniqueItemsTất cả mục phải duy nhất"uniqueItems": true

Mẫu Schema Phổ Biến

Schema trong thế giới thực thường yêu cầu các mẫu vượt ra ngoài kiểm tra kiểu đơn giản. Dưới đây là các mẫu được sử dụng phổ biến nhất.

Xác Thực Điều Kiện Với if/then/else

Sử dụng logic điều kiện để áp dụng các ràng buộc khác nhau dựa trên giá trị thuộc tính. Ví dụ, đối tượng thanh toán yêu cầu các trường khác nhau tùy theo phương thức thanh toán.

{
    "type": "object",
    "properties": {
        "method": { "enum": ["credit_card", "bank_transfer"] },
        "card_number": { "type": "string" },
        "routing_number": { "type": "string" }
    },
    "required": ["method"],
    "if": {
        "properties": { "method": { "const": "credit_card" } }
    },
    "then": {
        "required": ["card_number"]
    },
    "else": {
        "required": ["routing_number"]
    }
}

Kết Hợp Với allOf, anyOf, oneOf

Từ khóa kết hợp cho phép bạn kết hợp Schema theo cách mạnh mẽ:

{
    "oneOf": [
        {
            "type": "object",
            "properties": {
                "type": { "const": "email" },
                "address": { "type": "string", "format": "email" }
            },
            "required": ["type", "address"]
        },
        {
            "type": "object",
            "properties": {
                "type": { "const": "phone" },
                "number": { "type": "string", "pattern": "^\\+?[1-9]\\d{1,14}$" }
            },
            "required": ["type", "number"]
        }
    ]
}

Tái Sử Dụng Schema Với $ref

Từ khóa $ref cho phép bạn tham chiếu và tái sử dụng Schema, loại bỏ trùng lặp và giữ Schema có thể bảo trì. Bạn có thể tham chiếu Schema trong cùng tài liệu hoặc trong file bên ngoài.

{
    "$id": "https://example.com/schemas/order.json",
    "type": "object",
    "properties": {
        "customer": { "$ref": "#/$defs/address" },
        "shipping": { "$ref": "#/$defs/address" },
        "billing": { "$ref": "#/$defs/address" },
        "items": {
            "type": "array",
            "items": { "$ref": "#/$defs/lineItem" },
            "minItems": 1
        }
    },
    "required": ["customer", "items"],
    "$defs": {
        "address": {
            "type": "object",
            "properties": {
                "street": { "type": "string" },
                "city": { "type": "string" },
                "zip": { "type": "string", "pattern": "^\\d{5}(-\\d{4})?$" },
                "country": { "type": "string", "minLength": 2, "maxLength": 2 }
            },
            "required": ["street", "city", "zip", "country"]
        },
        "lineItem": {
            "type": "object",
            "properties": {
                "product": { "type": "string" },
                "quantity": { "type": "integer", "minimum": 1 },
                "price": { "type": "number", "exclusiveMinimum": 0 }
            },
            "required": ["product", "quantity", "price"]
        }
    }
}

Kiểu Nullable

Trong JSON Schema Draft 2020-12, kiểu nullable được biểu diễn bằng mảng kiểu chứa "null":

{
    "type": ["string", "null"],
    "description": "An optional display name, or null if not set"
}

Trong các draft cũ hơn, đặc tả OpenAPI sử dụng từ khóa nullable: true. Đối với JSON Schema tiêu chuẩn, luôn sử dụng phương pháp mảng kiểu.

Xác Thực Định Dạng

Từ khóa format cung cấp xác thực ngữ nghĩa vượt ra ngoài kiểm tra cấu trúc. Nó chỉ định chuỗi phải tuân thủ một định dạng được công nhận. Các định dạng được hỗ trợ phổ biến bao gồm:

Format Description Example
emailĐịa chỉ emailuser@example.com
uriURI hợp lệhttps://example.com
date-timeNgày giờ ISO 86012024-01-15T14:30:00Z
ipv4Địa chỉ IPv4192.168.1.1
hostnameTên máy chủexample.com
time ISO 8601 time 14:30:00Z
ipv4 IPv4 address 192.168.1.1
ipv6 IPv6 address ::1
uuid Universally unique identifier 550e8400-e29b-41d4-a716-446655440000
hostname Internet hostname www.example.com
Important:format{ strict: true }{ validateFormats: true } to enforce format checking. Always verify that your validator enforces format constraints.

Xác Thực Dữ Liệu JSON Theo Chương Trình

Xác thực Schema hữu ích nhất khi được tích hợp vào code ứng dụng. Dưới đây là ví dụ sử dụng thư viện phổ biến trong các ngôn ngữ khác nhau.

JavaScript Với Ajv

Ajv là trình xác thực JSON Schema được sử dụng rộng rãi nhất trong JavaScript. Nó hỗ trợ tất cả phiên bản draft và cung cấp hiệu suất xuất sắc thông qua JIT compilation của Schema.

import Ajv from 'ajv';
import addFormats from 'ajv-formats';

const ajv = new Ajv();
addFormats(ajv);

const schema = {
    type: 'object',
    properties: {
        name: { type: 'string', minLength: 1 },
        email: { type: 'string', format: 'email' },
        age: { type: 'integer', minimum: 0 }
    },
    required: ['name', 'email'],
    additionalProperties: false
};

const validate = ajv.compile(schema);
const valid = validate({ name: 'Alice', email: 'alice@example.com', age: 30 });

if (!valid) {
    console.log(validate.errors);
    // [{ keyword: 'required', params: { missingProperty: 'email' }, ... }]
}

Python Với jsonschema

from jsonschema import validate, ValidationError

schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string", "minLength": 1},
        "email": {"type": "string", "format": "email"},
        "age": {"type": "integer", "minimum": 0}
    },
    "required": ["name", "email"],
    "additionalProperties": False
}

try:
    validate(instance={"name": "Alice", "email": "alice@example.com"}, schema=schema)
except ValidationError as e:
    print(f"Validation failed: {e.message}")

Xác Thực Dữ Liệu API Với JSON Schema

Một trong những ứng dụng giá trị nhất của JSON Schema là xác thực dữ liệu API request và response. Điều này đảm bảo API của bạn nhận đầu vào đúng định dạng và trả về dữ liệu theo định dạng mong đợi, phát hiện lỗi sớm và cung cấp thông báo lỗi rõ ràng cho client.

Express.js Middleware

import Ajv from 'ajv';

const ajv = new Ajv({ allErrors: true });

function validateBody(schema) {
    const validate = ajv.compile(schema);
    return (req, res, next) => {
        if (!validate(req.body)) {
            return res.status(400).json({
                error: 'Validation failed',
                details: validate.errors
            });
        }
        next();
    };
}

app.post('/api/users',
    validateBody({
        type: 'object',
        properties: {
            name: { type: 'string', minLength: 1, maxLength: 100 },
            email: { type: 'string', format: 'email' },
            role: { enum: ['admin', 'editor', 'viewer'] }
        },
        required: ['name', 'email'],
        additionalProperties: false
    }),
    (req, res) => {
        // req.body is guaranteed valid here
        createUser(req.body);
    }
);

OpenAPI và JSON Schema

OpenAPI (trước đây là Swagger) sử dụng tập con của JSON Schema để định nghĩa API request và response Schema. Nếu bạn đã sử dụng OpenAPI, bạn có thể trích xuất Schema từ đặc tả API và sử dụng chúng cho xác thực runtime. Các công cụ như openapi-schema-validator và express-openapi-validator có thể tự động hóa quá trình này, đảm bảo tài liệu API và logic xác thực của bạn luôn đồng bộ.

Thực Hành Tốt Nhất

Cần xác thực dữ liệu JSON theo Schema? Hãy dùng thử công cụ xác thực JSON Schema trực tuyến miễn phí của chúng tôi. Dán Schema và dữ liệu của bạn để nhận kết quả xác thực tức thì với thông báo lỗi chi tiết.

Dùng Thử Trình Xác Thực JSON SchemaJSON Formatter

Câu Hỏi Thường Gặp

JSON Schema là gì?

JSON Schema là tài liệu JSON mô tả cấu trúc và ràng buộc của các tài liệu JSON khác. Nó cho phép bạn định nghĩa trường bắt buộc, kiểu dữ liệu mong đợi, phạm vi giá trị, mẫu chuỗi và cấu trúc đối tượng lồng nhau. Bạn có thể sử dụng nó để xác thực dữ liệu đầu vào, tạo tài liệu và tự động tạo form interface.

Tôi nên sử dụng phiên bản JSON Schema nào?

Sử dụng JSON Schema Draft 2020-12 cho dự án mới. Đây là phiên bản ổn định mới nhất và được các thư viện xác thực chính như Ajv hỗ trợ. Nếu cần tương thích với công cụ cũ, Draft 7 cũng được hỗ trợ rộng rãi. Tránh Draft 4 và các phiên bản cũ hơn vì chúng sử dụng từ khóa lỗi thời và thiếu tính năng hiện đại.

JSON Schema khác TypeScript Interface như thế nào?

TypeScript interface chỉ cung cấp kiểm tra kiểu tại thời điểm biên dịch trong code TypeScript. JSON Schema cung cấp xác thực runtime trên nhiều ngôn ngữ lập trình, có thể xác thực dữ liệu từ bất kỳ nguồn nào (API request, file, database). Sử dụng TypeScript để có an toàn khi phát triển, sử dụng JSON Schema để xác thực dữ liệu runtime tại ranh giới hệ thống.

JSON Schema có thể xác thực API request body không?

Có, JSON Schema được sử dụng rộng rãi để xác thực API request và response. Các framework như Express (với express-json-validator), FastAPI và Spring Boot hỗ trợ nguyên bản hoặc qua middleware xác thực JSON Schema. Xác thực request body theo Schema đảm bảo dữ liệu đầu vào có cấu trúc đúng trước khi ứng dụng xử lý.

Từ khóa JSON Schema quan trọng nhất là gì?

Các từ khóa quan trọng nhất là: type (kiểu dữ liệu), properties (trường đối tượng), required (trường bắt buộc), items (Schema phần tử mảng), minimum/maximum (ranh giới số), minLength/maxLength (ranh giới chuỗi), pattern (regex chuỗi), enum (giá trị được phép) và $ref (tham chiếu để tái sử dụng Schema). Những từ khóa này bao phủ phần lớn nhu cầu xác thực.