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.

Microsoft Entra ID (Internal/Corporate Users)

@useAuth(Scopes<["user_impersonation"]> | Roles<["read"]>)

For internal corporate authentication, scopes are configured in Microsoft Entra ID app registrations.

  • Configuration: /infra/auth/corp/

⚠️ Important: The user_impersonation scope is a delegated permission from Microsoft Entra ID that allows the application to access the API on behalf of the signed-in user. This scope must be:

  1. Exposed in your API's app registration under "Expose an API" → "Add a scope" with the name user_impersonation
  2. Granted to client applications that need to call your API

When a client application requests an access token with this scope, the token will contain the user's identity and permissions, allowing the API to perform actions as that user. This is the standard pattern for Experience APIs that need to act on behalf of users.

Okta (External Users)

@useAuth(Scopes<["read"]> | Roles<["read"]>)

For external user authentication via Okta, scopes and roles are defined in YAML configuration files:

  • Scopes: /infra/auth/ext/okta-client/scopes.yml
  • Roles: /infra/auth/ext/okta-client/user_groups.yml

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).

Here is an example of models and their associated endpoints using Okta (external) authentication:

@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<["write"]> | Roles<["write"]>)
    post is ResourceCreate<Person>;

    @useAuth(Scopes<["write"]> | Roles<["write"]>)
    put is ResourceCreateOrReplace<Person>;

    @useAuth(Scopes<["delete"]> | Roles<["admin"]>)
    delete is ResourceDelete<Person>;
}

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