Skip to main content

Operation filters

operationFilters selects which operations of a specification are generated, by tag, path, HTTP method, operationId or deprecation. The Playwright generator adds two filters that select which responses of an operation get a service method. Read this when you want one specification to produce several smaller outputs, or when a generated file contains more, or less, than you expected.

What a filter does​

An operation is one HTTP method on one path. Every generator walks all operations of the specification and asks the filters whether to keep each one. A dropped operation produces no client method, no service method and no operation-derived types or schemas (query parameters, headers, request bodies, responses). In the TypeScript and zod generators, filtering also decides which component schemas are emitted: when at least one surviving operation references a schema, only the schemas reachable from surviving operations are written, so a filtered output does not carry the types of the endpoints it left out.

operationFilters is an object with up to nine keys, set per entry in specs or once in defaults:

KeyTypeKeeps or drops an operation when
includeTagsstring[]Kept only if at least one of its tags is listed. Exact match.
excludeTagsstring[]Dropped if any of its tags is listed. Exact match.
includePathsstring[]Kept only if its path matches one of the patterns. Glob patterns.
excludePathsstring[]Dropped if its path matches one of the patterns. Glob patterns.
includeMethodsstring[]Kept only if its HTTP method is listed. Case-insensitive ("GET" and "get" are the same).
excludeMethodsstring[]Dropped if its HTTP method is listed. Case-insensitive.
includeOperationIdsstring[]Kept only if its operationId matches one of the patterns. Glob patterns. An operation without an operationId is dropped.
excludeOperationIdsstring[]Dropped if its operationId matches one of the patterns. Glob patterns. An operation without an operationId is kept.
excludeDeprecatedbooleanDropped if it declares deprecated: true.

Paths and operation IDs are matched with glob patterns (the minimatch syntax): * matches within one path segment, ** crosses segments, ? matches one character, [abc] a set and {a,b} alternatives. A pattern without wildcards is an exact match, so includePaths: ["/users"] matches /users and nothing below it; use ["/users", "/users/**"] for the whole subtree. Tags and methods are compared literally.

The path that is matched depends on the generator when stripPathPrefix is set: the TypeScript and zod generators match the path as written in the specification, the Playwright and k6 generators match the path after the prefix is stripped. Without stripPathPrefix there is no difference. See naming.md for prefix stripping.

Include first, then exclude​

The rules combine the same way in every generator:

  1. With no operationFilters, every operation is kept.
  2. An empty array means "no constraint", not "exclude everything". includeTags: [] keeps all operations.
  3. Every include* filter that is set must be satisfied. They narrow the set, so includeTags: ["users"] with includeMethods: ["get"] keeps only the GET operations tagged users.
  4. Then every exclude* filter that is set is applied to what is left. An exclude always wins over an include.

The examples below all run against one specification with fifteen operations spread over /users, /users/{id}, /admin/users, /admin/settings, /posts, /products, /products/{id}, /api/v1/items, /api/v2/items, /internal/metrics and /deprecated/old-endpoint, tagged users, admin, posts, products, items, internal and legacy. The output shown is the list of methods in the generated k6 client, with useOperationId: true so the names are the specification's operation IDs; the same operations survive in every generator.

Tags​

{
input: "openapi.yaml",
outputClient: "k6/users/client.ts",
outputTypes: "k6/users/types.ts",
operationFilters: { includeTags: ["users"], excludeDeprecated: true },
}
getUsers(); // GET /users
createUser(); // POST /users
getUser(id); // GET /users/{id}
updateUser(id); // PUT /users/{id}

DELETE /users/{id} carries the users tag but is marked deprecated: true, so excludeDeprecated removed it after includeTags had selected it. An operation with several tags is kept by includeTags when any one of them is listed, and dropped by excludeTags when any one of them is listed, so excludeTags: ["internal"] also removes /admin/settings, which is tagged both admin and internal.

Paths​

operationFilters: { includePaths: ["/users", "/users/**"], excludeMethods: ["put", "delete"] }
getUsers(); // GET /users
createUser(); // POST /users
getUser(id); // GET /users/{id}

