Language Reference

Complete specification of the TypeMUX IDL syntax and semantics.

Table of Contents

File Structure

A TypeMUX schema file (.typemux) has the following structure:

[namespace IDENTIFIER]

[import "path/to/file.typemux"]*

[enum DEFINITION]*
[type DEFINITION]*
[union DEFINITION]*
[service DEFINITION]*

Elements can appear in any order, but best practice is:

  1. Namespace declaration (if used)
  2. Import statements
  3. Enums
  4. Types
  5. Unions
  6. Services

Primitive Types

TypeMUX supports these built-in types:

Type Description Size/Range
string UTF-8 text Variable length
int32 Signed 32-bit integer -2,147,483,648 to 2,147,483,647
int64 Signed 64-bit integer -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
float32 32-bit floating point IEEE 754 single precision
float64 64-bit floating point IEEE 754 double precision
bool Boolean value true or false
timestamp Date and time ISO 8601 / Unix timestamp
bytes Binary data Variable length

Type Definitions

Basic Syntax

type TYPENAME {
  fieldName: fieldType
  [fieldName: fieldType]*
}

Example

type User {
  id: string
  email: string
  age: int32
  active: bool
  createdAt: timestamp
}

Field Types

Fields can be:

Arrays

Array syntax uses brackets:

type Post {
  tags: []string
  comments: []Comment
}

Maps

Map syntax specifies key and value types:

type Configuration {
  settings: map<string, string>
  scores: map<string, int32>
}

Map constraints:

Nested map support:

TypeMUX fully supports nested map syntax:

type NestedMapExample {
  // Simple map
  settings: map<string, string>

  // Nested map (two levels)
  nested: map<string, map<string, int32>>

  // Triple nested map (three levels)
  deep: map<string, map<string, map<string, bool>>>
}

Each generator handles nested maps according to its schema capabilities:

Nested Types

Types can reference other types:

type Address {
  street: string
  city: string
  zipCode: string
}

type User {
  id: string
  name: string
  address: Address
}

Enum Definitions

Basic Syntax

enum ENUMNAME {
  VALUE1
  VALUE2
  [VALUE_N]*
}

Example

enum UserRole {
  ADMIN
  MODERATOR
  USER
  GUEST
}

Custom Values

Assign explicit numeric values:

enum Status {
  UNKNOWN = 0
  ACTIVE = 1
  INACTIVE = 2
  DELETED = 99
}

Rules:

Protobuf Enum Generation

Protobuf enums always include an UNSPECIFIED value at 0:

enum UserRole {
  USER_ROLE_UNSPECIFIED = 0;
  ADMIN = 1;
  MODERATOR = 2;
  USER = 3;
  GUEST = 4;
}

Union Definitions

Unions represent a value that can be one of several types (sum types, tagged unions, oneOf).

Syntax

union UNIONNAME {
  TypeName1
  TypeName2
  [TypeName_N]*
}

Example

type TextContent {
  text: string
}

type ImageContent {
  url: string
  width: int32
  height: int32
}

type VideoContent {
  url: string
  duration: int32
}

union Content {
  TextContent
  ImageContent
  VideoContent
}

Generated Code

GraphQL:

union Content @oneOf = TextContent | ImageContent | VideoContent

Protobuf:

message Content {
  oneof value {
    TextContent text_content = 1;
    ImageContent image_content = 2;
    VideoContent video_content = 3;
  }
}

OpenAPI:

Content:
  oneOf:
    - $ref: '#/components/schemas/TextContent'
    - $ref: '#/components/schemas/ImageContent'
    - $ref: '#/components/schemas/VideoContent'

Service Definitions

Services define RPC-style methods for APIs.

Syntax

service SERVICENAME {
  rpc MethodName(InputType) returns (OutputType)
    [@ANNOTATION]*
  [rpc ...]*
}

Example

service UserService {
  rpc GetUser(GetUserRequest) returns (User)
  rpc CreateUser(CreateUserRequest) returns (User)
  rpc UpdateUser(UpdateUserRequest) returns (User)
  rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse)
}

Method Naming Conventions

GraphQL operation types are inferred from method names:

Override with @graphql() annotation.

Field Attributes

Attributes modify field behavior and generation.

@required

Marks a field as non-nullable.

Syntax: @required

Example:

type User {
  id: string @required
  email: string @required
  nickname: string
}

Generated GraphQL:

type User {
  id: String!
  email: String!
  nickname: String
}

Generated OpenAPI:

