@pcraig3, @mepps, and @tom_plinth,
Thank you all so much for your thoughtful responses!
It was really helpful to have these additional as we synthesized the first round of feedback for HHS leadership. And I appreciate your patience as I got a chance to respond more thoughtfully to your comments.
I might not be able to touch on all of the individual questions and suggestions, but I’ll try to cover the main themes below:
Data model
Thanks for the deep dive into the proposed data model @pcraig3! I know we’ve chatted a bit about your questions directly, but for other folks who might have similar questions.
Before we dive into the specific questions though, I wanted to highlight a couple of important distinctions about CommonGrants:
- The CommonGrants models and requirements only apply to CommonGrants-defined API endpoints (e.g.
GET /common-grants/opportunities/
). Platforms interested in adopting the standard can continue maintain their own representation of the data internally and in non-CommonGrants public API endpoints (i.e. endpoints not prefixed with /common-grants/
)
- Systems or tools that want to interface with other CommonGrants APIs need to be able to translate data into the proposed CommonGrants format, but DO NOT need to implement the required routes themselves.
- Because we anticipate most tools will opt to translate their current data models into CommonGrants compatible-formats rather than changing how the data is represented internally, we’re working on a proposed mapping format and set of SDKs that will enable adopters to automate this data transformation using a declarative mapping config.
Field name casing
Yes, the fields defined explicitly by the standard are in camelCase
matching the case for those properties is REQUIRED, but camelCase is RECOMMENDED for all other custom fields. We should add that guidance to the specification though.
Additionally, we’re considering building the SDKs to automatically convert custom field names into camelCase unless directed to preserve the original case.
IDs
While systems looking to adopt the CommonGrants standard can continue to support serial or integer IDs for their internal systems or custom API endpoints, they should support some indexed UUID field as well if they plan to implement the CommonGrants API routes.
As mentioned above, if a system doesn’t plan to implement the CommonGrants API endpoints directly and only needs to fetch data from or write data to other systems that support CommonGrants, then adoption of a UUID is a little less critical.
Source (url)
The intention behind this field is for CommonGrants systems that are designed to serve as aggregators of opportunities from multiple sources (e.g. Grants.gov, state-specific grant platforms, etc.) to be able to link users back to the original grant posting on the host system.
As such, it doesn’t really apply to the NOFO builder, since y’all are upstream of the final posting and, as you mentioned, members of the public wouldn’t be fetching data from your system directly.
Status
Since we don’t post NOFOs, we won’t ever have a use for “status” the way it is described here. Our status field describes where the NOFO document is in the editing process (‘draft’, ‘active’, ‘in review’, etc).
Yup! Because y’all’s status is semantically different from the opportunity status field defined by CommonGrants, there are two main options:
- As you suggested, hide it from the related CommonGrants endpoint
- Move it to a separate custom field e.g. (
nofoStatus
) that indicates it relates to the NOFO rather than the opportunity as a whole
Again this is only really necessary when we’re talking about translating data from the NOFO builder to another system that is using CommonGrants.
Custom fields
Thanks for these additional thoughts about custom fields @pcraig3 and @mepps!
Summarizing a bit, it sounds like there are three main questions it would be helpful to address:
- Why move custom fields into a nested property rather than keeping them at the root of the opportunity model?
- How can we provide more structure or context around custom fields to make them useful?
- How can we avoid duplication of custom fields that are semantically equivalent but defined differently across systems?
This is definitely an area for further design as we incorporate feedback from the RFC into the first release of the protocol, but I’ll try to offer some initial clarification around these questions below:
Why nest custom fields?
The primary use case for custom fields is for platforms that have implemented the CommonGrants-defined API endpoints (e.g. GET /common-grants/opportunities/
) to enrich their response with fields that aren’t defined by the CommonGrants standard but important for their specific platform (e.g. CFDA listing for federal opportunities)
There are two main reasons we require API responses for CommonGrants endpoints to follow the custom fields format:
- It distinguishes standard fields from non-standard fields within the response body, and requires custom fields to provide a bit more context for parsing and interpretation.
- It avoids collisions with future additions to the standard data model by reserving the top-level namespace for CommonGrants-defined fields.
However, again these restrictions only apply to the specific endpoints defined by the CommonGrants API. Other platform-specific endpoints can include other properties at the root-level.
Custom field structure
It might be helpful to explain that custom fields are really defined at two levels:
- An arbitrary custom field in the CommonGrants standard
- A specific custom field in a given CommonGrants implementation
At the CommonGrants standard level, custom fields only need to satisfy a basic set of criteria:
- They are an object in nested in the
customFields
property on a model that supports custom fields
- They have a name,
type
, and value field, with optional description and schema field
- The
type
field describes the JSON-compliant type used to deserialize the value field
Within a given CommonGrants implementation, ideally the OpenAPI spec is explicitly defining which custom fields it supports and/or requires. So in addition to the general criteria above, a given CommonGrants API will likely define:
- A specific key for each custom field (e.g.
cfdaListing
or legacyId
) that allows the API consumer to parse that field deterministically.
- A specific format that the
value
field must satisfy (could be a simple type like string, int, etc. or compound types like an array of strings)
What I’m potentially hearing though, is that maybe in addition to having a CommonGrants API define these custom fields in their OpenAPI specs, it could be helpful to include a mapping of all supported custom fields and their expected schemas at the root of the API response?
If so, I’ll have to think a bit more about how best to represent that in the OpenAPI spec itself since it’s a bit meta.
Avoiding duplicate custom fields
This is a much deeper problem space that we haven’t fully explored.
The ideal vision is to have CommonGrants APIs optionally publish packages for frequently custom fields, so that other platforms could re-use them. It’s part of the reason we chose TypeSpec as the language for defining the protocol itself since developers could create custom npm packages.
How we make those custom field packages discoverable and usable across multiple language-specific SDKs, though, is something we’re still figuring out. But ideally CommonGrants would be a repository for these custom fields so that users can discover and re-use them.
Similar efforts and strategic considerations
@tom_plinth Thank you for all of the resources and notes you shared about past standardization efforts that you’ve seen succeed and struggle in the UK.
I’ve been looking into 360 Giving more since you mentioned it and anticipate making few changes to our proposed data model to align more closely with their existing standard.
Your broader suggestions about the role of LLMs and the importance of defining a clear value proposition and use case for adopting this standard, doing so in a way that balances centralization with federation is now the focus of our strategic conversations around next steps for CommonGrants. We’d love to continue to engage you in those conversations and maybe pitch some ideas for incentivizing the kind of reciprocal data sharing you and I discussed.