Skip to content

feat: listvalues endpoint WIP#875

Open
divysinghvi wants to merge 1 commit intokubeflow:notebooks-v2from
divysinghvi:feat/stub-listvalues-endpoint
Open

feat: listvalues endpoint WIP#875
divysinghvi wants to merge 1 commit intokubeflow:notebooks-v2from
divysinghvi:feat/stub-listvalues-endpoint

Conversation

@divysinghvi
Copy link

@divysinghvi divysinghvi commented Jan 31, 2026

Stub /listvalues endpoint (#691)

Implements stub POST /api/v1/workspacekinds/{name}/podtemplate/options/listvalues endpoint.

Changes:

  • Returns filtered imageConfig/podConfig options with rule_effects.ui_hide: false
  • Supports context-based filtering by imageConfig.id and podConfig.id
  • Includes Swagger documentation

Note: Full compatibility selector rules to be implemented in follow-up work.

…#691)

Signed-off-by: Divy Singhvi <divysinghvi5@gmail.com>
@google-oss-prow
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign andyatmiami for approval. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@google-oss-prow google-oss-prow bot added the area/backend area - related to backend components label Jan 31, 2026
@google-oss-prow google-oss-prow bot added area/v2 area - version - kubeflow notebooks v2 size/XL labels Jan 31, 2026
@divysinghvi divysinghvi changed the title Feat: listvalues endpoint WIP feat: listvalues endpoint WIP Jan 31, 2026
Copy link
Contributor

@andyatmiami andyatmiami left a comment

Choose a reason for hiding this comment

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

@divysinghvi

Really appreciate you raising this PR and starting to make real some of the abstract thoughts we have had in this area.

Seeing the code really made me think through what this would look like from a golang perspective - which the API Proposal and guidance I had provided you thus far didn't really speak to (instead really focusing on the JSON structure itself).

As we are still clearly trying to harden and establish "best practices" in this repo - feel free to push back and/or question any of the comments I have made. Happy to continue discussions as necessary to ensure you understand the underlying motivation as well as agree on the outcome.

Look forward to continuing to collaborate and getting this PR eventually merged! 💯

Copy link
Contributor

@andyatmiami andyatmiami Feb 8, 2026

Choose a reason for hiding this comment

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

We should discuss if ListValues is a "good enough" prefix vs. something (sadly wayy more verbose and) specific.

  • ex: PodTemplateOptionsListValues

Hard to know right now - but if/as we add non PodTemplate data structures in the future - its possible ListValues is misleadingly vague.

Choose a reason for hiding this comment

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

@andyatmiami Yes I agree, this will be more detailed even though it is a bit verbose.

Comment on lines +271 to +276
// parse request body
var requestBody models.ListValuesRequest
if err := a.DecodeJSON(r, &requestBody); err != nil {
a.badRequestResponse(w, r, err)
return
}
Copy link
Contributor

Choose a reason for hiding this comment

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

After decoding the request payload - we want to make sure we are validating the contents. Existing codebase strives for a clear/repeatable pattern in how this is accomplished:

  1. Handler Pattern (e.g., secrets_handler.go, workspaces_handler.go)
  // validate the request body
  dataPath := field.NewPath("data")
  if bodyEnvelope.Data == nil {
      valErrs := field.ErrorList{field.Required(dataPath, "data is required")}
      a.failedValidationResponse(w, r, errMsgRequestBodyInvalid, valErrs, nil)
      return
  }
  valErrs = bodyEnvelope.Data.Validate(dataPath)
  if len(valErrs) > 0 {
      a.failedValidationResponse(w, r, errMsgRequestBodyInvalid, valErrs, nil)
      return
  }
  1. Model Validate Pattern (e.g., workspaces/types_write.go)
  func (w *WorkspaceCreate) Validate(prefix *field.Path) []*field.Error {
      var errs []*field.Error

      // validate the workspace name
      namePath := prefix.Child("name")
      errs = append(errs, helper.ValidateWorkspaceName(namePath, w.Name)...)

      // validate nested struct
      podTemplatePath := prefix.Child("podTemplate")
      errs = append(errs, w.PodTemplate.Validate(podTemplatePath)...)

      return errs
  }
  • ℹ️ As your request payload simply acts as filters - your model definitions defined in a types.go is the proper way to be structured!

Copy link
Contributor

Choose a reason for hiding this comment

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

I would follow/adhere to existing patterns when calling DecodeJSON

For instance, in secrets_handler.go (and/or most files) - you see this pattern:

	// parse request body
	bodyEnvelope := &SecretCreateEnvelope{}
	err := a.DecodeJSON(r, bodyEnvelope)
	if err != nil {
		if a.IsMaxBytesError(err) {
			a.requestEntityTooLargeResponse(w, r, err)
			return
		}

		//
		// TODO: handle UnmarshalTypeError and return 422,
		//       decode the paths which were failed to decode (included in the error)
		//       and also do this in the other handlers which decode json
		//
		a.badRequestResponse(w, r, fmt.Errorf("error decoding request body: %w", err))
		return
	}

Lets structure similarly in this PR.

Copy link

@akrem-chabchoub akrem-chabchoub Mar 12, 2026

Choose a reason for hiding this comment

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

Done in #972 (WIP for comments below)

Copy link
Contributor

Choose a reason for hiding this comment

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

This it TOTALLY MY FAULT and I humbly apologize for the oversight, but we use camelCase in our backend API - and I have no idea why I forgot this when originally drafting up the API spec 😢

The following kebab_case attributes should be moved to camelCase:

  • rule_effects -> ruleEffects
  • ui_hide -> uiHide

Choose a reason for hiding this comment

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

Done in #972

}