User:
  type: object
  required:
    - id
    - email
  properties:
    id:
      type: string
    email:
      type: string
    nickname:
      type: string

@default

Sets a default value for a field.

Syntax: @default("value")

Example:

type User {
  id: string @required
  active: bool @default("true")
  role: UserRole @default("USER")
  loginCount: int32 @default("0")
}

Value format:

@exclude

Excludes a field from specific output formats.

Syntax: @exclude(format1,format2,...)

Formats: graphql, protobuf, openapi

Example:

type User {
  id: string @required
  email: string @required
  passwordHash: string @exclude(graphql,openapi)
  internalId: int64 @exclude(graphql)
}

The passwordHash appears only in Protobuf. The internalId appears in Protobuf and OpenAPI, but not GraphQL.

@only

Includes a field only in specific output formats.

Syntax: @only(format)

Example:

type User {
  id: string @required
  email: string @required
  __typename: string @only(graphql)
}

The __typename field appears only in GraphQL schema.

Custom Field Numbers

Assign explicit Protobuf field numbers using = N.

Syntax: fieldName: type = NUMBER

Example:

type User {
  id: string = 1
  email: string = 2
  name: string = 10
  age: int32 = 20
}

Generated Protobuf:

message User {
  string id = 1;
  string email = 2;
  string name = 10;
  int32 age = 20;
}

Rules:

Combining Attributes

Multiple attributes can be applied to a single field:

type Product {
  id: string @required = 1
  name: string @required @default("Unnamed") = 2
  price: float64 @required = 3
  internalNotes: string @exclude(graphql,openapi) = 100
}

Method Annotations

Annotations provide metadata for service methods.

@http

Specifies the HTTP method for REST endpoints.

Syntax: @http(METHOD)

Methods: GET, POST, PUT, PATCH, DELETE

Example:

service UserService {
  rpc GetUser(GetUserRequest) returns (User)
    @http(GET)

  rpc CreateUser(CreateUserRequest) returns (User)
    @http(POST)

  rpc UpdateUser(UpdateUserRequest) returns (User)
    @http(PUT)

  rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse)
    @http(DELETE)
}

@path

Defines the URL path template.

Syntax: @path("URL_PATH")

Path parameters: Use {paramName} for variables

Example:

service UserService {
  rpc GetUser(GetUserRequest) returns (User)
    @http(GET)
    @path("/api/v1/users/{id}")

  rpc ListUsers(ListUsersRequest) returns (ListUsersResponse)
    @http(GET)
    @path("/api/v1/users")

  rpc GetUserPosts(GetUserPostsRequest) returns (GetUserPostsResponse)
    @http(GET)
    @path("/api/v1/users/{userId}/posts")
}

Path parameters are extracted from request type fields.

@graphql

Specifies the GraphQL operation type.

Syntax: @graphql(OPERATION_TYPE)

Operation types: query, mutation, subscription

Example:

service UserService {
  rpc GetUser(GetUserRequest) returns (User)
    @graphql(query)

  rpc CreateUser(CreateUserRequest) returns (User)
    @graphql(mutation)

  rpc WatchUser(WatchUserRequest) returns (User)
    @graphql(subscription)
}

Default behavior:

@success

Lists HTTP success status codes.

Syntax: @success(CODE1,CODE2,...)

Example:

service UserService {
  rpc CreateUser(CreateUserRequest) returns (User)
    @http(POST)
    @path("/api/v1/users")
    @success(201)

  rpc UpdateUser(UpdateUserRequest) returns (User)
    @http(PUT)
    @path("/api/v1/users/{id}")
    @success(200,204)
}

Common codes:

@errors

Lists HTTP error status codes.

Syntax: @errors(CODE1,CODE2,...)

Example:

service UserService {
  rpc GetUser(GetUserRequest) returns (User)
    @http(GET)
    @path("/api/v1/users/{id}")
    @success(200)
    @errors(404,500)

  rpc CreateUser(CreateUserRequest) returns (User)
    @http(POST)
    @path("/api/v1/users")
    @success(201)
    @errors(400,409,500)
}

Common codes:

Complete Method Example

service ProductService {
  rpc GetProduct(GetProductRequest) returns (Product)
    @http(GET)
    @path("/api/v1/products/{id}")
    @graphql(query)
    @success(200)
    @errors(404,500)

  rpc CreateProduct(CreateProductRequest) returns (Product)
    @http(POST)
    @path("/api/v1/products")
    @graphql(mutation)
    @success(201)
    @errors(400,409,500)
}

Annotation Order

