### Interact with Project Models Source: https://github.com/mittwald/api-client-js/blob/master/packages/models/README.md Examples demonstrating how to get, create, update, and query project models, including using references and accessing server details. ```typescript // Get a detailed project const detailedProject = await Project.get("p-vka9t3"); // Create a project reference const projectRef = Project.ofId("p-vka9t3"); // Get the detailed project from the reference const anotherDetailedProject = await projectRef.getDetailed(); // Update project description await detailedProject.updateDescription("My new description!"); // This method just needs the ID and a description and // thus is also available on the reference await projectRef.updateDescription("My new description!"); // Accessing the projects server reference const server = project.server; // List all projects of this server const serversProjects = await server.projects.execute(); // List all projects const allProjects = await Project.query().execute(); // Iterate over project List Models for (const project of serversProjects) { await project.leave(); } ``` -------------------------------- ### Install Dependencies and Compile Project Source: https://github.com/mittwald/api-client-js/blob/master/CONTRIBUTING.md Run these commands to install project dependencies and compile the project locally. ```shell $ yarn install $ yarn compile ``` -------------------------------- ### Set Path Parameters for Project Get Source: https://github.com/mittwald/api-client-js/blob/master/packages/mittwald/README.md Example of setting the 'projectId' path parameter when fetching a specific project. ```javascript // Setting the projectId path parameters const project = await mittwaldApi.project.getProject({ projectId: "p-xxxxx", }); ``` -------------------------------- ### Install API Client with Yarn Source: https://github.com/mittwald/api-client-js/blob/master/packages/mittwald/README.md Install the @mittwald/api-client package using Yarn. ```shell yarn add @mittwald/api-client ``` -------------------------------- ### Install React Use Promise Package Source: https://github.com/mittwald/api-client-js/blob/master/packages/mittwald/README.md Install the additional @mittwald/react-use-promise package required for the React client. ```shell yarn add @mittwald/react-use-promise ``` -------------------------------- ### Setup API Client with API Token Source: https://github.com/mittwald/api-client-js/blob/master/packages/models/README.md Initialize the API client using an API token from environment variables. ```typescript import { api } from "@mittwald/api-models"; api.setupWithApiToken(process.env.MW_API_TOKEN); ``` -------------------------------- ### Example of Server Model with Projects Query Source: https://github.com/mittwald/api-client-js/blob/master/packages/models/README.md Demonstrates how a Server model can expose a ProjectsListQuery property, allowing for efficient querying of associated projects. ```typescript class Server { public readonly projects: ProjectsListQuery; public constructor(id: string) { this.projects = new ProjectListQuery({ server: this, }); } } ``` -------------------------------- ### Interact with API Domains and Operations Source: https://context7.com/mittwald/api-client-js/llms.txt Demonstrates making API calls to different domains (e.g., project, app, database) using typed request objects. Supports path parameters, query parameters, and data payloads. Includes examples for creating, getting, and listing resources, with status assertions. ```typescript import { MittwaldAPIV2Client, assertStatus, assertOneOfStatus } from "@mittwald/api-client"; const client = MittwaldAPIV2Client.newWithToken(process.env.MITTWALD_API_TOKEN!); // Create a MySQL database const createResp = await client.database.createMysqlDatabase({ pathParameters: { projectId: "abc123" }, data: { database: { name: "my_db", characterSettings: { characterSet: "utf8mb4", collate: "utf8mb4_unicode_ci" } }, user: { name: "my_user", password: "Str0ng!Pass", accessLevel: "full", externalAccess: false }, }, }); assertStatus(createResp, 201); const dbId = createResp.data.id; // Get the database, tolerating both found and not-found const getResp = await client.database.getMysqlDatabase({ pathParameters: { mysqlDatabaseId: dbId }, }); assertOneOfStatus(getResp, [200, 404]); if (getResp.status === 200) { console.log("DB name:", getResp.data.name); } else { console.log("Database not found"); } // List all MySQL databases for a project with pagination const listResp = await client.database.listMysqlDatabases({ pathParameters: { projectId: "abc123" }, queryParameters: { limit: 25, skip: 0 }, }); assertStatus(listResp, 200); ``` -------------------------------- ### Install API Models Package Source: https://github.com/mittwald/api-client-js/blob/master/packages/models/README.md Install the @mittwald/api-models package using yarn. ```shell yarn add @mittwald/api-models ``` -------------------------------- ### Migrate Project Get Request from V2 to V3 Source: https://github.com/mittwald/api-client-js/blob/master/packages/mittwald/README.md Compares the V2 and V3 syntax for making a project get request, highlighting the change in how path parameters are handled. ```javascript // V2 mittwaldApi.project.getProject({ pathParameters: { projectId: "p-xxxxx", }, }); // V3 mittwaldApi.project.getProject({ projectId: "p-xxxxx", }); ``` -------------------------------- ### Initialize API Client with Token Source: https://github.com/mittwald/api-client-js/blob/master/packages/mittwald/README.md Example of creating a MittwaldAPIV2Client instance using an API access token. ```typescript import { MittwaldAPIV2Client } from "@mittwald/api-client"; const mittwaldApi = MittwaldAPIClient.newWithToken("your-access-token"); const projects = await mittwaldApi.project.listProjects(); ``` -------------------------------- ### Usage of Async Methods in React Source: https://github.com/mittwald/api-client-js/blob/master/packages/models/README.md Examples showing how to use asynchronous methods with the '.use()' property for React components, leveraging AsyncResources. ```typescript const detailedProject = Project.get.use("p-vka9t3"); // Create a project reference const projectRef = Project.ofId("p-vka9t3"); // Get the detailed project from the reference const anotherDetailedProject = projectRef.getDetailed.use(); // Accessing the projects server reference const server = project.server; // List all projects of this server const serversProjects = server.projects.execute.use(); // List all projects const allProjects = Project.query().execute.use(); ``` -------------------------------- ### Enable Event Consistency Handling Source: https://github.com/mittwald/api-client-js/blob/master/packages/commons/README.md Use `withEventConsistencyHandling` to automatically handle the `etag` response header and set it as the `if-event-reached` request header for GET requests, opting into event consistency. ```typescript const client = new APIClient({ baseURL }); const authenticatedClient = withEventConsistencyHandling(client); ``` -------------------------------- ### withEventConsistencyHandling Source: https://github.com/mittwald/api-client-js/blob/master/packages/commons/README.md An interceptor that opts into event consistency handling by automatically managing the `ETag` and `if-event-reached` headers for GET requests. ```APIDOC ## withEventConsistencyHandling(client) ### Description Enables event consistency handling. For GET requests, this interceptor automatically sets the `ETag` response header as the `if-event-reached` request header. ### Parameters - **client**: An instance of `APIClient`. ### Returns An `APIClient` instance configured with the event consistency handling interceptor. ### Example ```ts const client = new APIClient({ baseURL }); const authenticatedClient = withEventConsistencyHandling(client); ``` ``` -------------------------------- ### withEventConsistencyHandling(client) Source: https://context7.com/mittwald/api-client-js/llms.txt Attaches response and request interceptors to a client instance to handle event consistency. It captures `etag` headers from mutating responses and forwards them as `if-event-reached` on subsequent GET requests. ```APIDOC ## `withEventConsistencyHandling(client)` — Attach consistency interceptor Attaches two interceptors: a response interceptor that captures `etag` headers from mutating responses, and a request interceptor that forwards the captured value as `if-event-reached` on GET requests. Accepts both client instances and Axios instances. ```typescript import { withEventConsistencyHandling, withAccessToken } from "@mittwald/api-client-commons"; import { MittwaldAPIV2Client } from "@mittwald/api-client"; const client = withEventConsistencyHandling( withAccessToken( MittwaldAPIV2Client.newUnauthenticated(), process.env.MITTWALD_API_TOKEN, ), ); // Now any mutation's etag is tracked and forwarded to subsequent GETs await client.mail.createMailAddress({ pathParameters: { projectId: "abc123" }, data: { address: "info@example.com", forwardAddresses: [] }, }); // This read will automatically include `if-event-reached` header const mailResp = await client.mail.listMailAddresses({ pathParameters: { projectId: "abc123" }, }); assertStatus(mailResp, 200); ``` ``` -------------------------------- ### client.withEventConsistencyHandling() Source: https://context7.com/mittwald/api-client-js/llms.txt Activates the event-consistency interceptor that tracks mutating-request `etag` response headers and automatically forwards the latest value as `if-event-reached` on subsequent GET requests, ensuring reads reflect the most recent write. ```APIDOC ## client.withEventConsistencyHandling() ### Description Activates the event-consistency interceptor that tracks mutating-request `etag` response headers and automatically forwards the latest value as `if-event-reached` on subsequent GET requests, ensuring reads reflect the most recent write. ### Usage ```typescript import { MittwaldAPIV2Client, assertStatus } from "@mittwald/api-client"; const client = MittwaldAPIV2Client.newWithToken(process.env.MITTWALD_API_TOKEN!) .withEventConsistencyHandling(); // After a mutation, subsequent reads will include the event ID automatically const patchResp = await client.project.updateProjectDescription({ pathParameters: { projectId: "abc123" }, data: { description: "Updated description" }, }); assertStatus(patchResp, 200); // This GET will carry if-event-reached from the patch's etag const getResp = await client.project.getProject({ pathParameters: { projectId: "abc123" }, }); assertStatus(getResp, 200); console.log("Description is now:", getResp.data.description); ``` ``` -------------------------------- ### Enable Eventual Consistency Headers with client.withEventConsistencyHandling() Source: https://context7.com/mittwald/api-client-js/llms.txt Activates the event-consistency interceptor. It tracks mutating-request `etag` response headers and automatically forwards the latest value as `if-event-reached` on subsequent GET requests, ensuring reads reflect the most recent write. ```typescript import { MittwaldAPIV2Client, assertStatus } from "@mittwald/api-client"; const client = MittwaldAPIV2Client.newWithToken(process.env.MITTWALD_API_TOKEN!) .withEventConsistencyHandling(); // After a mutation, subsequent reads will include the event ID automatically const patchResp = await client.project.updateProjectDescription({ pathParameters: { projectId: "abc123" }, data: { description: "Updated description" }, }); assertStatus(patchResp, 200); // This GET will carry if-event-reached from the patch's etag const getResp = await client.project.getProject({ pathParameters: { projectId: "abc123" }, }); assertStatus(getResp, 200); console.log("Description is now:", getResp.data.description); ``` -------------------------------- ### Generate TypeScript API Client from OpenAPI Spec (CLI) Source: https://context7.com/mittwald/api-client-js/llms.txt The primary CLI command to generate typed TypeScript files from an OpenAPI spec. Install the generator globally or as a dev dependency, then use 'acg generate' with input and output paths. ```shell # Install the generator npm install -D @mittwald/api-code-generator # Validate the spec first acg validate spec/openapi.json # Generate the client acg generate \ --name MyAPIV2 \ --optionalHeader x-access-token \ spec/openapi.json \ src/generated # Generated output: # src/generated/descriptors.ts – operation metadata # src/generated/types.ts – request/response TypeScript types # src/generated/client.ts – Axios-based typed client class # src/generated/client-react.ts – React suspense resource wrappers ``` -------------------------------- ### Attach Event Consistency Interceptor to API Client Source: https://context7.com/mittwald/api-client-js/llms.txt Attaches response and request interceptors to track etags from mutating responses and forward them as 'if-event-reached' on subsequent GET requests. Accepts both client and Axios instances. ```typescript import { withEventConsistencyHandling, withAccessToken } from "@mittwald/api-client-commons"; import { MittwaldAPIV2Client } from "@mittwald/api-client"; const client = withEventConsistencyHandling( withAccessToken( MittwaldAPIV2Client.newUnauthenticated(), process.env.MITTWALD_API_TOKEN, ), ); // Now any mutation's etag is tracked and forwarded to subsequent GETs await client.mail.createMailAddress({ pathParameters: { projectId: "abc123" }, data: { address: "info@example.com", forwardAddresses: [] }, }); // This read will automatically include `if-event-reached` header const mailResp = await client.mail.listMailAddresses({ pathParameters: { projectId: "abc123" }, }); assertStatus(mailResp, 200); ``` -------------------------------- ### api.setupWithApiToken(token) Source: https://context7.com/mittwald/api-client-js/llms.txt Initializes the domain model layer by wiring high-level domain models to the live API. This method must be called once at application startup before using any model class. ```APIDOC ## `api.setupWithApiToken(token)` — Initialize domain model layer Wires the high-level domain models to the live API by creating an authenticated client and injecting all behavior implementations. Must be called once at app startup before using any model class. ```typescript import { api, Project, Customer, Server } from "@mittwald/api-models"; // Initialize once at startup api.setupWithApiToken(process.env.MITTWALD_API_TOKEN!); // Now all model classes work against the live API const projects = await Project.list(); console.log("Projects:", projects.map((p) => p.data.description)); const customer = await Customer.get("cst-abc123"); console.log("Customer:", customer.data.name); // Access nested relations const customerProjects = await customer.projects.execute(); console.log("Customer's projects:", customerProjects.items.map((p) => p.data.description)); ``` ``` -------------------------------- ### Initialize and Use React API Client Source: https://github.com/mittwald/api-client-js/blob/master/packages/mittwald/README.md Demonstrates how to initialize the React API client from a base client and use it to fetch and display a list of projects. Handles potential API errors by throwing an ApiClientError. ```javascript jsx import { MittwaldAPIV2Client } from "@mittwald/api-client"; import { MittwaldAPIV2ClientReact } from "@mittwald/api-client/react"; const api = MittwaldAPIV2Client.newUnauthenticated(); const apiReact = MittwaldAPIV2ClientReact.fromBaseClient(api); const ProjectsList = () => { // apiReact.project.listProjects() returns an AsyncResource that can be "used" const projects = apiReact.project.listProjects().use({ autoRefresh: { seconds: 30, }, }); return ( ); }; ``` -------------------------------- ### Run Test Suite Source: https://github.com/mittwald/api-client-js/blob/master/CONTRIBUTING.md Execute this command to run the project's test suite. ```shell $ yarn test ``` -------------------------------- ### Configure Request Parameters Source: https://github.com/mittwald/api-client-js/blob/master/packages/mittwald/README.md Demonstrates setting path parameters, headers, query parameters, and request body for an API operation. ```javascript const response = await mittwaldApi.category.operation({ // path parameters pathParameter1: "param1", pathParameter2: "param2", // parameters in header headers: { "x-header": "header", }, // query parameters queryParameters: { queryParameter1: "queryParam1", queryParameter2: "queryParam2", }, // JSON object in request body data: { data1: "data1", data2: "data2", }, }); ``` -------------------------------- ### Create React Client Instance Source: https://github.com/mittwald/api-client-js/blob/master/packages/mittwald/README.md Instantiate a React-aligned API client from a base client instance. ```javascript const api = MittwaldAPIV2Client.newUnauthenticated(); const apiReact = MittwaldAPIV2ClientReact.fromBaseClient(api); ``` -------------------------------- ### Project Model Source: https://context7.com/mittwald/api-client-js/llms.txt Represents a Mittwald project, providing static finder methods, mutation methods, and typed relational accessors. All async methods are wrapped with `provideReact` and can be called as plain async functions or used as React hooks. ```APIDOC ## `Project` model — Domain object for mittwald projects Provides static finder methods, mutation methods, and typed relational accessors. All async methods are wrapped with `provideReact` and can be called as plain async functions or used as React hooks. ```typescript import { api, Project } from "@mittwald/api-models"; api.setupWithApiToken(process.env.MITTWALD_API_TOKEN!); // Find by ID (returns undefined if not found) const project = await Project.find("p-abc123"); if (!project) { console.log("Project not found"); process.exit(1); } console.log("Description:", project.data.description); console.log("Customer ID:", project.customer.id); // Update description await project.updateDescription("New description"); // List ingresses for the project const ingressList = await project.ingresses.execute(); console.log("Ingresses:", ingressList.items.map((i) => i.data.hostname)); // Create a new project on a server const newProject = await Project.create("srv-xyz789", "My New Project"); console.log("Created project ID:", newProject.id); // In React: suspending component function MyComponent({ projectId }: { projectId: string }) { // .use() suspends until data is available const project = Project.get.use(projectId); return
{project.data.description}
; } ``` ``` -------------------------------- ### Generate API Client with CLI Source: https://github.com/mittwald/api-client-js/blob/master/packages/generator/README.md Use the `acg generate` command to build your API client. Specify the client name, input OpenAPI spec, output directory, and optional headers. ```shell acg generate --name MittwaldAPIV2 spec/openapi.json src/generated --optionalHeader x-access-token ``` -------------------------------- ### MittwaldAPIClient.newWithCredentials(email, password) Source: https://context7.com/mittwald/api-client-js/llms.txt Authenticates with email and password, then returns a fully authenticated client. It throws an ApiClientError if login fails. ```APIDOC ## MittwaldAPIClient.newWithCredentials(email, password) — Authenticate with email + password Performs a login request, extracts the session token, and returns a fully authenticated client. Throws `ApiClientError` if login fails. ```typescript import { MittwaldAPIV2Client } from "@mittwald/api-client"; const client = await MittwaldAPIV2Client.newWithCredentials( "user@example.com", "s3cr3tP@ss", ); const response = await client.user.getOwnAccount(); assertStatus(response, 200); console.log("Logged in as:", response.data.email); ``` ``` -------------------------------- ### Initialize API Client with Token Source: https://context7.com/mittwald/api-client-js/llms.txt Initialize the domain model layer with an API token. This must be called once at application startup before using any model class. ```typescript import { api, Project, Customer, Server } from "@mittwald/api-models"; // Initialize once at startup api.setupWithApiToken(process.env.MITTWALD_API_TOKEN!); ``` ```typescript // Now all model classes work against the live API const projects = await Project.list(); console.log("Projects:", projects.map((p) => p.data.description)); const customer = await Customer.get("cst-abc123"); console.log("Customer:", customer.data.name); // Access nested relations const customerProjects = await customer.projects.execute(); console.log("Customer's projects:", customerProjects.items.map((p) => p.data.description)); ``` -------------------------------- ### Project Model Operations Source: https://context7.com/mittwald/api-client-js/llms.txt Demonstrates static finder, mutation, and relational accessors for the Project model. Async methods can be used as plain async functions or React hooks. ```typescript import { api, Project } from "@mittwald/api-models"; api.setupWithApiToken(process.env.MITTWALD_API_TOKEN!); ``` ```typescript // Find by ID (returns undefined if not found) const project = await Project.find("p-abc123"); if (!project) { console.log("Project not found"); process.exit(1); } console.log("Description:", project.data.description); console.log("Customer ID:", project.customer.id); ``` ```typescript // Update description await project.updateDescription("New description"); ``` ```typescript // List ingresses for the project const ingressList = await project.ingresses.execute(); console.log("Ingresses:", ingressList.items.map((i) => i.data.hostname)); ``` ```typescript // Create a new project on a server const newProject = await Project.create("srv-xyz789", "My New Project"); console.log("Created project ID:", newProject.id); ``` ```typescript // In React: suspending component function MyComponent({ projectId }: { projectId: string }) { // .use() suspends until data is available const project = Project.get.use(projectId); return
{project.data.description}
; } ``` -------------------------------- ### Implement API Interaction via Behaviors Source: https://github.com/mittwald/api-client-js/blob/master/packages/models/README.md Shows the recommended approach where API interactions are delegated to behaviors, promoting loose coupling and testability. ```typescript class ProjectDetailed { public static async find(id: string): Promise { const data = await config.project.behaviors.find(id); if (data !== undefined) { return new Project(data.id, data); } } } ``` -------------------------------- ### Import API Client Source: https://github.com/mittwald/api-client-js/blob/master/packages/mittwald/README.md Import the MittwaldAPIV2Client from the @mittwald/api-client package. ```typescript import { MittwaldAPIV2Client } from "@mittwald/api-client"; ``` -------------------------------- ### MittwaldAPIClient.newUnauthenticated() Source: https://context7.com/mittwald/api-client-js/llms.txt Creates a client without any authentication, suitable for accessing public endpoints. ```APIDOC ## MittwaldAPIClient.newUnauthenticated() — Unauthenticated client Creates a client without authentication. Useful for public endpoints (e.g., listing available software versions). ```typescript import { MittwaldAPIV2Client } from "@mittwald/api-client"; const client = MittwaldAPIV2Client.newUnauthenticated(); const response = await client.app.listApps({}); assertStatus(response, 200); console.log("Available apps:", response.data.map((a) => a.name)); ``` ``` -------------------------------- ### React Suspense Client for API Operations Source: https://context7.com/mittwald/api-client-js/llms.txt Demonstrates using the auto-generated React client to wrap API operations as suspense-compatible resources. Use `.use()` within a React component wrapped in ``. ```typescript import { MittwaldAPIClientReact } from "@mittwald/api-client/react"; import { MittwaldAPIV2Client } from "@mittwald/api-client"; import React, { Suspense } from "react"; const baseClient = MittwaldAPIV2Client.newWithToken(process.env.MITTWALD_API_TOKEN!); const reactClient = new MittwaldAPIClientReact(baseClient); ``` ```typescript function ProjectDetail({ projectId }: { projectId: string }) { // Suspends until the API responds; throws on error const project = reactClient.project.getProject .use({ pathParameters: { projectId } }); return (

