{"id":31660401,"url":"https://github.com/thanhtunguet/flutter_json_entity","last_synced_at":"2026-05-19T07:32:34.807Z","repository":{"id":250520352,"uuid":"825096132","full_name":"thanhtunguet/flutter_json_entity","owner":"thanhtunguet","description":"A library for parsing JSON data into Dart objects, inspired by PHP Laravel ORM.","archived":false,"fork":false,"pushed_at":"2025-09-17T01:21:18.000Z","size":997,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-26T04:15:21.838Z","etag":null,"topics":["flutter","library","package"],"latest_commit_sha":null,"homepage":"https://thanhtunguet.info/posts/overcome-flutter-json-drawbacks/","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thanhtunguet.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-07-06T19:00:00.000Z","updated_at":"2025-09-29T07:06:32.000Z","dependencies_parsed_at":"2025-05-12T03:29:40.659Z","dependency_job_id":"7b99de55-a6df-4bb6-bf04-fd4411736f8b","html_url":"https://github.com/thanhtunguet/flutter_json_entity","commit_stats":null,"previous_names":["thanhtunguet/supa_architecture","supavn/supa_architecture","thanhtunguet/flutter_json_entity"],"tags_count":80,"template":false,"template_full_name":null,"purl":"pkg:github/thanhtunguet/flutter_json_entity","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanhtunguet%2Fflutter_json_entity","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanhtunguet%2Fflutter_json_entity/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanhtunguet%2Fflutter_json_entity/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanhtunguet%2Fflutter_json_entity/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thanhtunguet","download_url":"https://codeload.github.com/thanhtunguet/flutter_json_entity/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanhtunguet%2Fflutter_json_entity/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33206320,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-19T07:16:55.748Z","status":"ssl_error","status_checked_at":"2026-05-19T07:16:54.366Z","response_time":58,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flutter","library","package"],"created_at":"2025-10-07T17:06:37.132Z","updated_at":"2026-05-19T07:32:34.788Z","avatar_url":"https://github.com/thanhtunguet.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# json_entity\n\nA lightweight, Laravel-inspired JSON mapping library for Dart/Flutter that avoids code generation. Define rich models using field objects (`JsonString`, `JsonInteger`, `JsonDouble`, `JsonBoolean`, `JsonDate`, `JsonNumber`, `JsonObject`, `JsonList`) and serialize/deserialize without `.g.dart` files.\n\nThis approach is inspired by Laravel Eloquent's implicit attribute mapping and whitelisting/blacklisting philosophy. It keeps models explicit and composable, while eliminating build-step overhead and IDE slowdowns.\n\n- **No code generation**: zero builders, no watch tasks, no generated files.\n- **Explicit fields**: models declare fields as objects with type-aware behavior.\n- **Nested models \u0026 lists**: compose with `JsonObject\u003cT\u003e` and `JsonList\u003cT\u003e`.\n- **Validation metadata**: per-field `error`, `warning`, `information` plus model-level collections.\n- **Selective output**: only non-null values are serialized; special handling for `id`-suffixed fields.\n\nFor background and motivation, read the article: [Overcome Flutter JSON drawbacks](https://thanhtunguet.info/posts/overcome-flutter-json-drawbacks/).\n\n---\n\n## Installation\n\nAdd to your `pubspec.yaml`:\n\n```yaml\ndependencies:\n  json_entity: ^2.0.0\n```\n\nThis package depends on `get_it` and `intl`.\n\n---\n\n## Core concepts\n\n- **JsonModel**: base class for your models. Implements `fromJson` and `toJson` over a list of declared `fields`.\n- **JsonField\u003cT\u003e**: base class for fields. Concrete types provide parsing, defaults, and JSON conversion.\n- **GetIt**: used to construct nested models when deserializing `JsonObject\u003cT\u003e` and `JsonList\u003cT\u003e`.\n\n### Field types\n\n- `JsonString`, `JsonInteger`, `JsonDouble`, `JsonBoolean`, `JsonNumber`\n- `JsonDate` (string parsing, ISO output in UTC)\n- `JsonObject\u003cT extends JsonModel\u003e` (nested model)\n- `JsonList\u003cT extends JsonModel\u003e` (list of nested models)\n\nAll fields expose:\n- `rawValue` (nullable backing store)\n- `value` getter (type-safe, with sensible defaults like empty string or 0)\n- `error` / `warning` / `information` (metadata for validation/UX)\n\n---\n\n## Quick start\n\n1) Register your model types with `GetIt` so nested objects/lists can be constructed during `fromJson`:\n\n```dart\nfinal getIt = GetIt.instance;\ngetIt.registerFactory\u003cUser\u003e(() =\u003e User());\ngetIt.registerFactory\u003cAddress\u003e(() =\u003e Address());\n```\n\n2) Define models by extending `JsonModel` and declaring `fields`:\n\n```dart\nclass Address extends JsonModel {\n  final street = JsonString('street');\n  final city = JsonString('city');\n  final zipCode = JsonString('zipCode');\n\n  @override\n  List\u003cJsonField\u003e get fields =\u003e [street, city, zipCode];\n}\n\nclass User extends JsonModel {\n  final id = JsonInteger('id');\n  final name = JsonString('name');\n  final email = JsonString('email');\n  final isActive = JsonBoolean('isActive');\n  final balance = JsonDouble('balance');\n  final createdAt = JsonDate('createdAt');\n\n  final address = JsonObject\u003cAddress\u003e('address');\n  final tags = JsonList\u003cTag\u003e('tags');\n\n  @override\n  List\u003cJsonField\u003e get fields =\u003e [\n    id, name, email, isActive, balance, createdAt,\n    address, tags,\n  ];\n}\n\nclass Tag extends JsonModel {\n  final id = JsonInteger('id');\n  final name = JsonString('name');\n\n  @override\n  List\u003cJsonField\u003e get fields =\u003e [id, name];\n}\n```\n\n3) Deserialize from JSON:\n\n```dart\nfinal user = getIt\u003cUser\u003e();\nuser.fromJson({\n  'id': 0,\n  'name': 'Alice',\n  'email': 'alice@example.com',\n  'isActive': true,\n  'balance': '19.99',\n  'createdAt': '2024-08-07T12:34:56Z',\n  'address': {\n    'street': '1 Main St',\n    'city': 'Springfield',\n    'zipCode': '12345',\n  },\n  'tags': [\n    {'id': 1, 'name': 'pro'},\n    {'id': 2, 'name': 'beta'},\n  ],\n});\n\n// Access values\nafinal String name = user['name'];\nfinal String city = user.address['city'];\nfinal Tag firstTag = user.tags[0];\n```\n\n4) Serialize to JSON:\n\n```dart\nfinal map = user.toJson();\nfinal json = user.toString(); // jsonEncode(toJson())\n```\n\nSerialization rules:\n- Only fields with non-null `rawValue` are emitted.\n- Fields whose name ends with `id` (case-insensitive) except `statusId` are omitted if their `value` is `0`.\n- Fields use their specific `toJson` implementations (e.g., `JsonDate` outputs UTC ISO 8601).\n\n---\n\n## Working with values vs rawValue\n\n- Use `value` to read/write in a type-safe way. Implementations accept helpful inputs:\n  - `JsonInteger` parses numeric strings.\n  - `JsonDouble` accepts `int`, `double`, numeric `String`.\n  - `JsonDate` accepts ISO string and outputs UTC ISO string.\n- Use `rawValue` if you need to check presence (`null`) vs defaulted value.\n\nExamples:\n\n```dart\nuser.balance.value = '42.5'; // stored as double\nuser.createdAt.value = '2024-08-07T12:34:56Z';\n\nif (user.email.isNull) {\n  user.email.error = 'Email is required';\n}\n```\n\n---\n\n## Validation metadata and messages\n\nAt the model level:\n- `generalErrors`, `generalWarnings`, `generalInformations` (Lists)\n- `errors`, `warnings`, `informations` (fieldName -\u003e message)\n\n`fromJson` maps these structures into matching field properties so your UI can bind per-field messages:\n\n```dart\nuser.fromJson({\n  'errors': {\n    'email': 'Email already taken',\n  },\n  'warnings': {\n    'name': 'Nickname looks too short',\n  }\n});\n\nif (user.email.hasError) {\n  print(user.email.error);\n}\n```\n\n---\n\n## Nested objects and lists\n\n`JsonObject\u003cT\u003e` and `JsonList\u003cT\u003e` construct nested model instances using `GetIt`. Register factories for all `T` types you nest.\n\n```dart\ngetIt.registerFactory\u003cOrder\u003e(() =\u003e Order());\ngetIt.registerFactory\u003cOrderItem\u003e(() =\u003e OrderItem());\n\nclass Order extends JsonModel {\n  final id = JsonInteger('id');\n  final items = JsonList\u003cOrderItem\u003e('items');\n  @override\n  List\u003cJsonField\u003e get fields =\u003e [id, items];\n}\n\nclass OrderItem extends JsonModel {\n  final sku = JsonString('sku');\n  final qty = JsonInteger('qty');\n  @override\n  List\u003cJsonField\u003e get fields =\u003e [sku, qty];\n}\n```\n\n---\n\n## Date handling\n\n`JsonDate`:\n- `value` returns `DateTime` (defaults to `DateTime.now()` if `rawValue` is null).\n- Accepts ISO strings on assignment and parses with `DateTime.tryParse`.\n- `toJson()` emits `toUtc().toIso8601String()`.\n- `format()` uses `intl` `DateFormat` (default `dd/MM/yyyy`).\n\nUtility extension `DateTimeOffsetExtensions` provides:\n- `getTimezoneOffsetString()` as `±hh:mm` or empty for UTC.\n- `toIso8601StringWithOffset()` appends offset string to `toIso8601String()`.\n\n---\n\n## Access helpers\n\n- Index into models by field name: `model['name']`, `model['id'] = 123`.\n- Index into objects/lists: `jsonObject['city']`, `jsonList[0]`.\n\nOut-of-range or missing-field access throws an exception to surface errors early.\n\n---\n\n## Why this approach (vs code generation)?\n\n- **No build step**: instant feedback, simpler CI, fewer moving parts.\n- **Lean repo**: no `.g.dart` file explosion; easier navigation and diffs.\n- **IDE performance**: fewer files to index; faster search and refactors.\n- **Explicit mapping**: fields are first-class citizens where you attach validation and transformation logic.\n- **Composable**: nested models and lists are defined declaratively without annotations.\n\nIf you prefer annotation-based codegen, packages like `json_serializable` are great. This library targets teams that value runtime composition and development ergonomics akin to Laravel Eloquent.\n\n---\n\n## Tips\n\n- Always register nested model types in `GetIt` before calling `fromJson`.\n- Use `rawValue` null checks to control serialization output.\n- For IDs, setting `0` effectively omits the key (except `statusId`).\n- `JsonList` defaults to an empty list and maps elements via `GetIt`.\n\n---\n\n## License\n\nMIT © Thanh Tung\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthanhtunguet%2Fflutter_json_entity","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthanhtunguet%2Fflutter_json_entity","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthanhtunguet%2Fflutter_json_entity/lists"}