/users/** matches /users/{id} and anything deeper; /admin/users does not start with /users and is not matched. The excluded methods then remove PUT and DELETE /users/{id}.

Methods​

operationFilters: { includeMethods: ["get"], excludeTags: ["internal", "admin"] }
getUsers(); // GET /users
getUser(id); // GET /users/{id}
getPosts(); // GET /posts
getProducts(); // GET /products
getProductById(id); // GET /products/{id}
getV1Items(); // GET /api/v1/items
getV2Items(); // GET /api/v2/items
getOldEndpoint(); // GET /deprecated/old-endpoint

Every GET operation survives except the two tagged admin or internal. getOldEndpoint is deprecated but nothing excluded deprecated operations here, so it stays: the filters do only what they are told.

Operation IDs​

operationFilters: { includeOperationIds: ["get*"], excludeOperationIds: ["getMetrics", "getOld*"] }
getUsers(); // GET /users
getUser(id); // GET /users/{id}
getPosts(); // GET /posts
getProducts(); // GET /products
getProductById(id); // GET /products/{id}
getAdminSettings(); // GET /admin/settings
getV1Items(); // GET /api/v1/items
getV2Items(); // GET /api/v2/items

get* selected every operation whose ID starts with get; the exclude list then removed getMetrics and getOldEndpoint. Operation IDs are matched as written, so this is the filter to reach for when the IDs follow a naming convention and the tags do not.

When everything is filtered out​

operationFilters: {
includeTags: ["billing"];
}

No operation carries that tag. The entry still succeeds, but the run warns, so a typo in a filter does not pass as a quiet success:

[@spartaficial/openapi-to-k6] Warnings:
⚠️ All 15 operations were filtered out. Check your operationFilters configuration.
⚠️ No output generated - no operations found after filtering

What is written in this case differs per generator: k6 writes the types file and no client, Playwright writes the schemas file and no client or service, and the TypeScript and zod generators write a file holding the component schemas with no operation-derived members. When showStats is on, the file header of the TypeScript and zod output also carries an "Operation Filtering" block with the number of operations kept and the number dropped per reason, which is the quickest way to see what a filter did.

Response filters in the Playwright generator​

The Playwright service has one method per response of an operation, each asserting its status code and validating its body (see generators/zod-playwright.md). Two further keys of operationFilters, accepted only by this generator, select which responses get a method. They do not touch the client, which keeps one method per operation.

KeyTypeEffect
includeStatusCodesstring[]The responses that get methods. Exact codes ("404") and ranges ("4xx", "2xx"). Naming it is what opts into non-2xx.
excludeStatusCodesstring[]Responses removed from whichever set resulted. Same syntax.

Without includeStatusCodes, only the success responses (200 to 299) get methods. Naming includeStatusCodes replaces that default with exactly the responses it matches, whatever their class. excludeStatusCodes only ever subtracts, so an exclude-only configuration never widens past the success responses. For an operation declaring 200, 201, 404 and 500:

ConfigurationMethods generated for
none200, 201
includeStatusCodes: ["2xx", "4xx"]200, 201, 404
includeStatusCodes: ["200"]200
includeStatusCodes: ["4xx"]404
excludeStatusCodes: ["5xx"]200, 201 (excluding never adds the 4xx)
excludeStatusCodes: ["201"]200

A specification with POST /users declaring 201, 202 and 400, and GET /users/{user-id} declaring 200 and 404, generates these service methods under includeStatusCodes: ["2xx", "4xx"]:

async postUsersCreated(options: { data: User }): Promise<User> // asserts 201
async postUsersAccepted(options: { data: User }): Promise<void> // asserts 202
async postUsersBadRequest(options: { data: User }): Promise<Problem> // asserts 400, validates against problemSchema
async getUsersByUserId(userId: string): Promise<User> // asserts 200
async getUsersByUserIdNotFound(userId: string): Promise<Problem> // asserts 404

and these with excludeStatusCodes: ["202"] and no include list:

async postUsersCreated(options: { data: User }): Promise<User>
async getUsersByUserId(userId: string): Promise<User>

Two details follow from how the names are built. Method and schema names are derived from the unfiltered specification, so narrowing a filter never renames anything: postUsersCreated keeps its suffix in the second configuration even though 201 is now the operation's only generated response. And an operation whose every response is filtered out disappears from the service entirely, while an operation that declares no responses at all keeps a single method that validates nothing. The suffix rules are in naming.md; the option is listed in reference/options-zod-playwright.md.