# CommonGrants Protocol Example Implementations: A Complete Guide

> Explore CommonGrants protocol example implementations in the hhs/simpler-grants-protocol repository. Learn with FastAPI and Python SDK for Pennsylvania and California APIs.

- Repository: [U.S. Department of Health & Human Services/simpler-grants-protocol](https://github.com/hhs/simpler-grants-protocol)
- Tags: how-to-guide
- Published: 2026-03-03

---

**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`](https://github.com/hhs/simpler-grants-protocol/blob/main/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`](https://github.com/hhs/simpler-grants-protocol/blob/main/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`](https://github.com/hhs/simpler-grants-protocol/blob/main/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`](https://github.com/hhs/simpler-grants-protocol/blob/main/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`](https://github.com/hhs/simpler-grants-protocol/blob/main/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`](https://github.com/hhs/simpler-grants-protocol/blob/main/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`](https://github.com/hhs/simpler-grants-protocol/blob/main/src/common_grants/routes/opportunities.py) delegates to the service layer:

```python

# 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:

```python

# 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:

```python

# 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:
   ```bash
   cd examples/pa-opportunity-example
   ```

2. Install dependencies and start the development server:
   ```bash
   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`](https://github.com/hhs/simpler-grants-protocol/blob/main/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`](https://github.com/hhs/simpler-grants-protocol/blob/main/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`](https://github.com/hhs/simpler-grants-protocol/blob/main/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.