Sử dụng .NET để xác thực JSON bằng lược đồ JSON

JSON được cho là một trong những định dạng dữ liệu được sử dụng nhiều nhất trên hành tinh, có thể là do tính linh hoạt và khả năng đọc của con người. Chúng ta cũng có thể nhận ra rằng hai điểm mạnh lớn nhất của nó cũng có thể là điểm yếu của định dạng này.

Con người có thể đọc được mang lại cho các nhà phát triển sự tự tin để thực hiện các thay đổi thủ công, có khả năng mắc lỗi trong quá trình thực hiện. Tính linh hoạt của trình phân tích cú pháp có xu hướng để cho những lỗi cấu trúc này tồn tại trong cài đặt production lâu hơn chúng nên làm.

May mắn cho các nhà phát triển .NET, chúng ta có các cơ chế để kiểm tra tính hợp lệ của JSON để đảm bảo một số mức độ chính xác. Chúng ta sẽ xem cách đọc JSON và kiểm tra nó với định nghĩa lược đồ của nó.

Lược đồ JSON là gì?

Lược đồ JSON (Json Schema) cố gắng giúp xác định rõ ràng cho các đối tượng JSON. Lược đồ mô tả định dạng của JSON ở định dạng rõ ràng mà con người có thể đọc được và máy móc có thể đọc được.

Người dùng Lược đồ JSON có thể sử dụng nó để thực hiện xác thực cấu trúc, xác thực các yêu cầu của máy khách và tự động hóa các bài kiểm tra tích hợp bằng cách tạo đầu vào kiểm tra.

Hầu hết các trình soạn thảo hiện đại đều hỗ trợ lược đồ JSON bằng cách đặt một thuộc tính $schema ở đầu mô hình JSON. Hãy xem một ví dụ về lược đồ JSON.

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "Product",
  "description": "A product from Acme's catalog",
  "type": "object",
  "properties": {
    "id": {
      "description": "The unique identifier for a product",
      "type": "integer"
    },
    "name": {
      "description": "Name of the product",
      "type": "string"
    },
    "price": {
      "type": "number",
      "minimum": 0,
      "exclusiveMinimum": true
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "minItems": 1,
      "uniqueItems": true
    }
  },
  "required": ["id", "name", "price"]
}

Một số tính năng đáng chú ý của JSON Schema bao gồm:

  • Mô tả của từng thuộc tính trong một đối tượng JSON.
  • Kiểu dữ liệu cho từng thuộc tính.
  • Giá trị cho từng thuộc tính.
  • Các trường bắt buộc.
  • Lược đồ JSON cũng có thể được xác thực bằng Lược đồ JSON.

Chúng ta sẽ sử dụng lược đồ này trong ứng dụng .NET mẫu của chúng ta.

Xác thực JSON bằng .NET và NJsonSchema

Trước khi bắt đầu, chúng ta sẽ cần một ứng dụng console có cài đặt gói NuGet của NJsonSchema. Trong số các gói có sẵn để xác thực lược đồ JSON, tôi thấy đây là gói dễ sử dụng nhất.

dotnet add NJsonSchema

Mục tiêu của chúng ta là đọc thuộc tính $schema từ tệp JSON hiện có và sau đó xuất kết quả xác thực ra màn hình console. Chúng ta cũng sẽ sử dụng Spectre.Console để có đầu ra hiển thị đẹp, nhưng Console.WriteLine đơn giản cũng sẽ hoạt động tốt.

Ví dụ của chúng ta sẽ có ba tài liệu JSON khác nhau: valid.json, empty.jsonschemaless.json. Các biến thể của các đối tượng JSON sẽ giúp chúng ta thấy các kết quả khác nhau. Chúng ta đang đọc tệp schema.json từ đĩa, nhưng chúng ta có thể nhanh chóng đọc nó từ một URL từ xa, điều này thường xảy ra.

// empty.json
{
  "$schema": "schema.json"
}
// schemaless.json
{
  "wild": "west"
}
// valid.json
{
  "$schema": "schema.json",
  "id": 1,
  "name": "",
  "price": 149.00
}

Bây giờ chúng ta có tất cả ba tệp JSON và lược đồ của chúng ta, chúng ta có thể viết một số mã.

using System.IO;
using System.Linq;
using Newtonsoft.Json.Linq;
using NJsonSchema;
using Spectre.Console;

var files = new[] { "valid.json", "empty.json", "schemaless.json"};

var table = new Table().RoundedBorder()
    .AddColumn("📁 file name")
    .AddColumn("🚨 errors");

