Parsing JSON is a very common task for apps that need to fetch data from the Internet.
And depending on how much JSON data you need to process, you have two options:
write all the JSON parsing code manually
automate the process with code generation
Encoding and Decoding JSON
When a JSON response is sent over the network, the entire payload is encoded as a string.
But inside our Flutter apps, we don't want to extract the data from a string manually:
Instead, we can decode the JSON first to obtain a map of key-value pairs that can be more easily parsed. To send JSON data over the network, it first needs to be encoded or serialized. Encoding is the process of turning a data structure into a string. The opposite process is called decoding or deserialization. When you receive a JSON payload as a string, you need to decode or deserialize it before you can use it.
Decoding JSON with dart:convert
For simplicity, let's consider this small JSON payload:
// this represents some response data we get from the network, for example:
// ```
// final response = await http.get(uri);
// final jsonData = response.body
// ```
final jsonData = '{ "name": "Pizza da Mario", "cuisine": "Italian" }';
To read the keys and values inside it, we first need to decode it using the dart:convert package:
// 1. import dart:convert
import 'dart:convert';
// this represents some response data we get from the network
final jsonData = '{ "name": "Pizza da Mario", "cuisine": "Italian" }';
// 2. decode the json
final parsedJson = jsonDecode(jsonData);
// 3. print the type and value
print('${parsedJson.runtimeType} : $parsedJson');
the result type is the same as Map<String, dynamic>.
Note how the values are of type dynamic. This makes sense because each JSON value could be a primitive type (boolean/number/string), or a collection (list or map).
In fact, jsonDecode is a generic method that works on any valid JSON payload, regardless of what's inside it. All it does is decode it and return a dynamic value.
But if we work with dynamic values in Dart, we lose all the benefits of strong type-safety. A much better approach is to define some custom model classes that represent our response data.
Parsing JSON to a Dart model class
Given this simple map representing a JSON payload:
{
"name": "Pizza da Mario",
"cuisine": "Italian"
}
We can write a Restaurant class to represent it:
class Restaurant {
Restaurant({required this.name, required this.cuisine});
final String name;
final String cuisine;
}
As a result, rather than reading the data like this:
parsedJson['name']; // dynamic
parsedJson['cuisine']; // dynamic
We can read it like this:
restaurant.name; // guaranteed to be a non-nullable, immutable String
restaurant.cuisine; // guaranteed to be a non-nullable, immutable String
This way, we can leverage the type system to get compile-time safety and avoid typos and other mistakes.
However, we haven't specified how to convert our parsedJson to a Restaurant object yet!
JSON to Dart: Adding a factory constructor
Let's define a factory constructor to take care of this:
factory Restaurant.fromJson(Map<String, dynamic> data) {
// ! there's a problem with this code (see below)
final name = data['name'];
final cuisine = data['cuisine'];
return Restaurant(name: name, cuisine: cuisine);
}
A factory constructor is a good choice for JSON parsing as it lets us do some work (create variables, perform some validation) before returning the result. This is not possible with regular (generative) constructors.
Pages and Layouts in Nextjs- When building projects with Next.js, we typically create an entire user interface by assembling isolated components. However, some parts of the interface require the same code snippets across multiple routes — for example, the navigation header, footer, and sidebar. To manage this, we use layouts to structure the interface in a way that contains shared code snippets. Next.js recommends starting a new project with the App Router. However, we’ll discuss how to implement layouts and nested layouts with the Pages Router for users who have yet to migrate to the new Next.js routing system.
Introducing the useLoaderData Hook: The useLoaderData hook is a custom hook in React that helps you load data into your component. It simplifies the process of fetching data from an API or performing any asynchronous operation. When you use the useLoaderData hook, you provide it with a function that returns a Promise. This Promise represents an asynchronous operation that will fetch the data you need. Once the Promise resolves, the data becomes available to your component.