Try it yourself with our free Json Validator tool — runs entirely in your browser, no signup needed.

How to Validate JSON in Dart

How to validate JSON in Dart

Validating JSON data is a crucial step in ensuring the integrity and reliability of your application. JSON (JavaScript Object Notation) is a lightweight data interchange format that is widely used for exchanging data between web servers, web applications, and mobile apps. However, JSON data can be malformed, incomplete, or corrupted, which can lead to errors, crashes, or security vulnerabilities. In this article, we will explore how to validate JSON data in Dart, a modern, statically typed language developed by Google.

Quick Example

Here is a minimal example of how to validate JSON in Dart:

import 'dart:convert';

void main() {
  String jsonString = '{"name":"John","age":30}';
  try {
    Map<String, dynamic> jsonMap = jsonDecode(jsonString);
    print('JSON is valid: $jsonMap');
  } catch (e) {
    print('Invalid JSON: $e');
  }
}

This code uses the jsonDecode function from the dart:convert library to parse the JSON string into a Dart Map. If the JSON is valid, it prints the parsed map; otherwise, it catches the exception and prints an error message.

Step-by-Step Breakdown

Let's break down the code line by line:

  1. import 'dart:convert';: We import the dart:convert library, which provides functions for converting between Dart objects and JSON strings.
  2. String jsonString = '{"name":"John","age":30}';: We define a JSON string that we want to validate.
  3. try { ... } catch (e) { ... }: We use a try-catch block to catch any exceptions that may occur during JSON parsing.
  4. Map<String, dynamic> jsonMap = jsonDecode(jsonString);: We use the jsonDecode function to parse the JSON string into a Dart Map. The jsonDecode function returns a Map<String, dynamic>, where the keys are strings and the values are dynamic (i.e., can be any type).
  5. print('JSON is valid: $jsonMap');: If the JSON is valid, we print the parsed map.
  6. print('Invalid JSON: $e');: If an exception occurs during parsing, we catch the exception and print an error message.

Handling Edge Cases

Here are some common edge cases to consider when validating JSON in Dart:

Empty/Null Input

If the input JSON string is empty or null, the jsonDecode function will throw a FormatException.

void main() {
  String jsonString = '';
  try {
    jsonDecode(jsonString);
  } catch (e) {
    print('Error: $e'); // prints "Error: FormatException: Unexpected end of input"
  }
}

To handle this case, you can add a simple null check before calling jsonDecode.

void main() {
  String jsonString = '';
  if (jsonString != null && jsonString.isNotEmpty) {
    try {
      jsonDecode(jsonString);
    } catch (e) {
      print('Error: $e');
    }
  } else {
    print('Error: Input is empty or null');
  }
}

Invalid Input

If the input JSON string is malformed or invalid, the jsonDecode function will throw a FormatException.

void main() {
  String jsonString = '{"name":"John","age":30,}';
  try {
    jsonDecode(jsonString);
  } catch (e) {
    print('Error: $e'); // prints "Error: FormatException: Unexpected character ','"
  }
}

To handle this case, you can catch the FormatException and provide a more user-friendly error message.

void main() {
  String jsonString = '{"name":"John","age":30,}';
  try {
    jsonDecode(jsonString);
  } on FormatException catch (e) {
    print('Error: Invalid JSON input');
  }
}

Large Input

If the input JSON string is very large, parsing it may consume a lot of memory and CPU resources.

void main() {
  String jsonString = '{"name":"John","age":30,"data":${List.generate(1000000, (i) => i).join(',')}}';
  try {
    jsonDecode(jsonString);
  } catch (e) {
    print('Error: $e');
  }
}

To handle this case, you can use a streaming JSON parser like json_stream package, which can parse large JSON inputs without consuming too much memory.

import 'package:json_stream/json_stream.dart';

void main() {
  String jsonString = '{"name":"John","age":30,"data":${List.generate(1000000, (i) => i).join(',')}}';
  final parser = JsonParser();
  parser.listen((event) {
    print(event);
  });
}

Unicode/Special Characters

If the input JSON string contains Unicode or special characters, the jsonDecode function may throw a FormatException.

