fix: OpenAPI spec inconsistencies and documentation gaps in PublishingResource (/api/v1/publishing)
@fmontes is already working on this.
Since Mar 4, 2026.
- #34910 by @hassandotcms — closed without merging
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Summary
A review of the OpenAPI annotations in PublishingResource.java and its associated form/view classes revealed 10 issues ranging from spec-vs-implementation mismatches (confirmed by curl tests) to missing schema metadata that breaks code generation and Swagger UI usability.
Affected file: dotCMS/src/main/java/com/dotcms/rest/api/v1/publishing/PublishingResource.java and related files in the same package (PushBundleForm, AbstractRetryBundlesForm, AbstractRetryBundleResultView, AbstractPublishingJobView, AbstractPublishingJobDetailView, AbstractEndpointDetailView).
Findings
HIGH — Spec vs. Implementation mismatches (confirmed by curl tests)
1. status query params lack machine-readable allowableValues
- Affects:
GET /api/v1/publishing?status=andDELETE /api/v1/publishing/purge?status= - Valid values are listed as prose text only. Swagger UI won't render a dropdown and codegen tools won't produce enums.
- Fix: Add
@Schema(allowableValues = {...})with all validPublishAuditStatus.Statusnames, or change toList<String>with collection format.
2. DELETE /{bundleId} — 404 documented but never returned
- Confirmed by TC-3.1 and TC-3.3: deleting a non-existent bundle returns
200 {"message":"Bundle deleted successfully"}instead of404. @ApiResponse(responseCode = "404")is unreachable —deleteBundleAndDependenciessucceeds silently for unknown IDs.- Fix: Return 404 when neither audit nor bundle table contains the ID (correct fix), or remove the 404 response from the spec.
3. POST /push/{bundleId} — validation order causes wrong status codes
- Confirmed by TC-5.9, TC-5.10, TC-5.15, TC-5.17: requests with invalid date format, invalid
filterKey, or uppercaseoperationreturn404(bundle not found) instead of400, becauseparseISO8601DateandfilterKeylookup run after the bundle existence check. - The spec documents
400for these cases but the implementation returns404when the bundle is missing. - Fix: Move date-format parsing and filterKey validation into
form.checkValid()before the bundle lookup.
MEDIUM — Missing schema metadata
4. POST /retry — deliveryStrategy missing allowableValues and case-sensitivity note
AbstractRetryBundlesForm.deliveryStrategy()doesn't list allowed values or state that the enum is case-sensitive (TC-4.13:"all_endpoints"returns 400).- Fix: Add
allowableValues = {"ALL_ENDPOINTS", "FAILED_ENDPOINTS"}anddefaultValue = "ALL_ENDPOINTS".
5. POST /push/{bundleId} — operation case-insensitivity not documented
PushBundleFormdoesoperation.toLowerCase(), makingoperationcase-insensitive. ButdeliveryStrategyin retry is case-sensitive. The docs treat both identically.- Fix: Add "Case-insensitive." to the
operationdescription. Consider makingdeliveryStrategycase-insensitive too for consistency.
6. PushBundleForm date fields — missing format and no timezone-required note
publishDate/expireDatelackformat = "date-time". The docs don't state that timezone offset is mandatory — a date without offset (e.g.,"2025-12-01T10:00:00") fails (confirmed by TC-5.10).- Fix: Add
format = "date-time"and note timezone offset is required.
7. filterKey absent from list and detail views
AbstractPublishingJobViewandAbstractPublishingJobDetailViewexposefilterName(display label) but notfilterKey(the value needed for API calls).- A developer viewing a job has no way to know which
filterKeyto pass toPOST /push/{bundleId}to reproduce the push. - Fix: Add
filterKeyfield toAbstractPublishingJobDetailViewat minimum.
LOW — Minor doc improvements
8. DELETE /purge — async completion mechanism not explained for API clients
- The 200 description says "processes in background" but doesn't explain how results are delivered (dotCMS system message/WebSocket). Non-browser clients will never receive the completion notification.
- Fix: Add to the description: "The result is delivered as a system notification to the triggering user's browser session. Non-browser API clients will not receive the completion event."
9. bundleId path param example uses wrong format
@Parameter(example = "f3d9a4b7-staging-bundle-2026-01-15")doesn't match real bundle IDs which are ULID format (e.g.,01KJWNJM2C67DM56GHBJ4S7B89).- Fix: Update examples to ULID format.
10. EndpointDetailView.port — no format constraint on required string
port()isString+requiredMode = REQUIREDbut accepts"". No pattern or range documented.- Fix: Add a note on valid values or a pattern constraint.
Steps to reproduce (bug items)
BASE="http://localhost:7070"
TOKEN="<valid-backend-token>"
MISSING_BUNDLE="01KJWNJM2C67DM56GHBJ4S7B89"
# Bug 2 - DELETE non-existent bundle returns 200 instead of 404
curl -s -w "\nHTTP %{http_code}" -X DELETE \
-H "Authorization: Bearer $TOKEN" \
"$BASE/api/v1/publishing/$MISSING_BUNDLE"
# Expected: 404 Actual: 200
# Bug 3 - Invalid date format returns 404 instead of 400
curl -s -w "\nHTTP %{http_code}" -X POST \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"operation":"publish","publishDate":"2025/12/01 10:00:00","environments":["env-id"],"filterKey":"ForcePush.yml"}' \
"$BASE/api/v1/publishing/push/$MISSING_BUNDLE"
# Expected: 400 Actual: 404
Acceptance Criteria
-
DELETE /{bundleId}returns 404 when the bundle does not exist in either audit or bundle table - All input validation in
pushBundle(date format, filterKey, operation) runs before the bundle existence check -
statusquery parameters on GET list and DELETE purge have machine-readableallowableValues -
deliveryStrategyinRetryBundlesFormhasallowableValuesand case-sensitivity documented -
operationinPushBundleFormhas case-insensitivity documented -
publishDate/expireDateannotated withformat = "date-time"and timezone requirement stated -
filterKeyexposed inPublishingJobDetailView - Purge async behavior documented for non-browser clients
-
bundleIdexamples updated to ULID format -
EndpointDetailView.porthas format/constraint documented
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.