{project.data.description}

Customer: {project.data.customerId}

); } ``` ```typescript function App() { return ( Loading…}> ); } ``` -------------------------------- ### Implement API Behavior Source: https://github.com/mittwald/api-client-js/blob/master/packages/models/README.md Provides a concrete implementation for the API behavior, handling the actual API request and response processing. ```typescript import { ProjectBehaviors } from "./types.js"; import { assertStatus, MittwaldAPIV2Client } from "@mittwald/api-client"; export const apiProjectBehaviors = ( client: MittwaldAPIV2Client, ): ProjectBehaviors => ({ find: async (id) => { const response = await client.project.getProject({ projectId: id, }); if (response.status === 200) { return response.data; } assertStatus(response, 403); }, }); ``` -------------------------------- ### Customer Model Operations Source: https://context7.com/mittwald/api-client-js/llms.txt Illustrates customer-specific operations including listing, detail retrieval, and updates. Also shows traversal to related servers and projects. ```typescript import { api, Customer } from "@mittwald/api-models"; api.setupWithApiToken(process.env.MITTWALD_API_TOKEN!); ``` ```typescript // List all customers with default pagination const query = Customer.query({ limit: 20 }); const list = await query.execute(); console.log(`Showing ${list.items.length} of ${list.totalCount} customers`); for (const item of list.items) { console.log(item.id, item.data.name); } ``` ```typescript // Get a single customer (throws ObjectNotFoundError if missing) const customer = await Customer.get("cst-abc123"); await customer.update({ name: "Updated Name" }); ``` ```typescript // Traverse to related resources const servers = await customer.servers.execute(); console.log("Servers:", servers.items.map((s) => s.id)); const projects = await customer.projects.execute(); console.log("Projects:", projects.items.map((p) => p.data.description)); ``` -------------------------------- ### Authenticate Client with Email and Password Source: https://context7.com/mittwald/api-client-js/llms.txt Performs a login request using email and password, extracts the session token, and returns an authenticated client. Throws ApiClientError on login failure. ```typescript import { MittwaldAPIV2Client } from "@mittwald/api-client"; const client = await MittwaldAPIV2Client.newWithCredentials( "user@example.com", "s3cr3tP@ss", ); const response = await client.user.getOwnAccount(); assertStatus(response, 200); console.log("Logged in as:", response.data.email); ``` -------------------------------- ### Create Authenticated Client with API Token Source: https://context7.com/mittwald/api-client-js/llms.txt Instantiates a MittwaldAPIV2Client with an API token for server-side usage. The token is sent as the 'x-access-token' header. Handles all API scenarios explicitly. ```typescript import { MittwaldAPIV2Client } from "@mittwald/api-client"; import { assertStatus } from "@mittwald/api-client"; const client = MittwaldAPIV2Client.newWithToken(process.env.MITTWALD_API_TOKEN!); // List all projects the authenticated user can access const response = await client.project.listProjects({}); assertStatus(response, 200); // response.data is typed as the full project list array console.log(response.data.map((p) => `${p.id}: ${p.description}`)); ``` -------------------------------- ### MittwaldAPIClient.newWithToken(apiToken) Source: https://context7.com/mittwald/api-client-js/llms.txt Creates an authenticated MittwaldAPIClient instance using an API token. This is suitable for server-side applications. ```APIDOC ## MittwaldAPIClient.newWithToken(apiToken) — Create authenticated client Instantiates a `MittwaldAPIClient` that attaches the given API token as the `x-access-token` header on every request. This is the standard entry point for server-side usage. ```typescript import { MittwaldAPIV2Client } from "@mittwald/api-client"; import { assertStatus } from "@mittwald/api-client"; const client = MittwaldAPIV2Client.newWithToken(process.env.MITTWALD_API_TOKEN!); // List all projects the authenticated user can access const response = await client.project.listProjects({}); assertStatus(response, 200); // response.data is typed as the full project list array console.log(response.data.map((p) => `${p.id}: ${p.description}`)); ``` ``` -------------------------------- ### Customer Model Source: https://context7.com/mittwald/api-client-js/llms.txt Represents a Mittwald customer, mirroring the `Project` pattern with customer-specific operations. Includes traversal to related servers and projects. ```APIDOC ## `Customer` model — Domain object for mittwald customers Mirrors the `Project` pattern with customer-specific operations: listing, detail retrieval, and update. Includes traversal to related servers and projects. ```typescript import { api, Customer } from "@mittwald/api-models"; api.setupWithApiToken(process.env.MITTWALD_API_TOKEN!); // List all customers with default pagination const query = Customer.query({ limit: 20 }); const list = await query.execute(); console.log(`Showing ${list.items.length} of ${list.totalCount} customers`); for (const item of list.items) { console.log(item.id, item.data.name); } // Get a single customer (throws ObjectNotFoundError if missing) const customer = await Customer.get("cst-abc123"); await customer.update({ name: "Updated Name" }); // Traverse to related resources const servers = await customer.servers.execute(); console.log("Servers:", servers.items.map((s) => s.id)); const projects = await customer.projects.execute(); console.log("Projects:", projects.items.map((p) => p.data.description)); ``` ``` -------------------------------- ### client..(requestObject) Source: https://context7.com/mittwald/api-client-js/llms.txt Provides access to API operations organized by domain (e.g., project, app, database). Each operation takes a typed request object. ```APIDOC ## client..(requestObject) — Domain-organized API calls Every API domain is a property on the client (e.g., `client.project`, `client.app`, `client.database`). Each operation accepts a typed request object with `pathParameters`, `queryParameters`, `data`, and optional `headers`. ```typescript import { MittwaldAPIV2Client, assertStatus, assertOneOfStatus } from "@mittwald/api-client"; const client = MittwaldAPIV2Client.newWithToken(process.env.MITTWALD_API_TOKEN!); // Create a MySQL database const createResp = await client.database.createMysqlDatabase({ pathParameters: { projectId: "abc123" }, data: { database: { name: "my_db", characterSettings: { characterSet: "utf8mb4", collate: "utf8mb4_unicode_ci" } }, user: { name: "my_user", password: "Str0ng!Pass", accessLevel: "full", externalAccess: false }, }, }); assertStatus(createResp, 201); const dbId = createResp.data.id; // Get the database, tolerating both found and not-found const getResp = await client.database.getMysqlDatabase({ pathParameters: { mysqlDatabaseId: dbId }, }); assertOneOfStatus(getResp, [200, 404]); if (getResp.status === 200) { console.log("DB name:", getResp.data.name); } else { console.log("Database not found"); } // List all MySQL databases for a project with pagination const listResp = await client.database.listMysqlDatabases({ pathParameters: { projectId: "abc123" }, queryParameters: { limit: 25, skip: 0 }, }); assertStatus(listResp, 200); ``` ``` -------------------------------- ### Generate TypeScript API Client Programmatically Source: https://github.com/mittwald/api-client-js/blob/master/packages/generator/README.md This TypeScript code demonstrates how to use the API client generator programmatically. It loads the OpenAPI spec, parses it, and generates descriptors, types, and the client code. ```typescript import * as path from "path"; import { UniversalContentLoader } from "@mittwald/api-code-generator/js"; import { UniversalFileLoader } from "@mittwald/api-code-generator/js"; import { OpenApiSpec } from "@mittwald/api-code-generator/js"; import { CodeGenerationModel } from "@mittwald/api-code-generator/js"; import { prepareTypeScriptOutput } from "@mittwald/api-code-generator/js"; import { writeIfChangedAsync } from "@mittwald/api-code-generator/js"; const name = "MittwaldAPIV2"; const inout = `${process.cwd()}/spec/openapi.json`; const output = `${process.cwd()}/src/generated`; // Loading OpenAPI spec const loader = new UniversalContentLoader(new UniversalFileLoader(input)); const openApiDoc = await loader.load(); // Parsing OpenAPI spec const spec = await OpenApiSpec.parse(openApiDoc, { skipValidation: flags.skipValidation, }); // Building transformation model const model = CodeGenerationModel.fromDoc(name, spec.document); // Generating descriptors const descriptorsFileContent = model.paths.compileDescriptors(); await writeIfChangedAsync( path.join(output, "descriptors.ts"), await prepareTypeScriptOutput(descriptorsFileContent), ); // Generating types const typesFileContent = await model.compileTypes({ rootNamespace: flags.name, optionalHeaders: ["x-access-token"], }); await writeIfChangedAsync( path.join(output, "types.ts"), await prepareTypeScriptOutput(typesFileContent), ); // Generating client const clientFileContent = model.paths.compileClient(); await writeIfChangedAsync( path.join(output, "client.ts"), await prepareTypeScriptOutput(clientFileContent), ); // if needed: Generating React client const reactClientFileContent = model.paths.compileReactClient(); await writeIfChangedAsync( path.join(output, "client-react.ts"), await prepareTypeScriptOutput(reactClientFileContent), ); ``` -------------------------------- ### Add Custom HTTP Headers with Axios Source: https://github.com/mittwald/api-client-js/blob/master/packages/mittwald/README.md Shows how to add custom HTTP headers to all requests made by the API client by accessing the underlying Axios instance. ```typescript client.axios.defaults.headers["User-Agent"] = `your-tool/v1.2.3`; ``` -------------------------------- ### Use Behaviors in Model Source: https://github.com/mittwald/api-client-js/blob/master/packages/models/README.md Illustrates how a model class utilizes the defined behaviors to perform its operations, such as finding data. ```typescript import { config } from "../../config/config.js"; class ProjectDetailed { public static async find(id: string): Promise { const data = await config.project.behaviors.find(id); if (data !== undefined) { return new Project(data.id, data); } } } ``` -------------------------------- ### Reference API Request and Response Types with TypeScript Source: https://github.com/mittwald/api-client-js/blob/master/packages/mittwald/README.md Illustrates how to import and reference specific request and response types from the MittwaldAPIV2 namespace for use in TypeScript projects. ```typescript import { MittwaldAPIV2 } from "@mittwald/api-client"; type ProjectData = MittwaldAPIV2.Operations.ProjectGetProject.ResponseData; // Reference "non-200" response type type ProjectNotFoundData = MittwaldAPIV2.Operations.ProjectGetProject.ResponseData<404>; type CreateProjectData = MittwaldAPIV2.Operations.ProjectCreateProject.RequestData; ``` -------------------------------- ### Provide React Compatibility for Async Methods Source: https://github.com/mittwald/api-client-js/blob/master/packages/models/README.md Enhances asynchronous model methods with a `use`-method property for seamless integration with React using `@mittwald/react-use-promise`. ```typescript class ProjectDetailed { public static find = provideReact( async (id: string): Promise => { const data = await config.behaviors.project.find(id); if (data !== undefined) { return new ProjectDetailed(data); } }, ); } ``` -------------------------------- ### Add Access Token to API Client Source: https://github.com/mittwald/api-client-js/blob/master/packages/commons/README.md Use `withToken` to automatically add the user's access token as a request header for all API requests. ```typescript const client = new APIClient({ baseURL }); const authenticatedClient = withToken(client, token); ``` -------------------------------- ### MittwaldAPIV2ClientReact Source: https://context7.com/mittwald/api-client-js/llms.txt The auto-generated React client wraps every readable API operation as a suspense-compatible resource. Each method returns a value that can be consumed with `.use()` inside a React component wrapped in ``. ```APIDOC ## `MittwaldAPIV2ClientReact` — React suspense client (generated) The auto-generated React client wraps every readable API operation as a suspense-compatible resource. Each method returns a value that can be consumed with `.use()` inside a React component wrapped in ``. ```typescript import { MittwaldAPIClientReact } from "@mittwald/api-client/react"; import { MittwaldAPIV2Client } from "@mittwald/api-client"; import React, { Suspense } from "react"; const baseClient = MittwaldAPIV2Client.newWithToken(process.env.MITTWALD_API_TOKEN!); const reactClient = new MittwaldAPIClientReact(baseClient); function ProjectDetail({ projectId }: { projectId: string }) { // Suspends until the API responds; throws on error const project = reactClient.project.getProject .use({ pathParameters: { projectId } }); return (

