JSON (JavaScript Object Notation) has become the de facto standard for data exchange in web development. This lightweight data format is used everywhere, from APIs to configuration files. However, working with JSON requires an understanding of validation, formatting, and error handling. In this article, we’ll take a deep dive into JSON and cover every aspect of working with this format.
What JSON is and why it matters
JSON is a text-based format for representing structured data. It was created by Douglas Crockford in the early 2000s as an alternative to XML. Its simple syntax, readability, and broad range of applications have made JSON an indispensable tool in modern web development.
The main advantages of JSON include human readability, ease of parsing, and broad support across modern programming languages. Unlike XML, JSON has minimal syntax and does not require complex validation schemas for basic use cases.
JSON data structure
JSON supports six data types: strings, numbers, booleans, null, arrays, and objects. Understanding these types is critical to working with data correctly.
Strings in JSON
Strings in JSON must be enclosed in double quotes. This is one of the key differences from JavaScript, where single quotes can be used. Special characters must be escaped with a backslash.
{
"name": "Иван Петров",
"email": "ivan@example.com",
"description": "Строка с \"кавычками\" и \n переносами строк"
}Numbers in JSON
JSON supports integers, floating-point numbers, and exponential notation. Remember that JSON does not support special numeric values such as Infinity or NaN.
{
"integer": 42,
"float": 3.14159,
"exponential": 1.23e-4,
"negative": -100
}Booleans and null
JSON supports only two boolean values: true and false. The null value represents the absence of data and differs from undefined in JavaScript.
{
"isActive": true,
"isDeleted": false,
"middleName": null
}Arrays and objects
Arrays in JSON are ordered lists of values, while objects are unordered collections of key-value pairs. These structures can be nested without limitation.
{
"users": [
{
"id": 1,
"name": "Анна",
"roles": ["admin", "editor"]
},
{
"id": 2,
"name": "Борис",
"roles": ["user"]
}
],
"metadata": {
"total": 2,
"page": 1,
"perPage": 10
}
}Validating JSON data
JSON validation is the process of checking whether data conforms to specified rules and constraints. It is a critical step in developing reliable applications.
Syntax validation
The first step is always to check the JSON syntax. Invalid syntax can cause parsing errors and application failures.
function validateJSONSyntax(jsonString) {
try {
JSON.parse(jsonString);
return { isValid: true, error: null };
} catch (error) {
return { isValid: false, error: error.message };
}
}
// Пример использования
const testJSON = '{"name": "test", "value": 42}';
const result = validateJSONSyntax(testJSON);
console.log(result); // { isValid: true, error: null }Semantic validation
After checking the syntax, you need to ensure that the data matches the expected structure and business rules.
function validateUserData(data) {
const errors = [];
// Проверка обязательных полей
if (!data.name || typeof data.name !== 'string') {
errors.push('Поле name обязательно и должно быть строкой');
}
if (!data.email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) {
errors.push('Поле email обязательно и должно быть валидным email');
}
// Проверка типов данных
if (data.age && (typeof data.age !== 'number' || data.age < 0)) {
errors.push('Возраст должен быть положительным числом');
}
// Проверка значений
if (data.roles && (!Array.isArray(data.roles) || data.roles.length === 0)) {
errors.push('Роли должны быть непустым массивом');
}
return {
isValid: errors.length === 0,
errors: errors
};
}Validation using schemas
For complex data structures, JSON Schema is recommended. It is a standard for describing and validating JSON documents.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"email": {
"type": "string",
"format": "email"
},
"age": {
"type": "integer",
"minimum": 0,
"maximum": 150
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["admin", "editor", "user"]
},
"minItems": 1
}
},
"required": ["name", "email"]
}Formatting JSON
Properly formatting JSON improves readability and makes debugging easier. There are several approaches to formatting, depending on the context.
Pretty formatting for development
During development, readable code is important. Proper indentation and structure help you find the data you need quickly.
function formatJSON(data, indent = 2) {
return JSON.stringify(data, null, indent);
}
const userData = {
id: 1,
name: "Мария Иванова",
email: "maria@example.com",
profile: {
age: 28,
city: "Москва",
interests: ["программирование", "путешествия", "чтение"]
},
settings: {
notifications: true,
theme: "dark",
language: "ru"
}
};
console.log(formatJSON(userData));Minification for production
In production, it is important to minimize the size of data to speed up transmission over the network.
function minifyJSON(data) {
return JSON.stringify(data);
}
const minified = minifyJSON(userData);
console.log(minified.length); // Меньший размерConditional formatting
Sometimes different formatting is needed depending on the context.
function formatJSONConditional(data, options = {}) {
const {
pretty = false,
indent = 2,
sortKeys = false,
replacer = null
} = options;
if (sortKeys) {
const sortedData = sortObjectKeys(data);
return JSON.stringify(sortedData, replacer, pretty ? indent : 0);
}
return JSON.stringify(data, replacer, pretty ? indent : 0);
}
function sortObjectKeys(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
if (Array.isArray(obj)) {
return obj.map(sortObjectKeys);
}
const sorted = {};
Object.keys(obj).sort().forEach(key => {
sorted[key] = sortObjectKeys(obj[key]);
});
return sorted;
}Handling JSON errors
Working with JSON inevitably involves errors. Handling these errors correctly is critical to application stability.
Common parsing errors
The most common errors include incorrect quotation marks, trailing commas, and unescaped characters.
function safeJSONParse(jsonString, defaultValue = null) {
try {
return JSON.parse(jsonString);
} catch (error) {
console.error('Ошибка парсинга JSON:', error.message);
// Попытка исправить распространенные ошибки
const fixed = fixCommonJSONErrors(jsonString);
if (fixed !== jsonString) {
try {
return JSON.parse(fixed);
} catch (secondError) {
console.error('Не удалось исправить JSON:', secondError.message);
}
}
return defaultValue;
}
}
function fixCommonJSONErrors(jsonString) {
let fixed = jsonString;
// Замена одинарных кавычек на двойные
fixed = fixed.replace(/'/g, '"');
// Удаление лишних запятых
fixed = fixed.replace(/,(\s*[}\]])/g, '$1');
// Исправление незакрытых строк
fixed = fixed.replace(/"([^"]*)$/g, '$1"');
return fixed;
}Validation with detailed error messages
Detailed error information is important for debugging.
function validateJSONWithDetails(jsonString) {
const result = {
isValid: false,
errors: [],
warnings: [],
data: null
};
try {
result.data = JSON.parse(jsonString);
result.isValid = true;
} catch (error) {
result.errors.push({
type: 'syntax',
message: error.message,
position: extractErrorPosition(error.message)
});
}
// Дополнительные проверки
if (result.isValid) {
const validationResult = validateDataStructure(result.data);
result.errors.push(...validationResult.errors);
result.warnings.push(...validationResult.warnings);
}
return result;
}
function extractErrorPosition(errorMessage) {
const match = errorMessage.match(/position (\d+)/);
return match ? parseInt(match[1]) : null;
}Working with large JSON files
When working with large volumes of data, it is important to use efficient processing methods.
Stream processing
For very large files, stream processing is recommended.
const fs = require('fs');
const { Transform } = require('stream');
class JSONParser extends Transform {
constructor() {
super({ objectMode: true });
this.buffer = '';
}
_transform(chunk, encoding, callback) {
this.buffer += chunk.toString();
// Обработка полных JSON объектов
const lines = this.buffer.split('\n');
this.buffer = lines.pop(); // Оставляем неполную строку в буфере
for (const line of lines) {
if (line.trim()) {
try {
const parsed = JSON.parse(line);
this.push(parsed);
} catch (error) {
this.emit('error', error);
}
}
}
callback();
}
_flush(callback) {
if (this.buffer.trim()) {
try {
const parsed = JSON.parse(this.buffer);
this.push(parsed);
} catch (error) {
this.emit('error', error);
}
}
callback();
}
}Caching and optimization
For frequently used data, it is important to implement caching.
class JSONCache {
constructor(maxSize = 100) {
this.cache = new Map();
this.maxSize = maxSize;
}
get(key) {
if (this.cache.has(key)) {
const item = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, item); // Обновляем порядок
return item;
}
return null;
}
set(key, value) {
if (this.cache.size >= this.maxSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, value);
}
clear() {
this.cache.clear();
}
}Integrating with web APIs
JSON is widely used in web APIs. Handling JSON correctly in APIs is critical to performance and security.
Validating incoming data
All incoming data must undergo strict validation.
function validateAPIRequest(req, res, next) {
const contentType = req.headers['content-type'];
if (!contentType || !contentType.includes('application/json')) {
return res.status(400).json({
error: 'Content-Type должен быть application/json'
});
}
try {
const data = JSON.parse(req.body);
req.validatedData = data;
next();
} catch (error) {
return res.status(400).json({
error: 'Невалидный JSON',
details: error.message
});
}
}Formatting responses
API responses should be consistent and well-structured.
function formatAPIResponse(data, options = {}) {
const {
pretty = false,
includeMetadata = true,
timestamp = new Date().toISOString()
} = options;
const response = {
success: true,
data: data,
timestamp: timestamp
};
if (includeMetadata) {
response.metadata = {
version: '1.0',
format: 'json'
};
}
return JSON.stringify(response, null, pretty ? 2 : 0);
}Conclusion
Working with JSON requires a deep understanding of validation, formatting, and error handling. The right approach to working with JSON data significantly improves the quality and reliability of web applications.
Use specialized tools to validate and format JSON, especially when working with large volumes of data or in mission-critical systems. Regular testing and monitoring can help prevent problems in production.
🔗 Try our JSON Formatter: rechecker.ru/services/json-formatter