foreach (var file in files)
{
    var text = await File.ReadAllTextAsync(file);
    var json = JToken.Parse(text);
    
    // use the schema on the json model
    var jsonSchema = json["$schema"]?.ToString();
    var schema = jsonSchema switch {
        {Length: > 0} when jsonSchema.StartsWith("http") => 
            await JsonSchema.FromUrlAsync(jsonSchema),
        {Length: > 0} =>
            await JsonSchema.FromFileAsync(jsonSchema),
        _ => null
    };

    if (schema is null)
    {
        table.AddRow(file, "[purple]unavailable $schema[/]");
        continue;
    }
    
    var errors = schema.Validate(json);
    var results = errors.Any()
        ? $"‣ {errors.Count} total errors\n" +
          string.Join("", errors
              .Select(e => $"  ‣ [red]{e}[/] at " +
                           $"[yellow]{e.LineNumber}:{e.LinePosition}[/]\n"))
        : "[green]✔[/] [lime]looks good![/]";

    table.AddRow(file, results);
}

AnsiConsole.Render(table);

Như có thể thấy, chúng ta phân tích cú pháp các tệp JSON của mình và tải lược đồ khi chúng tôi xem qua từng tệp. Việc tải lược đồ cho mỗi tệp cung cấp cho chúng ta sự linh hoạt tối ưu để xác thực từng tệp một cách độc lập. Trong các tình huống mà tất cả các mô hình JSON đều giống nhau, tôi khuyên bạn nên tải lược đồ JSON một lần duy nhất.

Chạy ứng dụng console, chúng ta nhận được kết quả mong đợi. (Kết quả trông đẹp hơn nhiều ở trên máy local).

╭─────────────────┬──────────────────────────────────────╮
│ 📁 file name    │ 🚨 errors                            │
├─────────────────┼──────────────────────────────────────┤
│ valid.json      │ ✔ looks good!                        │
│ empty.json      │ ‣ 3 total errors                     │
│                 │   ‣ PropertyRequired: #/id at 1:1    │
│                 │   ‣ PropertyRequired: #/name at 1:1  │
│                 │   ‣ PropertyRequired: #/price at 1:1 │
│                 │                                      │
│ schemaless.json │ unavailable $schema                  │
╰─────────────────┴──────────────────────────────────────╯

Thật tuyệt vời! Thật không thể tin được!

Phần kết luận

JSON ở khắp mọi nơi và là một định dạng dữ liệu linh hoạt, khả năng xác thực Json là một điều tuyệt vời. Lược đồ JSON cho phép chúng ta thực thi một cấu trúc mà chúng ta có thể sử dụng để cung cấp cho người dùng phản hồi.

Nhiều công cụ soạn thảo đã hỗ trợ thuộc tính $schema, mang lại cho chúng ta các vấn đề xác thực trong thời gian thực. Việc sử dụng thứ gì đó như NJsonSchema cho phép chúng ta sử dụng một lược đồ hiện có để thêm một lớp xác thực có thể giảm bớt các vấn đề trước khi chúng vượt ra khỏi tầm tay.

Nếu chúng ta không có lược đồ thì cũng không có vấn đề gì quá to tát vì định dạng lược đồ JSON dễ viết và dễ duy trì hơn.

Tôi hy vọng bạn thích bài viết này. Nếu bạn đã thích, hãy chia sẻ nó với bạn bè và đồng nghiệp của bạn.

Cảm ơn vì bạn đã đọc!

Nếu Comdy hữu ích và giúp bạn tiết kiệm thời gian làm việc

Bạn có thể vui lòng đưa Comdy vào whitelist của trình chặn quảng cáo ❤️ để hỗ trợ chúng tôi trong việc trả tiền cho dịch vụ lưu trữ web để duy trì hoạt động của trang web.

Lập Trình C#
Bài Viết Liên Quan:
Tạo tập tin Zip với .NET 5
Trung Nguyen 11/11/2021
Tạo tập tin Zip với .NET 5

Trong bài viết này, chúng ta sẽ tìm hiểu lớp tiện ích ZipFile trong C#, cách nén tập tin và thư mục, cùng với giải nén tập tin zip.

Đọc và ghi file Excel trong C#
Trung Nguyen 29/10/2021
Đọc và ghi file Excel trong C#

Bài viết này sẽ giới thiệu cách đơn giản nhất mà tôi đã tìm thấy để đọc và ghi file Excel bằng C# sử dụng ExcelMapper.

Làm việc với PriorityQueue của .NET 6
Trung Nguyen 25/10/2021
Làm việc với PriorityQueue của .NET 6

Bài viết này sẽ giúp bạn tìm hiểu PriorityQueue của .NET 6 là gì, cách chúng ta thêm các phần tử và cách chúng ta có thể xếp hàng lại cho các phần tử.

Hướng dẫn nhanh và ví dụ về pattern matching trong C#
Trung Nguyen 23/10/2021
Hướng dẫn nhanh và ví dụ về pattern matching trong C#

Bài viết này sẽ trình bày một số ví dụ về pattern matching hữu ích và bạn có thể xem xét sử dụng trong các dự án hiện tại hoặc tương lai của bạn.