Getting started
Welcome to the CommonGrants protocol documentation. This guide will help you get started with understanding and implementing the protocol.
What is CommonGrants?
CommonGrants is a protocol designed to standardize how data about funding opportunities, applications, and awards is shared across the grant ecosystem.
The CommonGrants protocol is built on top of TypeSpec, a language for describing APIs that compiles to OpenAPI, JSON Schema, and other formats. To simplify the process of adopting this protocol, CommonGrants has published both:
- A TypeSpec library
@common-grants/core
with a default set of models and routes - A CLI tool
@common-grants/cli
to help you define and validate your API implementation
Quickstart
The following tutorial will walk you through:
- Creating a new CommonGrants API specification using TypeSpec
- Compiling your project to OpenAPI and previewing it with Swagger
- Extending the base CommonGrants spec to include a custom field
- Viewing this new field in the OpenAPI docs
First steps
First, we’ll show you how to set up and preview the default CommonGrants API specification using the CLI and quickstart template.
-
Install the CLI and TypeSpec compiler globally
Terminal window npm install @common-grants/cli @typespec/compiler -g -
Create a new directory for your project
Terminal window mkdir common-grants-quickstartcd common-grants-quickstart -
Initialize your project with the quickstart template.
Terminal window cg init --template quickstartFollow the prompts and accept the default options.
Terminal window TypeSpec compiler v0.63.0Example from the quickstart guide✔ Project name … common-grants-quickstart✔ Do you want to generate a .gitignore file? … yes✔ Update the libraries? › @common-grants/coreTypeSpec init completed. You can run `tsp install` now to install dependencies.Project created successfully. -
Install the project dependencies
Terminal window tsp install -
Compile and preview your API specification at
http://localhost:3000
Terminal window cg compile main.tspcg preview tsp-output/@typespec/openapi3/openapi.Quickstart.yaml
Deep dive
Next, we’ll take a step back and walk you through what happened behind the scenes when you ran the CLI commands listed above.
Explore the files created by cg init
When you run cg init
it sets up a new CommonGrants project in the common-grants-quickstart
directory with the following files:
- main.tsp # Defines the API service
- routes.tsp # Defines the API routes
- tspconfig.yaml # Configures TypeSpec emitters (e.g. OpenAPI)
- package.json # Manages project dependencies
- .gitignore # Ignores files from the project
- README.md # The project README
We’ll focus on exploring the following files in particular:
Understanding routes.tsp
The routes.tsp
file is the TypeSpec file that defines the API routes.
import "@common-grants/core";
using TypeSpec.Http;
@tag("Opportunities")@route("/common-grants/opportunities")namespace Quickstart.Routes { alias OpportunitiesRouter = CommonGrants.Routes.Opportunities;
op list is OpportunitiesRouter.list; op read is OpportunitiesRouter.read; op search is OpportunitiesRouter.search;}
Since there’s a lot happening here, let’s break it down section by section.
-
Import the CommonGrants TypeSpec library.
import "@common-grants/core"; -
Expose the
TypeSpec.Http
namespace.using TypeSpec.Http;This makes the
@route
and@tag
keywords available in the current namespace without requiring theTypeSpec.Http
prefix. -
Define a namespace for the
OpportunitiesRouter
.@tag("Opportunities")@route("/common-grants/opportunities")namespace Quickstart.Routes {alias OpportunitiesRouter = CommonGrants.Routes.Opportunities;// operations omitted for brevity}Think of the
OpportunitiesRouter
as a controller in a traditional MVC framework that groups related routes together under theOpportunities
tag and exposes them at the/common-grants/opportunities
path. -
Expose the default routes from the CommonGrants library.
@tag("Opportunities")@route("/common-grants/opportunities")namespace Quickstart.Routes {alias OpportunitiesRouter = Opportunities;op list is OpportunitiesRouter.list;op read is OpportunitiesRouter.read;op search is OpportunitiesRouter.search;}This exposes the following default routes from the CommonGrants library:
GET /common-grants/opportunities
GET /common-grants/opportunities/{id}
POST /common-grants/opportunities/search
Understanding main.tsp
The main.tsp
file is the TypeSpec file that defines the API service.
import "@typespec/http";import "./routes.tsp";
using TypeSpec.Http;
/** API description here */@service({ title: "Quickstart API",})namespace Quickstart;
Let’s break down the main.tsp
file section by section.
-
Import the TypeSpec HTTP module and the
routes.tsp
file.import "@typespec/http";import "./routes.tsp";Importing the
routes.tsp
includes the routes from that file in the OpenAPI document generated by thecg compile
command. -
Expose the
TypeSpec.Http
namespace.using TypeSpec.Http;This makes the
@service
keyword available in the current namespace without requiring theTypeSpec.Http
prefix. -
Define the API service.
/** API description here */@service({title: "Quickstart API",})namespace Quickstart;This defines the API service with a title of “Quickstart API”. The
@service
keyword is used to define the API service and is required for the OpenAPI emitter to work. Thetitle
property is used to set the title of the API and the docstring is used to set the description of the API in the OpenAPI docs.
Understanding tspconfig.yaml
The tspconfig.yaml
file is the TypeSpec configuration file that defines the emitters for the project.
emitters: - "@typespec/openapi3" - "@typespec/json-schema"
This configures the TypeSpec compiler to emit the API definition as an OpenAPI document and a JSON Schema.
Explore the packages installed by tsp install
When you run tsp install
, the following packages are installed (among others):
@common-grants/core
The CommonGrants TypeSpec library, which includes a default set of models and routes that can be used to define your own CommonGrants API.@typespec/openapi3
The OpenAPI emitter for TypeSpec, which emits the CommonGrants API definition as an OpenAPI document.@typespec/json-schema
The JSON Schema emitter for TypeSpec, which emits the models in your CommonGrants API as JSON Schemas.
Explore the files created by cg compile
This will create a tsp-output
directory with the following files compiled from main.tsp
:
Directory
tsp-output/
Directory
@typespec/
Directory
openapi3/
Auto-generated by the OpenAPI emitteropenapi.CommonGrants.yaml
The base CommonGrants API specopenapi.Quickstart.yaml
The quickstart API spec
Directory
json-schema/
Auto-generated by the JSON Schema emitterCustomEnumValue.yaml
Opportunity.yaml
- …
Understanding the cg preview
command
The cg preview
command starts a local server that serves the OpenAPI specification using Swagger UI. View your API specification at http://localhost:3000
.
Customization
Finally, we’ll show you how to extend the base CommonGrants API specification with a custom field.
Add a custom field to the Opportunity
model
Create a new file called models.tsp
with the following code:
import "@common-grants/core";
// Allows us to use models defined in the specification library// without prefixing each model with `CommonGrants`using CommonGrants.Models;using CommonGrants.Fields;
namespace Quickstart.Models;
model Agency extends CustomField { name: "Agency"; type: CustomFieldType.string; value: string; description: "The agency managing the funding opportunity.";}
// Create a custom Opportunity type using the templatemodel CustomOpportunity extends OpportunityBase { @example(#{ agency: #{ name: "Agency", type: CustomFieldType.string, value: "Department of Energy", description: "The agency managing the funding opportunity.", }, }) customFields: { agency: Agency; };}
There’s a lot happening here, so let’s break it down section by section.
-
Import the CommonGrants TypeSpec library.
import "@common-grants/core"; -
Make the CommonGrants fields, models, etc. available in the current namespace.
using CommonGrants.Fields;using CommonGrants.Models;Without this, you would have to prefix each model with
CommonGrants.Models
and each field withCommonGrants.Fields
. For exampleCommonGrants.Fields.CustomField
. -
Declare a namespace for the current file.
namespace Quickstart.Models; -
Define a custom field by extending the
CustomField
model.model Agency extends CustomField {name: "Agency";type: CustomFieldType.string;value: string;description: "The agency managing the funding opportunity.";}The
Agency
model defines literal values for the field’sname
,type
, anddescription
metadata properties, and requires thevalue
property to be a string. -
Extend the
OpportunityBase
model to include this custom field.model CustomOpportunity extends Models.OpportunityBase {// Example omitted for brevitycustomFields: {agency: Agency;};}It also provides an example of the updated
customFields
property, which will be displayed in the OpenAPI docs.model CustomOpportunity extends Opportunity.OpportunityBase {@example(#{agency: #{name: "Agency",type: Fields.CustomFieldType.string,value: "Department of Energy",description: "The agency managing the funding opportunity."}})customFields: {agency: Agency;};}
Update the default routes
Update the routes.tsp
file and make the following changes:
- Import the
models.tsp
file to expose theCustomOpportunity
model. - Update the routes to use the
CustomOpportunity
model.
import "@common-grants/core";import "./models.tsp";
using TypeSpec.Http;
@tag("Opportunities")@route("/common-grants/opportunities")namespace Quickstart.Routes { alias OpportunitiesRouter = CommonGrants.Routes.Opportunities;
op list is OpportunitiesRouter.list; op read is OpportunitiesRouter.read; op search is OpportunitiesRouter.search; op list is OpportunitiesRouter.list<Models.CustomOpportunity>; op read is OpportunitiesRouter.read<Models.CustomOpportunity>; op search is OpportunitiesRouter.search<Models.CustomOpportunity>;}
Let’s explain these changes section by section.
-
Import the
models.tsp
file to expose theCustomOpportunity
model.import "./models.tsp"; -
Update the default routes to use the
CustomOpportunity
model.@tag("Opportunities")@route("/common-grants/opportunities")namespace Quickstart.Routes {alias OpportunitiesRouter = Opportunities;op list is OpportunitiesRouter.list<Models.CustomOpportunity>;op read is OpportunitiesRouter.read<Models.CustomOpportunity>;op search is OpportunitiesRouter.search<Models.CustomOpportunity>;}This updates
GET /opportunities
andGET /opportunities/{id}
to return ourCustomOpportunity
model instead of the default model from the CommonGrants library.
The updated routes.tsp
file should now look like this:
import "@common-grants/core";import "./models.tsp";
using TypeSpec.Http;
@tag("Opportunities")@route("/common-grants/opportunities")namespace Quickstart.Routes { alias OpportunitiesRouter = CommonGrants.Routes.Opportunities;
op list is OpportunitiesRouter.list<Models.CustomOpportunity>; op read is OpportunitiesRouter.read<Models.CustomOpportunity>; op search is OpportunitiesRouter.search<Models.CustomOpportunity>;}
View your changes
cg compile main.tspcg preview tsp-output/@typespec/openapi3/openapi.Quickstart.yaml
This should start a local server that serves the OpenAPI specification using Swagger UI. View your API specification at http://localhost:3000
.
Next steps
Learn more about the CommonGrants protocol:
Learn more about TypeSpec: