Introduction-to-TypeSpec

Introduction to TypeSpec

Posted in

Our 2024 Austin API Summit was notable for many things, but one thing that stuck in my mind (along with many great stories about AI) was a comprehensive introduction to TypeSpec. TypeSpec is an API description language that describes itself as “API-first for developers” and aims to differentiate itself from similar description languages.

The appearance of TypeSpec in an API landscape largely allied to OpenAPI may surprise many people. Using OpenAPI to create rich API descriptions has become the de facto choice for REST APIs in the API economy, so a new API description language may seem unnecessary to some.

However, TypeSpec was created to meet the needs of a large and varied developer community and includes a range of features to help them embrace API-first. It is an open-source project available to anyone in the API economy. Therefore, it’s important to explore the principles and constructs of TypeSpec to understand its value in API design and development.

Origins of TypeSpec

TypeSpec was originally conceived at Microsoft as a means to provide a universal, homogeneous API description language that could help underpin products like the Microsoft Graph, a single API that acts as a “gateway to data and intelligence” in Microsoft 365. TypeSpec was not built solely for Microsoft Graph, but the Graph team understood that TypeSpec provides a friendly means to do design-first API development, allowing developers to shape their APIs using a language that looks like code.

You may be asking why Microsoft did not use OpenAPI as the API description language of choice, especially given Microsoft is an OpenAPI Initiative member. At our 2024 Austin Summit, Mandy Whaley from the Microsoft Azure SDK team provided several reasons in her Summit talk on TypeSpec:

  • OpenAPI was perceived by Microsoft teams as being hard to write, review, and maintain.
  • It was difficult to follow API guidelines in this context, especially when working with many new teams that did “know” OpenAPI.
  • OpenAPI does not rule the Microsoft world in terms of API description languages and protocols, with others such as gRPC being supported.

An alternative mechanism was therefore required that allowed the consistency and ease-of-use Microsoft was looking for, hence the development of TypeSpec. Mandy highlighted three key features of using TypeSpec in her talk that benefit the developer community at Microsoft:

  • It provides a lightweight language for describing and designing APIs.
  • TypeSpec is easy to integrate into your OpenAPI toolchain.
  • Your API guidelines can be expressed in reusable code.

Each of these features brings something different to the use case for TypeSpec.

Watch Mandy Whaley speak at the 2024 Austin API Summit:

Lightweight Language for APIs

TypeSpec — as the name suggests — is closely allied to TypeScript in terms of the “look-and-feel” of the language. It is a TypeScript project and uses Node.js as its runtime. It follows the design-first concept so that an API designer will “start” with a TypeSpec project to describe their APIs and then use that to project to generate code, OpenAPI specifications, or do whatever they do next in their API lifecycle.

Once the project has been created by following the getting started guide, you can start modeling your API. If you want to start with your data, you can create models to represent your requests and responses first. For example, a model that represents the Pet in the famous Petstore OpenAPI description (borrowing heavily from the TypeSpec documentation) would look something like this:

model Pet {

  id: int64;
  name: string;
  status: "available" | "pending" | "sold";
}

You may decide that your API should follow HTTP and REST semantics. You can import support for these from TypeSpec packages:

using TypeSpec.Http;
using TypeSpec.Rest;

You can then design your API using TypeSpec decorators that indicate object types or provide metadata about them. For example, you can define a URI using the @route decorator:

@route("/pets")
namespace Pets {

}

Or you might pick up existing models from the imported packages, such as a BadRequestResponse to describe your message body when returning an HTTP 400 status code. You can combine this with other models and decorators to describe your APIs, with the focus being on providing terse definitions:

@route("/pets")
namespace Pets {
  op list(@query skip: int32, @query top: int32): {
    @statusCode statusCode: 200;
    @body pets: Pet[];
  };
  op read(@path petId: int32, @header ifMatch?: string): {
    @statusCode statusCode: 200;
    @header eTag: string;
    @body pet: Pet;
  } | {
    @statusCode statusCode: 404;
  };
  op create(@body pet: Pet): {
    @statusCode statusCode: 204;
  };
}

The goal is one of productivity. TypeSpec is a developer-orientated API description language with a low knowledge overhead that focuses on getting the design right with as little fuss as possible. This, when coupled with built-in packages and supported by tools like the Visual Studio Code plugin, has helped Microsoft to bring developers into the design-first fold.

Creating a new API description language is not, however, a silver bullet for Microsoft. There is still a need to engage with existing API description languages, especially with OpenAPI.

Integrates with OpenAPI Toolchain

A key feature of TypeSpec is that it seeks to act as a layer below API description languages like OpenAPI, effectively acting as a definition language that can be serialized into other formats. Mandy confirmed that Microsoft is “Committed to interoperability with OpenAPI,” which is critical to many API providers and consumers.

TypeSpec does this in two ways. Firstly, it provides features that support the functionality in OpenAPI, with libraries to support keywords like oneOf (which is inherited from JSON Schema). This support allows API designers to use TypeSpec and still support the needs of API consumers and the tools they use that rely on such features.

This support is reinforced by the TypeSpec compiler, which allows API designers to emit OpenAPI through a configuration setting. This can be done by installing the @typespec/openapi3 package in their TypeSpec project and adding the following to their project settings:

emit:
  - "@typespec/openapi3"

An API designer can run the tsp compile command and generate an OpenAPI description that reflects their TypeSpec description. The approach — called Emitters — can be repeated for other supported description languages. For example, Protobuf is also supported out-of-the-box and TypeSpec can be extended to support other description languages.

The TypeSpec tools, therefore, support the goal of reducing complexity for API designers while still supporting the developer community with the API description languages they use. However, this is not the only means of reducing complexity for API designers, as existing API guidelines and patterns can be created as code.

API Guidelines as Reusable Code

Codifying API guidelines has been a theme in the API economy for several years, particularly with the increasing number of OpenAPI linters like Spectral and Optic that support checking for adherence to a style guide.

The TypeSpec approach is, however, somewhat different in that API guidelines start life as reusable objects in the form of TypeSpec libraries. For example, the snippet below, shown at the Summit talk, shows a model for supporting pagination:

model Page<T> {
  items: T[];

  pagination: {
    pageSize: int32;
    totalSize: int32;
  }
}

Once this model is shared using a library (by following the instructions provided in the TypeSpec documentation), it can easily be imported and reused:

import "OrgGuidelinesPagination";
using OrgGuidelinesPagination;

model DefaultPages extends Page {
  maxPagesPerQuery: int32;
}

Clearly, linters are still required in this context, as there is still a need to check that the pagination library has been implemented according to the style guide. However, it is also possible to implement this approach using any other programming language and API description language when it is done with the right levels of governance to ensure consistency.

In this case, TypeSpec provides consistency in applying a pagination pattern and supports the design-first approach, as API designers can just pull in the library of choice. However, it does not absolve the organization from implementing API governance.

Is TypeSpec for You?

TypeSpec was created by Microsoft to provide a consistent and productive means to follow a design-first API development methodology. As described in the Summit talk, the development teams believe these objectives and other benefits, like capturing additional metadata for client libraries, have been met, indicating very positive results. Developer experience is very important at organizations that care about productivity and the general well-being of their teams, and TypeSpec certainly seems to help in providing a very positive experience for those who use it.

Is TypeSpec right for you, though? We’ve shown in this post that the language is lightweight, flexible, and rich enough to support designing an API from scratch using a code-like language. This naturally lends itself to developers who are API designers and will find this a familiar environment. However, API designers come in all shapes and sizes, and some will prefer the familiarity of OpenAPI and its extensibility due to the way it leans into JSON Schema.

At the same time, another breed of API designer will care for neither because they use graphical tools to design their APIs. An API description language in this context is simply an affordance to their tooling and a way of distributing their API description in a known format. However you like to design your APIs, there’ll be a section of the API community that sees the “Specification Wars” being reignited with the advent of TypeSpec.

We’ll cover that and Gareth Jones’ talk on the merits of TypeSpec versus OpenAPI in an upcoming post.

The final point is that you have to be comfortable with the idea of designing first. Many developers in countless organizations prefer the code-first approach. They can create their APIs in a language they are comfortable with — the programming language they know and love — and use annotations and introspection to drive the creation of an API description in OpenAPI or another description language. In this context, TypeSpec won’t necessarily give them or their organization what they want or need.

This leads us to one significant conclusion. The preferences and proclivities of human beings generally drive the way API designers work. TypeSpec can help you be consistent and productive in designing your APIs, but only if you want it to.