Getting started
Welcome! This quickstart tutorial will help you define a CommonGrants API using TypeSpec and explore the core routes and models defined by the protocol.
Find your way around
Section titled “Find your way around”Not looking for a quickstart guide? Here are some other resources to help you get started:
Quickstart
Section titled “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
Section titled “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 globally
Terminal window npm install @common-grants/cli -g -
Create a new directory for your project
Terminal window mkdir common-grants-quickstartcd common-grants-quickstart -
Initialize your project with the quickstart template.
Note: The TypeSpec compiler will warn you about using an untrusted template. This is expected and the template is safe to use.
Terminal window cg init --template quickstartFollow the prompts and accept the default options.
Terminal window ✔ Continue Yes✔ Enter a project name: common-grants-quickstart✔ Installing dependenciessuccess: Project initialized! -
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
Section titled “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.
If you want to jump straight into customizing the API spec, feel free to skip ahead to the Customization section.
Explore the files created by cg init
Section titled “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
Section titled “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
Section titled “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
Section titled “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 cg init
Section titled “Explore the packages installed by cg init”When you run cg init
, 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
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “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
.
Specifically look for the agency
field in the customFields
property of the Opportunity
model at http://localhost:3000/#/Opportunities/Routes_read
. It should look something like this:
Next steps
Section titled “Next steps”Learn more about the CommonGrants protocol:
Learn more about TypeSpec: