Runtime entry points
@spartaficial/openapi-to-k6/runtime and @spartaficial/openapi-to-zod-playwright/runtime are the two modules that generated clients and services import at run time. This page lists what they export, explains why generated code depends on them, and covers the one setup step k6 needs. Read it when you look at an import line in a generated file, or before bundling a k6 script.
Why generated code imports a runtime
The generated client is deliberately thin: each method builds a URL and hands the request to Playwright or to k6/http. The small amount of logic every method shares, such as serialising query parameters in the style the specification declares or merging per-request options with the ones set on the client, would otherwise be repeated in every generated file. It lives instead in a second entry point of the same package, so a generated file imports it rather than carrying its own copy. Nothing extra is installed: the package that generated the file already provides the module.
The main entry point of each package (@spartaficial/openapi-to-k6, @spartaficial/openapi-to-zod-playwright) is the generator: its CLI, configuration types and generator class. It does not re-export the runtime, and the runtime does not import the generator. Importing a /runtime module never requires a licence key, so compiling and running tests against already-generated code works with no key set; see licensing.md. The TypeScript and zod generators have no runtime entry point, because their output imports only zod.
@spartaficial/openapi-to-k6/runtime
A generated k6 client and service begin with:
import http from "k6/http";
import type { Params, Response } from "k6/http";
import { cleanBaseUrl, mergeRequestParameters } from "@spartaficial/openapi-to-k6/runtime";
import { check } from "k6";
import type { Params } from "k6/http";
import { type K6ServiceResult, serializeBody, formatResponseBody } from "@spartaficial/openapi-to-k6/runtime";
The module is written to run inside k6, which executes scripts on its own JavaScript runtime rather than Node.js: it uses no Node.js built-ins and no Node-only globals. Its exports:
| Export | Kind | What it does |
|---|---|---|
buildQueryString(params, serializations?) | function | Turns a query-parameter object into ?a=1&b=2, honouring each parameter's OpenAPI style, explode and allowReserved; arrays default to repeated keys. Returns "" for no parameters. |
mergeRequestParameters(requestParams, commonParams) | function | Merges per-call k6 Params over the ones given to the client constructor, deep-merging headers, tags and cookies. |
cleanBaseUrl(baseUrl) | function | Removes trailing slashes from the base URL passed to the client. |
serializeBody(body, contentType?) | function | Prepares a request body: strings, ArrayBuffers and k6 file data pass through, objects under a form or multipart content type are left for k6 to encode, other objects are JSON-encoded. |
serializePathParam(name, value, serialization?) | function | Encodes a path parameter in simple, label or matrix style for substitution into the URL. |
formatResponseBody(body) | function | Renders a response body for a log line: the string itself, null, or [ArrayBuffer: N bytes]. |
K6ServiceResult<T> | type | What a service method returns: { response, data: T, ok }, where ok is the result of the status check. |
QueryParams | type | The shape a client method accepts for params. |
QueryParameterStyle, ParameterSerialization, ParameterSerializationMap | types | The per-parameter serialisation the generated client passes to buildQueryString. |
PathParameterStyle, PathParameterSerialization | types | The same for path parameters. |
Params | type | Re-exported from k6/http for convenience. |
You rarely call these yourself. K6ServiceResult is the one you will name in your own code, when a helper takes the result of a service call:
import type { K6ServiceResult } from "@spartaficial/openapi-to-k6/runtime";
import type { User } from "./types";
function assertUsers(result: K6ServiceResult<User[]>): void {
if (!result.ok) {
console.log(`listUsers failed: ${result.response.status}`);
}
}
k6 needs a bundler
k6 resolves imports itself and does not understand the exports map in a package's package.json, so the specifier @spartaficial/openapi-to-k6/runtime does not resolve if you hand a generated TypeScript file straight to k6 run. Run the script through a bundler first (esbuild, webpack or rollup), the same step you already need to run TypeScript in k6; the bundle inlines the runtime module and the generated code together. Mark k6 and k6/* as external so the bundler leaves those imports for k6 itself. generators/k6.md covers the rest of the k6 setup.
@spartaficial/openapi-to-zod-playwright/runtime
A generated Playwright client and service begin with:
import type { APIRequestContext, APIResponse } from "@playwright/test";
import type { ApiRequestContextOptions } from "@spartaficial/openapi-to-zod-playwright/runtime";
import { serializeParams } from "@spartaficial/openapi-to-zod-playwright/runtime";
import { expect } from "@playwright/test";
import { parseWithPrettifyErrorWithValues } from "@spartaficial/openapi-to-zod-playwright/runtime";
import { ApiClient } from "./client";
import { userSchema, problemSchema, getUsersResponseSchema } from "./schemas";
This module runs in Node.js under Playwright and depends on zod, one of the package's two peer dependencies (the generated client itself imports the other, @playwright/test). Its exports:
| Export | Kind | What it does |
|---|---|---|
serializeParams(params, serializations?) | function | Serialises query parameters for Playwright's params option, honouring style, explode and allowReserved. Returns URLSearchParams (so arrays can repeat keys), or a pre-built string when a parameter uses allowReserved; a string or URLSearchParams you pass in is returned unchanged. |
serializeCookieHeader(cookies) | function | Turns an operation's in: cookie parameters into a Cookie header value, dropping undefined ones; returns undefined when nothing is left. |
serializePathParam(name, value, serialization?) | function | Encodes a path parameter in simple, label or matrix style. |
parseWithPrettifyErrorWithValues(schema, data) | function | Validates data against a Zod schema and throws a ZodValidationError whose message lists each issue with its path and the value received. What the service calls under the default zodErrorFormat. |
parseWithPrettifyError(schema, data) | function | The same with Zod's own prettifyError message, without received values. What the service calls under zodErrorFormat: "prettify". |
formatZodErrorWithValues(error, input), formatZodErrorPath(path) | functions | The formatting behind the two parsers, for use in your own helpers. |
ZodValidationError | class | The error the service throws on a failed validation: zodError (the original ZodError), issues (its issues array) and, for the values variant, input (the data that failed). |
ApiRequestContextOptions | type | The options a client method accepts: data, form, multipart, params, headers, timeout, failOnStatusCode, ignoreHTTPSErrors, maxRedirects, maxRetries. |
QueryParams, HttpHeaders, RequestBody, UrlEncodedFormData, MultipartFormData, MultipartFormValue, CookieParams | types | The parts of ApiRequestContextOptions and of a cookie parameter object. |
QueryParameterStyle, ParameterSerialization, ParameterSerializationMap, PathParameterStyle, PathParameterSerialization | types | The per-parameter serialisation the generated client passes to the serialisers. |
A failed validation in a test reads like this, with the default zodErrorFormat of "prettifyWithValues":
ZodValidationError:
✖ Too small: expected number >= 0 (received: -5)
→ at items[0].age
When a test needs the structured issues instead of the message, catch the error and read them from the class:
import { ZodValidationError } from "@spartaficial/openapi-to-zod-playwright/runtime";
try {
await service.getUsers();
} catch (error) {
if (error instanceof ZodValidationError) {
console.log(error.issues.map(issue => issue.path.join(".")));
}
throw error;
}
Choosing zodErrorFormat: "standard" makes the service call schema.parseAsync directly, so it throws Zod's own ZodError and the generated service imports nothing from the runtime for validation; serializeParams is still imported by the client. The option is described in generators/zod-playwright.md and listed in reference/options-zod-playwright.md.
Versioning
The runtime modules ship inside the same package version as the generator that wrote your files, so the generated code and the helpers it imports always come from one release. Regenerate after upgrading the package, and check release-notes.md for changes that affect generated output.