Annotations can be in any order:

// Both are valid
rpc GetUser(GetUserRequest) returns (User)
  @http(GET)
  @path("/users/{id}")
  @graphql(query)

rpc GetUser(GetUserRequest) returns (User)
  @graphql(query)
  @path("/users/{id}")
  @http(GET)

Best practice: Use consistent ordering (http, path, graphql, success, errors).

Documentation Comments

Add documentation using triple-slash comments (///).

Syntax

/// Documentation comment
/// Can span multiple lines
type TypeName {
  /// Field documentation
  fieldName: fieldType
}

Example

/// User account with authentication details
///
/// Users can have different roles and permissions
/// based on their account type.
type User {
  /// Unique user identifier
  ///
  /// This ID is immutable once created.
  id: string @required

  /// User's email address for login
  email: string @required

  /// Display name shown to other users
  username: string @required

  /// Account role determining permissions
  role: UserRole @required
}

/// User role enumeration
///
/// Roles are hierarchical: ADMIN > MODERATOR > USER > GUEST
enum UserRole {
  /// Full system access
  ADMIN

  /// Can moderate content
  MODERATOR

  /// Regular user
  USER

  /// Limited read-only access
  GUEST
}

/// Service for managing user accounts
///
/// Provides CRUD operations for user management.
service UserService {
  /// Retrieves a user by their unique ID
  ///
  /// Returns 404 if user is not found.
  rpc GetUser(GetUserRequest) returns (User)
    @http(GET)
    @path("/api/v1/users/{id}")
    @graphql(query)
}

Documentation in Generated Code

GraphQL:

"""
User account with authentication details

Users can have different roles and permissions
based on their account type.
"""
type User {
  """
  Unique user identifier

  This ID is immutable once created.
  """
  id: String!
}

Protobuf:

// User account with authentication details
//
// Users can have different roles and permissions
// based on their account type.
message User {
  // Unique user identifier
  //
  // This ID is immutable once created.
  string id = 1;
}

OpenAPI:

User:
  type: object
  description: |
    User account with authentication details

    Users can have different roles and permissions
    based on their account type.
  properties:
    id:
      type: string
      description: |
        Unique user identifier

        This ID is immutable once created.

Namespaces

Namespaces organize types and prevent naming conflicts.

Syntax

namespace NAMESPACE_IDENTIFIER

type TypeName {
  // ...
}

Namespace Format

Use reverse domain notation:

namespace com.example.api
namespace org.mycompany.users
namespace io.github.username.project

Example

namespace com.example.ecommerce

type Product {
  id: string @required
  name: string @required
}

type Order {
  id: string @required
  product: Product @required
}

Multiple Namespaces

Different files can have different namespaces:

com/example/users.typemux:

namespace com.example.users

type User {
  id: string @required
  email: string @required
}

com/example/orders.typemux:

namespace com.example.orders

import "com/example/users.typemux"

type Order {
  id: string @required
  userId: string @required
}

Namespace Effects

GraphQL:

Protobuf:

OpenAPI:

Imports

Import types from other files.

Syntax

import "relative/path/to/file.typemux"

Example

types.typemux:

type User {
  id: string @required
  email: string @required
}

type Product {
  id: string @required
  name: string @required
}

services.typemux:

import "types.typemux"

type GetUserRequest {
  id: string @required
}

service UserService {
  rpc GetUser(GetUserRequest) returns (User)
}

Import Resolution

Circular Imports

TypeMUX detects circular imports and reports an error:

a.typemux:

import "b.typemux"

type A {
  b: B
}

b.typemux:

import "a.typemux"  // Error: circular import

type B {
  a: A
}

Solution: Extract common types to a third file.

Type Mappings

How TypeMUX types map to output formats.

Complete Mapping Table

TypeMUX GraphQL Protobuf OpenAPI
string String string type: string
int32 Int int32 type: integer, format: int32
int64 Int int64 type: integer, format: int64
float32 Float float type: number, format: float
float64 Float double type: number, format: double
bool Boolean bool type: boolean
timestamp String google.protobuf.Timestamp type: string, format: date-time
bytes String bytes type: string, format: byte
[]T [T] repeated T type: array, items: {T}
map<K,V> [KeyValueEntry!] (typed) map<K, V> type: object, additionalProperties: {V}

Nullability

TypeMUX:

type User {
  id: string @required
  nickname: string
}

GraphQL:

type User {
  id: String!      # Non-null
  nickname: String # Nullable
}

OpenAPI:

User:
  required:
    - id
  properties:
    id:
      type: string
    nickname:
      type: string

Protobuf:

// All fields are optional in proto3
message User {
  string id = 1;
  string nickname = 2;
}

Arrays

TypeMUX:

type Post {
  tags: []string
}

GraphQL:

type Post {
  tags: [String]
}

Protobuf:

message Post {
  repeated string tags = 1;
}

OpenAPI:

Post:
  properties:
    tags:
      type: array
      items:
        type: string

Maps

TypeMUX:

type Config {
  settings: map<string, string>
  scores: map<string, int64>
}

GraphQL: Maps are converted to strongly-typed KeyValue entry lists:

"StringStringEntry represents a key-value pair for map<string, string>"
type StringStringEntry {
  key: String!
  value: String!
}

"StringStringEntryInput represents a key-value pair for map<string, string>"
input StringStringEntryInput {
  key: String!
  value: String!
}

"StringIntEntry represents a key-value pair for map<string, int64>"
type StringIntEntry {
  key: String!
  value: Int!
}

"StringIntEntryInput represents a key-value pair for map<string, int64>"
input StringIntEntryInput {
  key: String!
  value: Int!
}

type Config {
  settings: [StringStringEntry!]
  scores: [StringIntEntry!]
}

Protobuf: Uses native map syntax:

message Config {
  map<string, string> settings = 1;
  map<string, int64> scores = 2;
}

OpenAPI: Uses additionalProperties to specify value types:

Config:
  type: object
  properties:
    settings:
      type: object
      description: Map of string to string
      additionalProperties:
        type: string
    scores:
      type: object
      description: Map of string to int64
      additionalProperties:
        type: integer
        format: int64

Maps with custom types:

When using custom types as map values, all formats properly reference the type:

type User {
  name: string
  age: int32
}

type Department {
  users: map<string, User>
}

Nested maps:

TypeMUX supports nested maps, with each generator handling them according to its schema capabilities:

type NestedMapExample {
  // Nested map (two levels)
  nested: map<string, map<string, int32>>

  // Triple nested map (three levels)
  deep: map<string, map<string, map<string, bool>>>
}

GraphQL: Auto-generates wrapper types for nested map levels:

"MapWrapper0 is an auto-generated wrapper for nested map"
type MapWrapper0 {
  value: [StringIntEntry!]!
}

"StringMapWrapper0Entry represents a key-value pair for map<string, MapWrapper0>"
type StringMapWrapper0Entry {
  key: String!
  value: MapWrapper0!
}

type NestedMapExample {
  nested: [StringMapWrapper0Entry!]
  deep: [StringMapWrapper1Entry!]
}

Protobuf: Uses native nested map syntax:

message NestedMapExample {
  map<string, map<string, int32>> nested = 1;
  map<string, map<string, map<string, bool>>> deep = 2;
}

OpenAPI: Uses nested additionalProperties structures:

NestedMapExample:
  type: object
  properties:
    nested:
      type: object
      description: Map of string to Map of string to int32
      additionalProperties:
        type: object
        additionalProperties:
          type: integer
          format: int32
    deep:
      type: object
      description: Map of string to Map of string to Map of string to bool
      additionalProperties:
        type: object
        additionalProperties:
          type: object
          additionalProperties:
            type: boolean

Lexical Elements

Identifiers

Valid:

Invalid:

Keywords

Reserved keywords:

Comments

Documentation comments:

/// This is documentation
/// that appears in generated code

Regular comments:

// This is a regular comment
// Not included in generated code

String Literals

String literals use double quotes:

@default("hello world")
@path("/api/v1/users/{id}")

Escape sequences:

Best Practices

Naming Conventions

Types: PascalCase

type UserAccount { }
type OrderHistory { }

Fields: camelCase

type User {
  firstName: string
  lastName: string
  emailAddress: string
}

Enums: UPPER_SNAKE_CASE

enum UserRole {
  SUPER_ADMIN
  REGULAR_USER
  GUEST_USER
}

Services: PascalCase with “Service” suffix

service UserService { }
service OrderService { }

Methods: PascalCase with verb prefix

rpc GetUser(...)
rpc CreateOrder(...)
rpc UpdateProfile(...)
rpc DeleteAccount(...)

File Organization

Small projects:

schema.typemux

Medium projects:

types.typemux
enums.typemux
services.typemux

Large projects:

types/
  user.typemux
  order.typemux
  product.typemux
services/
  user_service.typemux
  order_service.typemux
  product_service.typemux

Documentation

Field Numbering

Annotations