Code for the CommonGrants core specification library, written in TypeSpec. This library is designed to be imported and extended by individual implementations of the CommonGrants protocol.
npm install @common-grants/core
A basic project structure that uses the library might look like this:
.
├── models.tsp # Extends @common-grants/core models with custom fields
├── routes.tsp # Overrides @common-grants/core routes to use the custom models
├── main.tsp # Defines an API service that uses the custom models and routes
|
├── tsp-output/ # Directory that stores the output of `tsp compile`, often .gitignored
|
├── package.json # Manages dependencies, commands, and library metadata
└── tspconfig.yaml # Manages TypeSpec configuration, including emitters
The Opportunity model is templated to support custom fields. First define your custom fields by extending the CustomField
model:
// models.tsp
import "@common-grants/core"; // Import the base specification library
// Allows us to use models and fields defined in the core library without
// prefixing each item with `CommonGrants.Models` or `CommonGrants.Fields`
using CommonGrants.Models;
using CommonGrants.Fields;
namespace CustomAPI.CustomModels;
// Define a custom field
model Agency extends CustomField {
name: "Agency";
type: CustomFieldType.string;
@example("Department of Transportation")
value: string;
description: "The agency responsible for this opportunity";
}
// Extend the `OpportunityBase` model to create a new `CustomOpportunity` model
// that includes the new `Agency` field in its `customFields` property
model CustomOpportunity extends OpportunityBase {
customFields: {
agency: Agency;
};
}
The router interfaces are templated to support your custom models. Override them like this:
// routes.tsp
import "@common-grants/core";
import "./models.tsp"; // Import the custom field and model from above
using CommonGrants.Routes;
using TypeSpec.Http;
@tag("Search")
@route("/common-grants/opportunities")
namespace CustomAPI.CustomRoutes {
alias OpportunitiesRouter = Opportunities;
// Use the default model for list but custom model for read and search
op list is OpportunitiesRouter.list;
op read is OpportunitiesRouter.read<CustomModels.CustomOpportunity>;
op search is OpportunitiesRouter.search<CustomModels.CustomOpportunity>;
}
Next, use these updated routes to define an API service:
// main.tsp
import "@typespec/http";
import "./routes.tsp"; // Import the routes from above
using TypeSpec.Http;
/** Description of your API goes here */
@service({
title: "Custom API",
})
namespace CustomAPI;
Generate an OpenAPI specification from your main.tsp
file using either the CLI:
npx tsp compile main.tsp --emit "@typespec/openapi3"
Or specify the emitter in tspconfig.yaml
:
# tspconfig.yaml
emitters:
- "@typespec/openapi3"
Both strategies will generate an OpenAPI specification in the tsp-output/
directory.
- See the TypeSpec documentation for more information on how to use TypeSpec.
- See the CommonGrants docs to learn more about the CommonGrants protocol.
- See the CommonGrants CLI for more developer tools related to the CommonGrants protocol.