Create a Data Helper in Python for gRPC-style APIs

This code builds a simple DataHelper class that mimics gRPC request/response handling with in-memory storage, JSON serialization, and basic CRUD operations for beginners.

Easy Python 3.10+ Aug 9, 2026 API design & gRPC 14 views 0 copies

Python code

54 lines
Python 3.10+
import json
from dataclasses import dataclass, asdict
from typing import Dict, Any


@dataclass
class User:
    user_id: int
    name: str
    email: str


class DataHelper:
    """Simple helper to demonstrate gRPC-like data handling for beginners."""

    def __init__(self) -> None:
        self._users: Dict[int, User] = {}

    def create_user(self, user: User) -> User:
        """Simulates a gRPC CreateUser request."""
        self._users[user.user_id] = user
        return user

    def get_user(self, user_id: int) -> User | None:
        """Simulates a gRPC GetUser request."""
        return self._users.get(user_id)

    def list_users(self) -> list[User]:
        """Simulates a gRPC ListUsers request."""
        return list(self._users.values())

    def to_json(self, user: User) -> str:
        """Serialize user to JSON (like protobuf-marshaling)."""
        return json.dumps(asdict(user), indent=2)


if __name__ == "__main__":
    helper = DataHelper()

    # Simulate client requests
    alice = helper.create_user(User(user_id=1, name="Alice", email="alice@example.com"))
    bob = helper.create_user(User(user_id=2, name="Bob", email="bob@example.com"))

    print("Created:", helper.to_json(alice))
    print("Fetched:", helper.to_json(helper.get_user(1)))
    print("All users:")
    for user in helper.list_users():
        print(" ", user)

    # Show request/response flow
    print("\n-- gRPC-like round trip --")
    response = helper.get_user(2)
    print("Request: GetUser(user_id=2)")
    print("Response:", helper.to_json(response) if response else "NOT FOUND")

Output

stdout
Created: {
  "user_id": 1,
  "name": "Alice",
  "email": "alice@example.com"
}
Fetched: {
  "user_id": 1,
  "name": "Alice",
  "email": "alice@example.com"
}
All users:
  User(user_id=1, name='Alice', email='alice@example.com')
  User(user_id=2, name='Bob', email='bob@example.com')

-- gRPC-like round trip --
Request: GetUser(user_id=2)
Response: {
  "user_id": 2,
  "name": "Bob",
  "email": "bob@example.com"
}

How it works

The @dataclass decorator automatically generates __init__, __repr__, and comparison methods, keeping the User model clean. asdict() converts a dataclass instance into a plain dictionary, which json.dumps() then serializes to a JSON string with formatting. The DataHelper uses a dict keyed by user_id for O(1) lookup, mirroring how a gRPC server stores state. The | syntax in User | None and list[User] are Python 3.10+ type hints that make the code self-documenting.

Common mistakes

  • Forgetting to call `asdict()` before `json.dumps()` will raise a TypeError because dataclasses aren't JSON serializable by default.
  • Assuming `get_user` always returns a User — it can return `None`, so always check before using the result.
  • Using mutable default arguments (e.g., `def __init__(self, users={})`) which persist across instances and cause subtle bugs.

Variations

  1. Use `dataclasses-json` package for automatic serialization/deserialization with JSON.
  2. Replace the in-memory dict with a real database like SQLite for persistent storage.

Real-world use cases

  • Building a mock gRPC server for testing client code without network calls.
  • Prototyping an API layer that later converts to actual gRPC service definitions.
  • Teaching beginners how to manage request/response data structures in API design.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from API design & gRPC

Related tutorials and quizzes for this topic.