- Serializing JSON Manually in Flutter
- Contents
- Core Guidelines
- Workflow: Implementing a Serializable Model
- Workflow: Fetching and Parsing JSON
- Examples
- Core Guidelines
- Import
- dart:convert
-
- Utilize Flutter's built-in
- dart:convert
- library for manual JSON encoding (
- jsonEncode
- ) and decoding (
- jsonDecode
- ).
- Enforce Type Safety
-
- Always cast the
- dynamic
- result of
- jsonDecode()
- to the expected type, typically
- Map
- for objects or
- List
- for arrays.
- Encapsulate Serialization Logic
-
- Define plain model classes containing properties corresponding to the JSON structure. Implement a
- fromJson
- factory constructor and a
- toJson
- method within the model.
- Handle Background Parsing
-
- If parsing large JSON documents (execution time > 16ms), offload the parsing logic to a separate isolate using Flutter's
- compute()
- function to prevent UI jank.
- Throw Exceptions on Failure
-
- When handling HTTP responses, throw an exception if the status code is not successful (e.g., not 200 OK or 201 Created). Do not return
- null
- .
- Workflow: Implementing a Serializable Model
- Use this checklist to implement manual JSON serialization for a data model.
- Task Progress:
- Define the plain model class with
- final
- properties.
- Implement the
- factory Model.fromJson(Map
json) - constructor.
- Implement the
- Map
toJson() - method.
- Write unit tests for both serialization methods.
- Run validator -> review type mismatch errors -> fix casting logic.
- Define the Model
-
- Create a class with properties matching the JSON keys.
- Implement
- fromJson
-
- Extract values from the
- Map
- and cast them to the appropriate Dart types. Use pattern matching or explicit casting.
- Implement
- toJson
-
- Return a
- Map
- mapping the class properties back to their JSON string keys.
- Validate
-
- Execute unit tests to ensure type safety, autocompletion, and compile-time exception handling function correctly.
- Workflow: Fetching and Parsing JSON
- Use this conditional workflow when retrieving and parsing JSON from a network request.
- Task Progress:
- Execute the HTTP request.
- Validate the response status code.
- Determine parsing strategy (Synchronous vs. Isolate).
- Decode and map the JSON to the model.
- Execute Request
-
- Use the
- http
- package to perform the network call.
- Validate Response
- :
- If
- response.statusCode == 200
- (or 201 for POST), proceed to parsing.
- If the status code indicates failure, throw an
- Exception
- .
- Determine Parsing Strategy
- :
- If parsing a
- small payload
- (e.g., a single object), parse synchronously on the main thread.
- If parsing a
- large payload
- (e.g., an array of thousands of objects), use
- compute(parseFunction, response.body)
- to parse in a background isolate.
- Decode and Map
- Pass the decoded JSON to your model's
fromJson
constructor.
Examples
High-Fidelity Model Implementation
import
'dart:convert'
;
class
User
{
final
int id
;
final
String
name
;
final
String
email
;
const
User
(
{
required
this
.
id
,
required
this
.
name
,
required
this
.
email
,
}
)
;
// Factory constructor for deserialization
factory
User
.
fromJson
(
Map
<
String
,
dynamic
json ) { return switch ( json ) { { 'id' : int id , 'name' : String name , 'email' : String email , } =
User ( id : id , name : name , email : email , ) , _ =
throw const FormatException ( 'Failed to load User.' ) , } ; } // Method for serialization Map < String , dynamic
toJson ( ) { return { 'id' : id , 'name' : name , 'email' : email , } ; } } Synchronous Parsing (Small Payload) import 'dart:convert' ; import 'package:http/http.dart' as http ; Future < User
fetchUser ( http . Client client , int userId ) async { final response = await client . get ( Uri . parse ( 'https://api.example.com/users/ $ userId ' ) , headers : { 'Accept' : 'application/json' } , ) ; if ( response . statusCode == 200 ) { // Decode returns dynamic, cast to Map
final Map < String , dynamic jsonMap
jsonDecode ( response . body ) as Map < String , dynamic
; return User . fromJson ( jsonMap ) ; } else { throw Exception ( 'Failed to load user' ) ; } } Background Parsing (Large Payload) import 'dart:convert' ; import 'package:flutter/foundation.dart' ; import 'package:http/http.dart' as http ; // Top-level function required for compute() List < User
parseUsers ( String responseBody ) { final parsed = ( jsonDecode ( responseBody ) as List < dynamic
) . cast < Map < String , dynamic
( ) ; return parsed . map < User
( ( json ) =
User . fromJson ( json ) ) . toList ( ) ; } Future < List < User
fetchUsers ( http . Client client ) async { final response = await client . get ( Uri . parse ( 'https://api.example.com/users' ) , headers : { 'Accept' : 'application/json' } , ) ; if ( response . statusCode == 200 ) { // Offload expensive parsing to a background isolate return compute ( parseUsers , response . body ) ; } else { throw Exception ( 'Failed to load users' ) ; } }
flutter-implement-json-serialization
安装
npx skills add https://github.com/flutter/skills --skill flutter-implement-json-serialization