python 133 lines · 3 tabs

Parsing a Nested JSON Feed into Normalized Dataclasses in Python

Shared by codesnips Aug 2026
3 tabs
from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Dict, List


@dataclass(frozen=True)
class Author:
    id: int
    name: str
    email: str = ""

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "Author":
        return cls(
            id=int(data["id"]),
            name=data["name"].strip(),
            email=data.get("email", ""),
        )


@dataclass
class Comment:
    id: int
    body: str
    created_at: datetime

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "Comment":
        return cls(
            id=int(data["id"]),
            body=data["body"],
            created_at=datetime.fromisoformat(data["created_at"]),
        )


@dataclass
class Article:
    id: int
    title: str
    author: Author
    comments: List[Comment] = field(default_factory=list)

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "Article":
        return cls(
            id=int(data["id"]),
            title=data["title"],
            author=Author.from_dict(data["author"]),
            comments=[Comment.from_dict(c) for c in data.get("comments", [])],
        )
3 files · python Explain with highlit

A common ETL problem is turning a deeply nested third-party JSON feed into flat, strongly-typed domain objects that the rest of an application can consume without reaching into raw dictionaries. This snippet shows how to do that with plain dataclasses and a small set of from_dict factory methods, keeping the mapping logic in one place and the rest of the code free of dict.get calls.

The entities.py tab defines the target shape. Each entity is a @dataclassAuthor, Comment, and Article — and normalization means the nested comment array on the feed becomes a real list of Comment objects rather than nested dicts. The from_dict classmethods act as the boundary between untyped input and typed output: Author.from_dict coerces the id to int, Comment.from_dict parses the ISO timestamp into a datetime, and Article.from_dict fans out over the raw comments list to build child objects. Defaults such as field(default_factory=list) keep the type honest when the feed omits a key.

The feed_importer.py tab drives the traversal. FeedImporter.load reads the feed and returns a flat ImportResult that separates a list of articles from a list of errors, so one malformed record does not abort the whole batch. The importer catches KeyError and ValueError per article and records the offending payload, a pattern that matters when ingesting real feeds where a single missing field is routine. _dedupe_authors shows a second normalization step: authors are collapsed by id so the same person referenced across many articles is stored once.

The test_importer.py tab documents the contract with a fixture. It asserts that nested comments become Comment instances, that timestamps are parsed to datetime, and that a record missing title lands in errors rather than raising. This tests the resilience guarantee explicitly.

The trade-off is that hand-written from_dict methods are more verbose than a schema library like pydantic, but they add zero dependencies and make the coercion rules obvious. This approach fits well for small-to-medium feeds where the shape is known and clarity beats configuration.


Related snips

python
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
from sklearn.linear_model import LogisticRegression

standard_pipeline = Pipeline([
    ('scaler', StandardScaler()),

Scaling and normalization choices for different model families

feature-scaling normalization machine-learning
by Dr. Elena Vasquez 1 tab
ruby
class SignupForm
  include ActiveModel::Model
  include ActiveModel::Attributes

  attribute :account_name, :string
  attribute :email, :string

Shallow Controller, Deep Params: Form Object Pattern

rails activemodel form-object
by codesnips 3 tabs
html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Form Validation Example</title>
  <style>

HTML forms with validation and accessibility

html forms validation
by Alex Chang 1 tab
ruby
module EmailNormalization
  extend ActiveSupport::Concern

  included do
    attr_accessor :soft_warnings

Soft Validation: Normalize + Validate Email

rails activerecord validations
by codesnips 4 tabs
ruby
class PostSerializer < ActiveModel::Serializer
  attributes :id, :title, :excerpt, :body, :published_at, :views, :likes_count, :comments_count

  attribute :can_edit, if: :current_user_can_edit?

  belongs_to :author, serializer: UserSummarySerializer

Serializers with ActiveModel::Serializers

rails api serialization
by Alex Kumar 2 tabs
ruby
class PostsController < ApplicationController
  def index
    posts = Post.for_feed.page(params[:page]).per(25)

    render json: {
      data: posts.map { |post| PostSerializer.new(post).as_json },

N+1 Proof Serialization with preloaded associations

rails activerecord performance
by codesnips 3 tabs

Share this code

Here's the card — post it anywhere.

Parsing a Nested JSON Feed into Normalized Dataclasses in Python — share card
Link copied