Skip to content

Conversation

@vdusek
Copy link
Contributor

@vdusek vdusek commented Jan 30, 2026

Summary

This PR refactors and fixes the OpenAPI specifications to better reflect actual API responses and to follow consistent naming conventions, primarily to improve the quality of generated client models.

Issue

Closes: #2182

I consider this to be a last update from my side (at least for now).

Key changes

Schema naming standardization

  • Rename response schemas to consistent patterns: GetXResponse / CreateXResponseXResponse.
  • Rename list schemas: XListListOfX, GetXListResponse →ListOfXResponse`.
    • This results in clearer, reusable models and avoids duplicate schemas with different names.

Type fixes

  • Add missing enums: WebhookDispatchStatus, ScheduleActionType, RunOrigin (for BuildsMeta.origin)
  • Add ANYONE_WITH_NAME_CAN_READ value to GeneralAccessEnum
  • Add ACTOR.STANDBY to WebhookEventType
  • Update usage schemas to use the additionalProperties pattern for dynamic keys

Schema cleanup

  • Remove duplicate schemas (e.g., PostAbortBuildResponse, BuildActorResponse)
  • Remove placeholder fields (e.g. foo)
  • Use PaginationResponse base for list schemas consistently
  • Remove enum constraint from SourceCodeFolder.folder

API response fixes

  • Remove required constraints from optional API fields
  • Fix schema to match actual API response (e.g. WebhookDispatch, WebhookEventType, ...)
  • Add missing schemas (e.g. ListOfTasks, ListOfTasksResponse, ...)

Questions

A few questions for the Platform team (a full review would be greatly appreciated):

  • What is GetOpenApiResponse.yaml supposed to represent?
    • It appears to be a meta-schema attempting to describe the full OpenAPI 3.x document structure, which causes code generators to produce many unnecessary intermediate classes.
  • The field DATA_TRANSFER_EXTERNAL_GBYTES? includes a question mark, is that intentional?
  • Is ActorDefinition.default_memory_mbytes intentionally defined as int or str?
  • Is WebhookDispatchList.data intentionally optional? It seems to be the only optional data field.
  • Please verify WebhookDispatchStatus; it is based only on observed API responses in tests.
  • Is WebhookEventType now correct with the TEST value?

Note

Medium Risk
Primarily spec/model changes, but they are widespread and will change generated client types and validation expectations; risk is in downstream compatibility rather than runtime behavior.

Overview
Standardizes and de-duplicates OpenAPI response/list schemas across Actors, builds, runs, tasks, schedules, store, datasets, key-value stores, request queues, users, and webhooks by renaming Get*/Create*/Update*Response and *List patterns to reusable *Response and ListOf* models, and updating path specs to reference the new schemas.

Corrects schema shapes and optionality: makes various fields nullable where responses are optional (e.g., build meta clientIp/userAgent, schedule lastRunAt/nextRunAt, actor/task stats), replaces placeholder request/response bodies with additionalProperties maps for dynamic JSON payloads (dataset items, KVS records, task input, usage maps), and removes outdated/duplicate meta-schemas (e.g., OpenAPI-document meta schema, abort-build/build-actor wrapper responses).

Adds/updates enums and references to tighten typing and reduce generator noise, including ScheduleActionType, WebhookDispatchStatus, expanded GeneralAccessEnum, and webhook dispatch/event typing (including switching webhook dispatch calls to an array and eventData to nullable).

Written by Cursor Bugbot for commit c08ee0e. Configure here.

vdusek and others added 18 commits January 30, 2026 19:49
Rename schemas to follow consistent naming patterns:
- List schemas: *List → ListOf* (e.g., BuildList → ListOfBuilds)
- Response schemas: Add Get/Create prefix for clarity
- Schedule schemas: Remove verbose ResponseData suffix

Schema renames:
- actor-builds: BuildList → ListOfBuilds, GetBuildListResponse → GetListOfBuildsResponse
- actor-runs: RunList → ListOfRuns, RunResponse → GetRunResponse
- actors: EnvVarList → ListOfEnvVars, VersionList → ListOfVersions
- datasets: DatasetResponse → CreateDatasetResponse
- key-value-stores: GetStoreResponse → GetKeyValueStoreResponse
- schedules: ScheduleResponseData → Schedule, GetListOfSchedulesResponseDataItems → ScheduleShort
- store: StoreData → ListOfStoreActors

Also makes lastRunAt and nextRunAt nullable in ScheduleShort (they can be null
when a schedule hasn't run yet or is disabled).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove required constraints from fields that the API doesn't always return:
- BuildsMeta.userAgent: Not always present in API response
- ActorStats: All stats fields can be missing for new actors
- TaskStats.totalRuns: Not always returned
- KeyValueStore: consoleUrl and keysPublicUrl are optional
- RequestQueueShort.expireAt: Not always present
- UsageItem: baseUnitPriceUsd, amountAfterVolumeDiscountUsd, priceTiers optional

These changes fix Pydantic ValidationError when parsing API responses where
these fields are missing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- TaskShort.actName: Can be null when actor is deleted
- TaskShort.actUsername: Can be null when user is deleted
- ActorShort.stats: Can be null for actors without stats
- RunStats.memAvgBytes: Remove minimum constraint (can be negative in edge cases)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- eventData: Remove from required and make nullable (can be null)
- calls: Change type from object to array (API returns array of call attempts)

The calls field contains multiple webhook delivery attempts, each with
startedAt, finishedAt, errorMessage, responseStatus, and responseBody.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change MonthlyServiceUsage and ServiceUsage from fixed property names to
additionalProperties pattern. The API returns dynamic keys like
ACTOR_COMPUTE_UNITS, PROXY_RESIDENTIAL_TRANSFER_BYTES, etc.

Using additionalProperties correctly models this as a map/dictionary where
keys are usage item names and values are UsageItem objects.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add missing enum value for resources that can be accessed by name without
authentication. Also reorder enum values for consistency.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract inline task list schema from actor-tasks path to reusable components:
- ListOfTasks: Pagination response with TaskShort items
- GetListOfTasksResponse: Response wrapper with data field

This follows the same pattern as other list endpoints (builds, runs, etc.).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The GetOpenApiResponse schema was a "meta-schema" that attempted to
define the full structure of an OpenAPI 3.x document, including nested
definitions for paths, components, schemas, requestBody, responses, etc.

This caused code generators (like datamodel-codegen) to produce ~40
unnecessary intermediate classes (Schema1-6, Properties1-2, Post1-2,
Paths, Content1-3, RequestBody1-2, etc.).

Since the endpoint simply returns a standard OpenAPI document, there's
no need to re-define the OpenAPI specification structure. The simplified
inline schema (`type: object` with description) is sufficient for
documentation and doesn't cause code generation bloat.

Removed files:
- GetOpenApiResponse.yaml
- RunsResponseSchemaDataProperties.yaml

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The `folder` property was defined as `type: boolean` with `enum: [true]`,
which caused code generators to create a strange `Folder` enum class with
only one value (`BOOLEAN_TRUE = True`).

Since `folder: true` as a plain boolean is sufficient to indicate that an
item is a folder (as opposed to a file), the enum constraint is unnecessary.

Added descriptions to clarify the schema's purpose and field meanings.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove "Get" prefix from response schema names and consolidate duplicate
response wrappers for consistent naming convention.

Changes:
- Rename Get*Response schemas to *Response (e.g., GetRunResponse → RunResponse)
- Rename GetListOf*Response to ListOf*Response
- Merge duplicate response wrappers (Create/Get/Update*Response → *Response)
  for Actor, Build, Dataset, KeyValueStore, RequestQueue, Task, Webhook
- Update all path file references to use new schema names

This reduces redundancy and establishes a clear naming pattern:
- Single object responses: {Object}Response
- List responses: ListOf{Objects}Response

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Consolidate identical schema definitions to reduce redundancy:

- Remove MonthlyUsageCycle.yaml (identical to UsageCycle.yaml)
  - Update AccountLimits.yaml to reference UsageCycle instead

- Remove CreateOrUpdateEnvVarRequest.yaml (identical to EnvVar.yaml)
  - Update env-vars path files to reference EnvVar for request bodies

Both removed schemas had exactly the same fields as their counterparts,
creating unnecessary duplication in the generated Python models.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refactor ListOfSchedules and ListOfStoreActors to extend
PaginationResponse using allOf instead of duplicating the
pagination fields (total, offset, limit, desc, count).

This makes them consistent with other list schemas like
ListOfActors, ListOfWebhooks, ListOfBuilds, etc.

Note: ListOfVersions and ListOfEnvVars intentionally use
simplified pagination (only total + items) as their API
endpoints don't support offset/limit/desc parameters.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove `format: ipv4` constraint to use plain string type
- Make clientIp and userAgent nullable (matching RunMeta pattern)
- Add descriptions for consistency with RunMeta

This ensures BuildsMeta.clientIp uses `str | None` instead of
`IPv4Address | None`, matching RunMeta and supporting IPv6 addresses.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Both Actor runs and builds share the same origin values (DEVELOPMENT, WEB,
API, CLI, SCHEDULER, WEBHOOK, ACTOR, STANDBY). This change makes BuildsMeta
reference the existing RunOrigin enum for type consistency, replacing the
previous untyped string field.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create WebhookDispatchStatus enum with SUCCEEDED and FAILED values
- Update WebhookDispatch.status to use the new enum
- Update WebhookDispatch.eventType to reference existing WebhookEventType enum
- Update ExampleWebhookDispatch.status to use WebhookDispatchStatus

This improves type safety by replacing untyped string fields with proper enums.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create ScheduleActionType enum with RUN_ACTOR and RUN_ACTOR_TASK values
- Update ScheduleAction.type to use the new enum
- Update ScheduleActions.type to use the new enum
- Update ScheduleCreateActions.type to use the new enum

This improves type safety by replacing untyped string fields with a proper enum.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vdusek vdusek self-assigned this Jan 30, 2026
@vdusek vdusek added t-tooling Issues with this label are in the ownership of the tooling team. adhoc Ad-hoc unplanned task added during the sprint. labels Jan 30, 2026
@vdusek vdusek added this to the 133rd sprint - Tooling team milestone Jan 30, 2026
@apify-service-account
Copy link

Preview for this PR was built for commit c08ee0e and is ready at https://pr-2212.preview.docs.apify.com!

@apify-service-account
Copy link

Preview for this PR was built for commit 2fbb154 and is ready at https://pr-2212.preview.docs.apify.com!

@apify-service-account
Copy link

Preview for this PR was built for commit 541458a and is ready at https://pr-2212.preview.docs.apify.com!

Copy link
Member

@fnesveda fnesveda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, great job, this is a massive improvement 🚀 I had just one tiny note, but otherwise looks good.

What is GetOpenApiResponse.yaml supposed to represent?

This is supposed to represent the OpenAPI schema of how to use the given Actor build. More info about that here: https://github.com/apify/apify-core/issues/18314

I don't think it's necessary to have the whole OpenAPI schema nested here if it makes the codegen complicated, I'm fine with it being a raw object.

The field DATA_TRANSFER_EXTERNAL_GBYTES? includes a question mark, is that intentional?

That must be a bug, I don't see a reason why the question mark should be there. Optionality / nullability is handled in a different way in OpenAPI.

Is ActorDefinition.default_memory_mbytes intentionally defined as int or str?

Yeah, instead of having to "hardcode" a number there, you can now also use an expression which determines the memory for the run, e.g. get(input, startUrls.length, 1) * 1024.

Is WebhookDispatchList.data intentionally optional? It seems to be the only optional data field.

I think that's wrong, data is always there, even if there are no dispatches.

Please verify WebhookDispatchStatus; it is based only on observed API responses in tests.

Verified, it's correct.

Is WebhookEventType now correct with the TEST value?

Verified, it's correct.

@@ -1,4 +1,5 @@
title: DatasetResponse
description: Response containing dataset data.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds like it's the data in the dataset, rather than its metadata.

Copy link
Contributor

@janbuchar janbuchar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, take a green tick mark! Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

adhoc Ad-hoc unplanned task added during the sprint. t-tooling Issues with this label are in the ownership of the tooling team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ensure OpenAPI specs can serve as a reliable source of truth for typed client generation

5 participants