func buildImageConfigValuesWithRules(imageConfig ImageConfig, context *ListValuesContext) []ImageConfigValueWithRules {
values := []ImageConfigValueWithRules{}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
values := []ImageConfigValueWithRules{}
// Pre-allocate to avoid repeated allocations and copies
values := make([]ImageConfigValueWithRules, 0, len(imageConfig.Values))

Choose a reason for hiding this comment

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

Done in #972

}

func buildPodConfigValuesWithRules(podConfig PodConfig, context *ListValuesContext) []PodConfigValueWithRules {
values := []PodConfigValueWithRules{}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
values := []PodConfigValueWithRules{}
// Pre-allocate to avoid repeated allocations and copies
values := make([]PodConfigValueWithRules, 0, len(podConfig.Values))

Choose a reason for hiding this comment

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

Done in #972

Comment on lines +112 to +120

type ListValuesRequest struct {
Data ListValuesRequestData `json:"data"`
}

type ListValuesRequestData struct {
Context *ListValuesContext `json:"context,omitempty"`
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
type ListValuesRequest struct {
Data ListValuesRequestData `json:"data"`
}
type ListValuesRequestData struct {
Context *ListValuesContext `json:"context,omitempty"`
}
// REMOVE this - it duplicates Envelope
// type ListValuesRequest struct {
// Data ListValuesRequestData `json:"data"`
// }
// KEEP this - it has the "context" field
type ListValuesRequest struct {
Context *ListValuesContext `json:"context,omitempty"`
}

Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Please note that I changed the remaining model here from ListValuesRequestData to ListValuesRequest

In api/workspacekinds_handler.go:

  // Use the standard Envelope pattern wrapping ListValuesRequest
  type ListValuesRequestEnvelope Envelope[*models.ListValuesRequest]

Choose a reason for hiding this comment

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

Done in #972

a.failedValidationResponse(w, r, errMsgPathParamsInvalid, valErrs, nil)
return
}

Copy link
Contributor

Choose a reason for hiding this comment

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

We want to be consistent with the other API endpoints in notebooks-v2.

After path param validation - given we are parsing a request body - we need need to validate content-type here:

	// validate the Content-Type header
	if success := a.ValidateContentType(w, r, MediaTypeJson); !success {
		return
	}

you can see this pattern in effect (for instance) here:

Choose a reason for hiding this comment

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

Done in #972

a.createdResponse(w, r, responseEnvelope, location)
}

// ListValuesHandler returns filtered imageConfig and podConfig options for a WorkspaceKind.
Copy link
Contributor

Choose a reason for hiding this comment

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

Based on other PR review comments I have made - I think we need to update annotations to reflect other 4xx status codes that can be returned:

 //	@Failure		413			{object}	ErrorEnvelope			"Request Entity Too Large. The request body is too large."
//	@Failure		415			{object}	ErrorEnvelope			"Unsupported Media Type. Content-Type header is not correct."
//	@Failure		422			{object}	ErrorEnvelope			"Unprocessable Entity. Validation error."

Choose a reason for hiding this comment

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

Done in #972

Copy link
Contributor

Choose a reason for hiding this comment

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

Given existing pattern we are starting to form (with SecretListItem and WorkspaceListItem - how do you feel about the following naming conventions?

Use <Entity>ListItem pattern for semantic alignment:

  // Consistent with SecretListItem, WorkspaceListItem
  type ImageConfigValueListItem struct {
      ImageConfigValue
      RuleEffects RuleEffects `json:"ruleEffects"`
  }

  type PodConfigValueListItem struct {
      PodConfigValue
      RuleEffects RuleEffects `json:"ruleEffects"`
  }

  // Response structs
  type ImageConfigListResult struct {
      Default string                      `json:"default"`
      Values  []ImageConfigValueListItem  `json:"values"`
  }

  type PodConfigListResult struct {
      Default string                    `json:"default"`
      Values  []PodConfigValueListItem  `json:"values"`
  }

  type ListValuesResponse struct {
      ImageConfig ImageConfigListResult `json:"imageConfig"`
      PodConfig   PodConfigListResult   `json:"podConfig"`
  }

Choose a reason for hiding this comment

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

Done in #972

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

Labels

area/backend area - related to backend components area/v2 area - version - kubeflow notebooks v2 size/XL

Projects

Status: Needs Triage

Development

Successfully merging this pull request may close these issues.

3 participants