{project.data.description}

Customer: {project.data.customerId}

); } function App() { return ( Loading…}> ); } ``` ``` -------------------------------- ### withAccessToken(client, token, headerName) Source: https://context7.com/mittwald/api-client-js/llms.txt Adds an Axios request interceptor that injects `x-access-token` header on every request where the header is not already present. Works with both `ApiClientBase` subclasses and raw `AxiosInstance` objects. ```APIDOC ## withAccessToken(client, token, headerName) ### Description Adds an Axios request interceptor that injects `x-access-token` header on every request where the header is not already present. Works with both `ApiClientBase` subclasses and raw `AxiosInstance` objects. ### Usage ```typescript import axios from "axios"; import { withAccessToken } from "@mittwald/api-client-commons"; import { MittwaldAPIV2Client } from "@mittwald/api-client"; // Usage with the high-level client const client = MittwaldAPIV2Client.newUnauthenticated(); withAccessToken(client, "my-api-token-here"); // Usage with a raw axios instance const axiosInstance = axios.create({ baseURL: "https://api.mittwald.de/" }); withAccessToken(axiosInstance, "my-api-token-here"); // Custom header name (for non-standard APIs) withAccessToken(client, "my-token", "Authorization"); ``` ``` -------------------------------- ### Programmatic Generation with `CodeGenerationModel` Source: https://context7.com/mittwald/api-client-js/llms.txt Allows for programmatic generation of API clients using TypeScript. This is useful for custom build scripts, CI pipelines, or advanced code generation workflows. ```APIDOC ### `CodeGenerationModel` + programmatic generation — TypeScript API Generates a client programmatically — useful for build scripts, CI pipelines, or custom code generation workflows. ```typescript import * as path from "path"; import { UniversalContentLoader, UniversalFileLoader, OpenApiSpec, CodeGenerationModel, prepareTypeScriptOutput, writeIfChangedAsync, } from "@mittwald/api-code-generator/js"; const name = "MyAPIV2"; const input = path.resolve("spec/openapi.json"); const output = path.resolve("src/generated"); // Load and parse the OpenAPI spec const loader = new UniversalContentLoader(new UniversalFileLoader(input)); const openApiDoc = await loader.load(); const spec = await OpenApiSpec.parse(openApiDoc, { skipValidation: false }); // Build the transformation model const model = CodeGenerationModel.fromDoc(name, spec.document); // Emit descriptors await writeIfChangedAsync( path.join(output, "descriptors.ts"), await prepareTypeScriptOutput(model.paths.compileDescriptors()), ); // Emit types await writeIfChangedAsync( path.join(output, "types.ts"), await prepareTypeScriptOutput( await model.compileTypes({ rootNamespace: name, optionalHeaders: ["x-access-token"] }), ), ); // Emit client await writeIfChangedAsync( path.join(output, "client.ts"), await prepareTypeScriptOutput(model.paths.compileClient()), ); // Emit React client (optional) await writeIfChangedAsync( path.join(output, "client-react.ts"), await prepareTypeScriptOutput(model.paths.compileReactClient()), ); console.log("Code generation complete."); ``` ``` -------------------------------- ### Create Unauthenticated Client Source: https://context7.com/mittwald/api-client-js/llms.txt Creates a MittwaldAPIV2Client without authentication, suitable for accessing public endpoints like listing available software versions. ```typescript import { MittwaldAPIV2Client } from "@mittwald/api-client"; const client = MittwaldAPIV2Client.newUnauthenticated(); const response = await client.app.listApps({}); assertStatus(response, 200); console.log("Available apps:", response.data.map((a) => a.name)); ``` -------------------------------- ### assertOneOfStatus(response, expectedStatuses) Source: https://context7.com/mittwald/api-client-js/llms.txt Like `assertStatus`, but accepts an array of acceptable status codes. Useful for optional resources or operations with multiple valid outcomes. ```APIDOC ## assertOneOfStatus(response, expectedStatuses) ### Description Like `assertStatus`, but accepts an array of acceptable status codes. Useful for optional resources or operations with multiple valid outcomes. ### Usage ```typescript import { MittwaldAPIV2Client, assertOneOfStatus } from "@mittwald/api-client"; const client = MittwaldAPIV2Client.newWithToken(process.env.MITTWALD_API_TOKEN!); const response = await client.project.getProject({ pathParameters: { projectId: "maybe-existing-id" }, }); assertOneOfStatus(response, [200, 404]); if (response.status === 200) { console.log("Found:", response.data.description); } else { console.log("Not found, status:", response.status); } ``` ``` -------------------------------- ### Programmatic TypeScript API Client Generation Source: https://context7.com/mittwald/api-client-js/llms.txt Generates an API client programmatically using the CodeGenerationModel. This is useful for build scripts or CI pipelines. Ensure all necessary modules are imported and paths are correctly resolved. ```typescript import * as path from "path"; import { UniversalContentLoader, UniversalFileLoader, OpenApiSpec, CodeGenerationModel, prepareTypeScriptOutput, writeIfChangedAsync, } from "@mittwald/api-code-generator/js"; const name = "MyAPIV2"; const input = path.resolve("spec/openapi.json"); const output = path.resolve("src/generated"); // Load and parse the OpenAPI spec const loader = new UniversalContentLoader(new UniversalFileLoader(input)); const openApiDoc = await loader.load(); const spec = await OpenApiSpec.parse(openApiDoc, { skipValidation: false }); // Build the transformation model const model = CodeGenerationModel.fromDoc(name, spec.document); // Emit descriptors await writeIfChangedAsync( path.join(output, "descriptors.ts"), await prepareTypeScriptOutput(model.paths.compileDescriptors()), ); // Emit types await writeIfChangedAsync( path.join(output, "types.ts"), await prepareTypeScriptOutput( await model.compileTypes({ rootNamespace: name, optionalHeaders: ["x-access-token"] }), ), ); // Emit client await writeIfChangedAsync( path.join(output, "client.ts"), await prepareTypeScriptOutput(model.paths.compileClient()), ); // Emit React client (optional) await writeIfChangedAsync( path.join(output, "client-react.ts"), await prepareTypeScriptOutput(model.paths.compileReactClient()), ); console.log("Code generation complete."); ``` -------------------------------- ### withAccessToken Source: https://github.com/mittwald/api-client-js/blob/master/packages/commons/README.md An interceptor that automatically adds the user's access token to every API request as an Authorization header. ```APIDOC ## withAccessToken(client, token) ### Description Automatically sets the `Authorization` request header with the provided `token` for all API requests made by the `client`. ### Parameters - **client**: An instance of `APIClient`. - **token** (string): The access token to be used for authentication. ### Returns An `APIClient` instance configured with the access token interceptor. ### Example ```ts const client = new APIClient({ baseURL }); const authenticatedClient = withToken(client, token); ``` ``` -------------------------------- ### Define Behavior Interface Source: https://github.com/mittwald/api-client-js/blob/master/packages/models/README.md Defines the interface for project behaviors, specifying the methods that concrete behavior implementations must provide. ```typescript export interface ProjectBehaviors { find: (id: string) => Promise; updateDescription: (projectId: string, description: string) => Promise; } ``` -------------------------------- ### Assert One of Multiple HTTP Statuses with assertOneOfStatus() Source: https://context7.com/mittwald/api-client-js/llms.txt Accepts an array of acceptable status codes, similar to `assertStatus`. Useful for optional resources or operations with multiple valid outcomes, such as checking for a resource that might exist (200) or not (404). ```typescript import { MittwaldAPIV2Client, assertOneOfStatus } from "@mittwald/api-client"; const client = MittwaldAPIV2Client.newWithToken(process.env.MITTWALD_API_TOKEN!); const response = await client.project.getProject({ pathParameters: { projectId: "maybe-existing-id" }, }); assertOneOfStatus(response, [200, 404]); if (response.status === 200) { console.log("Found:", response.data.description); } else { console.log("Not found, status:", response.status); } ``` -------------------------------- ### Validate OpenAPI Spec with CLI Source: https://github.com/mittwald/api-client-js/blob/master/packages/generator/README.md Use the `acg validate` command to validate your OpenAPI specification file. ```shell acg validate spec/openapi.json ``` -------------------------------- ### extractTotalCountHeader(response) Source: https://context7.com/mittwald/api-client-js/llms.txt Reads the `x-pagination-totalcount` response header from a 200 list response and returns it as a number. Throws if the header is absent or invalid. ```APIDOC ## extractTotalCountHeader(response) ### Description Reads the `x-pagination-totalcount` response header from a 200 list response and returns it as a number. Throws if the header is absent or invalid. ### Usage ```typescript import { MittwaldAPIV2Client, extractTotalCountHeader } from "@mittwald/api-client"; const client = MittwaldAPIV2Client.newWithToken(process.env.MITTWALD_API_TOKEN!); const response = await client.project.listProjects({ queryParameters: { limit: 1 }, }); const totalCount = extractTotalCountHeader(response); console.log(`Total projects: ${totalCount}`); // Fetch all pages const allProjects = []; const pageSize = 50; for (let skip = 0; skip < totalCount; skip += pageSize) { const page = await client.project.listProjects({ queryParameters: { limit: pageSize, skip }, }); assertStatus(page, 200); allProjects.push(...page.data); } ``` ``` -------------------------------- ### `acg generate` Source: https://context7.com/mittwald/api-client-js/llms.txt The primary CLI command for `@mittwald/api-code-generator`. It reads an OpenAPI JSON/YAML specification and generates typed TypeScript files for an API client, including descriptors, types, and client implementations. ```APIDOC ## `@mittwald/api-code-generator` ### `acg generate` — CLI: Generate TypeScript API client from OpenAPI spec The primary CLI command. Reads an OpenAPI JSON/YAML spec and emits typed TypeScript files: `descriptors.ts`, `types.ts`, `client.ts`, and optionally `client-react.ts`. ```shell # Install the generator npm install -D @mittwald/api-code-generator # Validate the spec first acg validate spec/openapi.json # Generate the client acg generate \ --name MyAPIV2 \ --optionalHeader x-access-token \ spec/openapi.json \ src/generated # Generated output: # src/generated/descriptors.ts – operation metadata # src/generated/types.ts – request/response TypeScript types # src/generated/client.ts – Axios-based typed client class # src/generated/client-react.ts – React suspense resource wrappers ``` ``` -------------------------------- ### Avoid Direct API Calls in Models Source: https://github.com/mittwald/api-client-js/blob/master/packages/models/README.md Demonstrates an anti-pattern where API calls are made directly within the model class. This leads to tight coupling and makes testing difficult. ```typescript class ProjectDetailed { public static async find( id: string, ): Promise { const response = await client.project.getProject({ id, }); if (response.status === 200) { return new Project(response.data.id, response.data); } assertStatus(response, 403); } } ```