void main() {
  String jsonString = '{"name":"\u{1F600}","age":30}';
  try {
    jsonDecode(jsonString);
  } catch (e) {
    print('Error: $e'); // prints "Error: FormatException: Unexpected character '\u{1F600}'"
  }
}

To handle this case, you can use the jsonDecode function with the reviver parameter, which allows you to specify a custom reviver function to handle Unicode and special characters.

void main() {
  String jsonString = '{"name":"\u{1F600}","age":30}';
  try {
    jsonDecode(jsonString, reviver: (key, value) {
      if (value is String) {
        return value.replaceAll(RegExp(r'[^ -~]+'), '');
      }
      return value;
    });
  } catch (e) {
    print('Error: $e');
  }
}

Common Mistakes

Here are some common mistakes developers make when validating JSON in Dart:

Mistake 1: Not handling null or empty input

void main() {
  String jsonString = '';
  jsonDecode(jsonString); // throws FormatException
}

Corrected code:

void main() {
  String jsonString = '';
  if (jsonString != null && jsonString.isNotEmpty) {
    jsonDecode(jsonString);
  } else {
    print('Error: Input is empty or null');
  }
}

Mistake 2: Not handling invalid input

void main() {
  String jsonString = '{"name":"John","age":30,}';
  jsonDecode(jsonString); // throws FormatException
}

Corrected code:

void main() {
  String jsonString = '{"name":"John","age":30,}';
  try {
    jsonDecode(jsonString);
  } on FormatException catch (e) {
    print('Error: Invalid JSON input');
  }
}

Mistake 3: Not handling large input

void main() {
  String jsonString = '{"name":"John","age":30,"data":${List.generate(1000000, (i) => i).join(',')}}';
  jsonDecode(jsonString); // consumes too much memory
}

Corrected code:

import 'package:json_stream/json_stream.dart';

void main() {
  String jsonString = '{"name":"John","age":30,"data":${List.generate(1000000, (i) => i).join(',')}}';
  final parser = JsonParser();
  parser.listen((event) {
    print(event);
  });
}

Performance Tips

Here are some performance tips for validating JSON in Dart:

Tip 1: Use jsonDecode with reviver parameter

void main() {
  String jsonString = '{"name":"John","age":30}';
  jsonDecode(jsonString, reviver: (key, value) {
    // custom reviver function
  });
}

Tip 2: Use json_stream package for large inputs

import 'package:json_stream/json_stream.dart';

void main() {
  String jsonString = '{"name":"John","age":30,"data":${List.generate(1000000, (i) => i).join(',')}}';
  final parser = JsonParser();
  parser.listen((event) {
    print(event);
  });
}

Tip 3: Avoid using jsonDecode in loops

void main() {
  List<String> jsonStrings = [...];
  for (var jsonString in jsonStrings) {
    jsonDecode(jsonString); // inefficient
  }
}

Instead, use a single jsonDecode call with a list of JSON strings:

void main() {
  List<String> jsonStrings = [...];
  jsonDecode(jsonStrings.join('')); // more efficient
}

FAQ

Q: What is the difference between jsonDecode and jsonDecodeStrict?

A: jsonDecode is a more lenient parser that allows for some flexibility in the input JSON, while jsonDecodeStrict is a stricter parser that requires the input JSON to conform to the JSON specification.

Q: How do I handle Unicode characters in JSON input?

A: You can use the reviver parameter of jsonDecode to specify a custom reviver function that handles Unicode characters.

Q: What is the best way to parse large JSON inputs?

A: Use the json_stream package, which provides a streaming JSON parser that can handle large inputs without consuming too much memory.

Q: Can I use jsonDecode with other data formats, such as XML or CSV?

A: No, jsonDecode is specifically designed for parsing JSON data and is not compatible with other data formats.

Q: How do I handle errors and exceptions when using jsonDecode?

A: Use a try-catch block to catch any exceptions that may occur during parsing, and provide a user-friendly error message.

AI agent tools available. The CodeTidy MCP Server gives Claude, Cursor, and other AI agents access to 60+ developer tools. One command: npx @codetidy/mcp