TypeSpec
Describe APIs
Describe your data up front and generate schemas, API specifications, client / server code,
docs, and more.
import "@typespec/http";
using TypeSpec.Http;
model Store { name: string; address: Address;}
model Address { street: string; city: string;}
@route("/stores")interface Stores { list(@query filter: string): Store[]; read(@path id: Store): Store;}
openapi: 3.0.0info: title: (title) version: 0.0.0tags: []paths: /stores: get: operationId: Stores_list parameters: - name: filter in: query required: true schema: type: string responses: '200': description: The request has succeeded. content: application/json: schema: type: array items: $ref: '#/components/schemas/Store' /stores/{id}: get: operationId: Stores_read parameters: - name: id in: path required: true schema: $ref: '#/components/schemas/Store' responses: '200': description: The request has succeeded. content: application/json: schema: $ref: '#/components/schemas/Store'components: schemas: Address: type: object required: - street - city properties: street: type: string city: type: string Store: type: object required: - name - address properties: name: type: string address: $ref: '#/components/schemas/Address'
import "@typespec/json-schema";
using TypeSpec.JsonSchema;
@jsonSchemanamespace Schemas;
model Person { name: string; address: Address; @uniqueItems nickNames?: string[]; cars?: Car[];}
model Address { street: string; city: string; country: string;}
model Car { kind: "ev" | "ice"; brand: string; @minValue(1900) year: int32;}
$schema: https://json-schema.org/draft/2020-12/schema$id: schema.yaml$defs: Address: $schema: https://json-schema.org/draft/2020-12/schema $id: Address type: object properties: street: type: string city: type: string country: type: string required: - street - city - country Car: $schema: https://json-schema.org/draft/2020-12/schema $id: Car type: object properties: kind: anyOf: - type: string const: ev - type: string const: ice brand: type: string year: type: integer minimum: 1900 maximum: 2147483647 required: - kind - brand - year Person: $schema: https://json-schema.org/draft/2020-12/schema $id: Person type: object properties: name: type: string address: $ref: Address nickNames: type: array items: type: string uniqueItems: true cars: type: array items: $ref: Car required: - name - address
import "@typespec/protobuf";
using TypeSpec.Protobuf;
@package({ name: "addressbook",})namespace AddressBook;
enum PhoneType { MOBILE: 0, HOME: 1, WORK: 2,}
model PhoneNumber { @field(1) number: string; @field(2) type: PhoneType;}
model Person { @field(1) name: string; @field(2) id: int32; @field(3) email: string; @field(4) phones: PhoneNumber[]; @field(5) last_updated: WellKnown.Timestamp;}
// Generated by Microsoft TypeSpec
syntax = "proto3";
package addressbook;
import "google/protobuf/timestamp.proto";
enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2;}
message PhoneNumber { string number = 1; PhoneType type = 2;}
message Person { string name = 1; int32 id = 2; string email = 3; repeated PhoneNumber phones = 4; google.protobuf.Timestamp last_updated = 5;}
Why TypeSpec
API-First for developers
With TypeSpec, remove the handwritten files that slow you down, and generate
standards-compliant API schemas in seconds.
![](/img/fluent/book-pencil-l-standard-128x128.png)
![](/img/fluent/book-pencil-d-standard-128x128.png)
Lightweight language for defining APIs
Inspired by TypeScript, TypeSpec is a minimal language that helps developers describe API shapes in a familiar way.
Learn more →
![](/img/fluent/document-add-l-standard-128x128.png)
![](/img/fluent/document-add-d-standard-128x128.png)
Easy integration with your toolchain
Write TypeSpec, emit to various formats and integrate with their ecosystems.
![](/img/fluent/tasks-l-standard-128x128.png)
![](/img/fluent/tasks-d-standard-128x128.png)
Multi-protocol support
TypeSpec's standard library includes support for OpenAPI 3.0, JSON Schema 2020-12 and Protobuf.
Learn more →
~ /my-project tsp init? Select a templateEmpty project> REST API
![](/img/illustrations/overview-ide.dark.png)
![](/img/illustrations/overview-ide.light.png)
Productivity
Streamline your OpenAPI workflow
Benefit from a huge ecosystem of OpenAPI tools for configuring API gateways, generating code, and validating your data.
![](/img/fluent/design-l-standard-128x128.png)
![](/img/fluent/design-d-standard-128x128.png)
Generate OpenAPI from TypeSpec
Learn more →
import "@typespec/http";
using TypeSpec.Http;
model Pet { name: string; age: int32;}
model Store { name: string; address: Address;}
model Address { street: string; city: string;}
@route("/pets")interface Pets { list(@query filter: string): Pet[]; create(@body pet: Pet): Pet; read(@path id: string): Pet;}
@route("/stores")interface Stores { list(@query filter: string): Store[]; read(@path id: string): Store;}
openapi: 3.0.0info: title: (title) version: 0.0.0tags: []paths: /pets: get: operationId: Pets_list parameters: - name: filter in: query required: true schema: type: string responses: '200': description: The request has succeeded. content: application/json: schema: type: array items: $ref: '#/components/schemas/Pet' post: operationId: Pets_create parameters: [] responses: '200': description: The request has succeeded. content: application/json: schema: $ref: '#/components/schemas/Pet' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Pet' /pets/{id}: get: operationId: Pets_read parameters: - name: id in: path required: true schema: type: string responses: '200': description: The request has succeeded. content: application/json: schema: $ref: '#/components/schemas/Pet' /stores: get: operationId: Stores_list parameters: - name: filter in: query required: true schema: type: string responses: '200': description: The request has succeeded. content: application/json: schema: type: array items: $ref: '#/components/schemas/Store' /stores/{id}: get: operationId: Stores_read parameters: - name: id in: path required: true schema: type: string responses: '200': description: The request has succeeded. content: application/json: schema: $ref: '#/components/schemas/Store'components: schemas: Address: type: object required: - street - city properties: street: type: string city: type: string Pet: type: object required: - name - age properties: name: type: string age: type: integer format: int32 Store: type: object required: - name - address properties: name: type: string address: $ref: '#/components/schemas/Address'
Ecosystem
Ensure data consistency
Define common models to use across your APIs, use the JSON schema emitter to get the JSON schema for your types and use them to validate your data.
![](/img/fluent/people-shield-l-standard-128x128.png)
![](/img/fluent/people-shield-d-standard-128x128.png)
JSON schema emitter reference
Learn more →
import "./common.tsp";
namespace MyOrg.Accounts;
using MyOrg.Types;
model Account { id: id; firstName: string; lastName: string; createdAt: utcDateTime;
// Use imported type by name only when using `using` ssn: ssn;
// Or use the fully qualified name email: MyOrg.Types.email;
balance: Amount;}
model Amount { value: decimal128; currency: Currency;}
// Create your own error types by extending the Error typemodel AccountError is Error<"duplicate-account" | "invalid-account">;
op createAccount(account: Account): Account;
op charge(accountId: id, amount: Amount): void | AccountError;
namespace MyOrg.Types;
@format("uuid")scalar uuid extends string;
// Defined a standard id type that all models can usescalar id extends uuid;
@pattern(".+\\@.+\\..+")scalar email extends string;
@pattern("^\\d{3}-\\d{2}-\\d{4}$")scalar ssn extends string;
/** * Standard error response */model Error<T extends string> { code: T; message: string; details?: Record<string>; timestamp: utcDateTime;}
enum Currency { USD, EUR, GBP, CAD, JPY,}
Tooling
Full language support in VS Code and Visual Studio
TypeSpec provides built-in support for many common editor features such as syntax highlighting, code completion, and more.
![](/img/fluent/data-trending-l-standard-128x128.png)
![](/img/fluent/data-trending-d-standard-128x128.png)
Check out our available tooling
Learn more →
![](/img/illustrations/ide-hero.dark.png)
![](/img/illustrations/ide-hero.light.png)
Extensibility
Generate assets in many formats
TypeSpec is built around extensibility - you can write your own emitter or add custom metadata using a new decorator.
![](/img/fluent/data-trending-l-standard-128x128.png)
![](/img/fluent/data-trending-d-standard-128x128.png)
Getting started with writing a library
Learn more →
extern dec group(target: TypeSpec.Reflection.Model, name: valueof string);
import { DecoratorContext, EmitContext, Model, resolvePath } from "@typespec/compiler";
export async function $onEmit(context: EmitContext) { const outputDir = resolvePath(context.emitterOutputDir, "hello.txt"); await context.program.host.writeFile(outputDir, "hello world!");}
const groupKey = Symbol.for("my-library/group");export function $group(context: DecoratorContext, target: Model, value: string) { context.program.stateMap(groupKey).set(target, value);}
Start your TypeSpec journey
Install the TypeSpec CLI or check out the playground to get started.