Skip to content

[views] /v1 views API contract (review aid for #694, not for merge) - #702

Draft
ruolin59 wants to merge 1 commit into
linkedin:mainfrom
ruolin59:rufan-linkedin-views-api-contract-only
Draft

[views] /v1 views API contract (review aid for #694, not for merge)#702
ruolin59 wants to merge 1 commit into
linkedin:mainfrom
ruolin59:rufan-linkedin-views-api-contract-only

Conversation

@ruolin59

@ruolin59 ruolin59 commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Important

This PR is a reading aid, not a merge candidate. #694 is the change under review and the one that would merge. This branch reproduces only the API definition from it — the endpoints and the wire models — so the surface can be read without the surrounding implementation. Please leave review comments on #694 unless they're specifically about the shape of these files.

Extracted from #694 in response to the feedback that 5k lines gets a shallow review. 573 lines across eight files, no validator, no service logic, no test suite.

The endpoints

ViewsController — the five routes under /v1/databases/{databaseId}/views:

Verb Path Success Privilege
POST /views 201 CREATE_VIEW
GET /views/{viewId} 200 SELECT
PUT /views/{viewId} 200, or 201 on create UPDATE_VIEW_METADATA
GET /views 200, paginated LIST_VIEW
DELETE /views/{viewId} 204 DELETE_VIEW

ViewsApiHandler — the interface the controller delegates to, included so the endpoint-to-handler contract is legible.

The wire models

CreateUpdateViewRequestBodyviewId, databaseId, clusterId, schema, representations, sourceDialect, defaultCatalog, defaultNamespace, viewProperties, baseViewVersion. representations is a list of ViewRepresentation {type, sql, dialect} rather than a scalar sql field, so a second dialect can be added later without changing the shape.

GetViewResponseBody — the pointer and row-backed identity. SQL, schema and history stay in the Iceberg metadata file, which the client already reads through its own FileIO.

GetAllViewsResponseBody — paginated from the first release, reusing GetViewResponseBody for its elements populated with identifiers only. Views only ever expose a paginated list.

ViewErrorCode — all fourteen failure modes declared now, including the ones M1 never emits, so later milestones add behaviour without changing the enum. It selects an HTTP status and is never serialized; the shared ErrorResponseBody is untouched.

Privileges gains CREATE_VIEW, LIST_VIEW, UPDATE_VIEW_METADATA, DELETE_VIEW; single-view reads reuse SELECT.

Where the rest lives

Everything else is in #694 and is not duplicated here:

ViewApiContractTest freezes every field set and JSON key set above
OpenHouseViewsApiHandler the handler implementation
OpenHouseViewsApiValidator structural validation
ViewsService / ViewsDisabledService the stubbed service seam
ViewDto, ViewsMapper internal model and mapping
audit redaction, dialect config, exception handling

For context on why the contract is shaped this way rather than following the Iceberg REST spec, see the feasibility comparison and the discussion on #694.

@ruolin59
ruolin59 force-pushed the rufan-linkedin-views-api-contract-only branch from 695133c to ce637f5 Compare August 28, 2026 23:00
@ruolin59 ruolin59 changed the title [views] Add the /v2 views API contract and freeze it [views] /v2 views API contract (review aid for #694, not for merge) Aug 28, 2026
@ruolin59
ruolin59 marked this pull request as draft August 28, 2026 23:01
@ruolin59
ruolin59 force-pushed the rufan-linkedin-views-api-contract-only branch from ce637f5 to 86dfc9e Compare September 1, 2026 23:10
@ruolin59 ruolin59 changed the title [views] /v2 views API contract (review aid for #694, not for merge) [views] /v1 views API contract (review aid for #694, not for merge) Sep 1, 2026
…merge)

Extracted from linkedin#694 so the wire contract and endpoint surface can be read
on their own. This branch is a reading aid: linkedin#694 remains the change under
review and the one that would merge. Only the API definition is
reproduced here; the validator, service seam, mappers, audit redaction
and the full test suite all stay in linkedin#694.

  ViewsController exposes the five routes under
  /v1/databases/{databaseId}/views: POST (201), GET item (200),
  PUT (200 or 201), GET collection (200, paginated), DELETE (204), with
  the status codes and view privileges each declares.

  ViewsApiHandler is the interface the controller delegates to, kept here
  so the endpoint-to-handler contract is legible.

  CreateUpdateViewRequestBody carries viewId, databaseId, clusterId,
  schema, representations, sourceDialect, defaultCatalog,
  defaultNamespace, viewProperties and baseViewVersion. representations
  is a list of ViewRepresentation {type, sql, dialect} rather than a
  scalar sql field, so a second dialect can be added later without
  changing the shape.

  GetViewResponseBody carries the pointer and row-backed identity only.
  SQL, schema and history stay in the Iceberg metadata file, which the
  client already reads through its own FileIO.

  GetAllViewsResponseBody is paginated from the first release and reuses
  GetViewResponseBody for its elements, populated with identifiers only.
  Views only ever expose a paginated list.

  ViewErrorCode declares all fourteen failure modes now, including the
  ones this milestone never emits, so later work adds behaviour without
  changing the enum. It selects an HTTP status and is never serialized.

  Privileges gains CREATE_VIEW, LIST_VIEW, UPDATE_VIEW_METADATA and
  DELETE_VIEW; single-view reads reuse SELECT.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@ruolin59
ruolin59 force-pushed the rufan-linkedin-views-api-contract-only branch from 86dfc9e to 35caf18 Compare September 9, 2026 20:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant