CommonGrants Protocol Example Implementations: A Complete Guide

The simpler-grants-protocol repository provides two fully functional example APIs—Pennsylvania and California—that demonstrate how to implement the CommonGrants protocol using FastAPI and the official Python SDK.

The hhs/simpler-grants-protocol repository ships with complete, runnable reference implementations that show exactly how to build a compliant grants data API. These examples demonstrate the CommonGrants protocol in action, illustrating how to transform legacy grant data into standardized formats and expose them through RESTful endpoints.

Available Example Implementations

The repository contains two parallel example projects located under the examples/ directory, each documented in examples/README.md:

  • Pennsylvania Grants Example API (examples/pa-opportunity-example/) – A FastAPI service that ingests Pennsylvania state grant data, transforms it to the CommonGrants schema, and exposes the standard endpoints.
  • California Grants Example API (examples/ca-opportunity-example/) – Uses the identical architecture applied to California state grant data, proving the reusability of the pattern across different data sources.

Both projects include quick-start commands (make install, make dev) and a src/common_grants/api.py entry point that wires the application together.

Architecture of the Example Implementations

Each example follows a clean, layered architecture that separates data ingestion from protocol compliance. According to the source code in pa-opportunity-example, the system is divided into four distinct layers:

Data Source Layer

Static JSON files stored under src/common_grants/data/ simulate the original state grant feeds. A small utility module (src/common_grants/utils/opp_data_source.py) provides a load_data() function that reads these files into Python dictionaries.

Transformation Layer

The src/common_grants/utils/opp_transform.py module contains helper functions that map raw source fields onto the SDK's typed models. For example, transform_pa_opportunity() converts Pennsylvania's native fields into OpportunityBase, OppFunding, and OppStatus objects from common_grants_sdk.schemas.pydantic.

Service Layer

The src/common_grants/services/opportunity.py file implements CRUD-style methods including list_opportunities() and get_opportunity(). These methods orchestrate data loading and transformation before returning fully typed response objects.

FastAPI Router Layer

The src/common_grants/routes/opportunities.py module wires the service layer into the standard CommonGrants REST contract. It exposes GET /common-grants/opportunities for listing and GET /common-grants/opportunities/{id} for retrieval.

Code Walkthrough: Pennsylvania Grants API

Examining the Pennsylvania example reveals the exact implementation pattern. The route handler in src/common_grants/routes/opportunities.py delegates to the service layer:


# pa-opportunity-example/src/common_grants/routes/opportunities.py

from fastapi import APIRouter, HTTPException
from ..services.opportunity import OpportunityService

router = APIRouter(prefix="/common-grants/opportunities", tags=["opportunities"])

@router.get("/", response_model=list[OpportunityBase])
def list_opportunities():
    """
    Return all opportunities in the Common Grants format.
    """
    try:
        return OpportunityService().list_opportunities()
    except Exception as exc:
        raise HTTPException(status_code=500, detail=str(exc))

The backing service loads raw data and applies the transformation utility:


# pa-opportunity-example/src/common_grants/services/opportunity.py

from ..utils.opp_transform import transform_pa_opportunity
from ..utils.opp_data_source import load_data

class OpportunityService:
    def list_opportunities(self):
        raw = load_data()                         # reads PA-grant-data.sample.json

        return [transform_pa_opportunity(item) for item in raw]

The transformation logic maps source fields to the SDK's Pydantic models:


# pa-opportunity-example/src/common_grants/utils/opp_transform.py

from common_grants_sdk.schemas.pydantic.models import OpportunityBase, OppFunding
from common_grants_sdk.schemas.pydantic.fields import Money

def transform_pa_opportunity(raw: dict) -> OpportunityBase:
    return OpportunityBase(
        id=raw["grant_id"],
        title=raw["title"],
        description=raw.get("description"),
        funding=OppFunding(
            amount=Money(value=raw["award_amount"], currency="USD")
        ),
        # ... map other required fields ...

    )

Running the Examples Locally

Each example includes a Makefile for dependency management and execution. To run the Pennsylvania API:

  1. Navigate to the example directory:

    cd examples/pa-opportunity-example
  2. Install dependencies and start the development server:

    make install
    make dev

The API becomes available at http://localhost:8000, where you can query:

  • GET /common-grants/opportunities – Returns the full list of transformed opportunities
  • GET /common-grants/opportunities/{id} – Returns a single opportunity by ID

Additionally, the src/common_grants/scripts/generate_openapi.py script generates the OpenAPI specification using the common-grants-sdk CLI, which you can validate with the cg check spec command.

Summary

  • The CommonGrants protocol example implementations include two complete FastAPI projects in examples/pa-opportunity-example/ and examples/ca-opportunity-example/.
  • Both examples demonstrate a layered architecture: data source → transformation → service → FastAPI router.
  • The transformation layer uses common_grants_sdk.schemas.pydantic types to ensure strict protocol compliance.
  • You can start either example locally using make dev and interact with the standard endpoints at /common-grants/opportunities.

Frequently Asked Questions

What is the CommonGrants protocol?

The CommonGrants protocol is a standardized specification for exposing grant opportunity data through RESTful APIs. It defines specific schemas for opportunities, funding details, and status information, allowing grant seekers to query multiple sources using a uniform interface.

Where are the example implementations located in the repository?

The examples reside in the examples/ folder at the repository root. The Pennsylvania implementation is under examples/pa-opportunity-example/, while the California counterpart is under examples/ca-opportunity-example/. Both are described in detail in examples/README.md.

How do the examples transform source data into the CommonGrants format?

Each example uses a dedicated transformation utility. In pa-opportunity-example/src/common_grants/utils/opp_transform.py, the transform_pa_opportunity() function takes raw dictionary data from state JSON files and constructs typed Pydantic models (OpportunityBase, OppFunding) imported from common_grants_sdk.schemas.pydantic.

Can I use these examples as a template for my own implementation?

Yes. The architecture is intentionally generic: replace the load_data() function with your own data source connector, update the transformation logic to match your source schema, and keep the service and router layers unchanged. The California example demonstrates this exact reuse pattern with a different data source than Pennsylvania.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →