Skip to content

TypeSpec Contracts

This guide covers creating OpenAPI contracts using TypeSpec. It contains the necessary files and configurations to define and generate API specifications.

Key Features

  • TypeSpec Integration: Leverages TypeSpec libraries for defining APIs, models, and endpoints
  • Versioning Support: Includes versioning for APIs using the @versioned decorator
  • Mocking and Authorization: Provides options for mocking endpoints and defining authorization scopes and roles
  • OpenAPI File Generation: Automates the creation of OpenAPI files from TypeSpec definitions

💡 This process should be performed using Visual Studio Code, as it has the best tooling for working with TypeSpec.

Folder Structure

  • TypeSpec Files: Contains TypeSpec code to define API models, endpoints, and configurations
  • Dependencies: Includes references to TypeSpec libraries and a custom SAIF platform library

Usage Instructions

  1. Open the repo/src/ApplicationName1.TypeSpec folder in Visual Studio Code
  2. Define your API using TypeSpec syntax:
  3. Import required libraries
  4. Define models, endpoints, and configurations
  5. Customize mocking, authorization, and versioning as needed
  6. Generate OpenAPI File:
  7. Open the folder in the integrated terminal
  8. Install required npm packages:
    vsts-npm-auth -config .npmrc
    npm install
    
  9. Compile the TypeSpec code to generate the OpenAPI file:
    npm run build
    
  10. The generated OpenAPI file will be located in /infra/api/openapi

Key TypeSpec Concepts Used

Models

Define the structure of API resources.

📖 Model Creation

@added(Versions.v1)
@resource("people")
model Person {
    @key
    id: string;
    firstName: string;
    lastName: string;
    age: int32;
}

Mocking

Configure mocking behavior for endpoints using @extension("x-mocking").

@extension("x-mocking", "true")

Authorization

This defines the default authentication scopes and roles for all endpoints in the namespace. One declaration covers both identity providers — the generated APIM policies check the correct claim per provider:

@useAuth(Scopes<["Client.Read"]> | Roles<["App.Read"]>)
  • Scopes<[...]> checks Client.* scopes (the scp claim) — what calling applications request
  • Roles<[...]> checks App.* roles (the roles/user-groups claims) — what is granted to users or applications

Use names that follow the permission naming convention and define them in both providers — see App Permissions. Never reference the platform-managed delegation scopes (user_impersonation, user-groups) in @useAuth; the platform handles those automatically.

Endpoints

This will create routes based on your model.

The @autoRoute decorator ensures that the operations list, get, post, put and delete are automatically routed based on their names and the HTTP methods they represent. This means you don't have to manually define the routes for these operations, making the code more concise and easier to maintain.

Methods

Method Description Route Example
list Endpoint to get all records GET /people
get Endpoint to get by @key field GET /people/{id}
post Create a record (body excludes @key) POST /people
put Replace or create a record (@key in route, body excludes) PUT /people/{id}
patch Update a record (@key in route, body excludes) PATCH /people/{id}
delete Delete a record (@key in route) DELETE /people/{id}

Endpoint Mocking

This will overwrite the default mocking specified above:

  • true = Your request will be routed to the mocking URL
  • false = Your request will be routed to the app backing your endpoint

Overriding Authorization

You can override the default authorization on individual endpoints. The scopes and roles must match those defined in your identity provider configuration (see Authorization above).

@added(Versions.v1)
@resource("people")
model Person {
    @key
    id: string;
    firstName: string;
    lastName: string;
    age: int32;
}

@added(Versions.v1)
@resource("orders")
model Order {
    @key
    id: string;
    customerId: string;
    orderDate: utcDateTime;
    totalAmount: decimal;
}

@autoRoute
@added(Versions.v1)
interface People {
    get is ResourceRead<Person>;
    all is ResourceList<Person>;

    @useAuth(Scopes<["Client.Write"]> | Roles<["App.Write"]>)
    post is ResourceCreate<Person>;

    @useAuth(Scopes<["Client.Write"]> | Roles<["App.Write"]>)
    put is ResourceCreateOrReplace<Person>;

    @useAuth(Scopes<["Client.Delete"]> | Roles<["App.Admin"]>)
    delete is ResourceDelete<Person>;
}

@autoRoute
@added(Versions.v1)
interface Orders {
    @useAuth(Scopes<["Client.Write"]> | Roles<["App.Write"]>)
    post is ResourceCreate<Order>;
}