launchdarkly / api-client-go

LaunchDarkly API Client for Go
Other
8 stars 12 forks source link

PatchSegment Doesn't Support Semantic Patching #14

Closed kwalsh-rz closed 1 year ago

kwalsh-rz commented 1 year ago

Does PatchSegment not support semantic patching? The documentation states that it does but I don't see the operations allowed. Am I misunderstanding? How would I accomplish removing an includedTarget through a JSON patch?

mmrj commented 1 year ago

Hi @kwalsh-rz , thanks for reaching out. Yes, the patchSegment endpoint supports semantic patching, and the operations are hidden in a "twistie" here, https://apidocs.launchdarkly.com/tag/Segments#operation/patchSegment:

patch segment - click to expand instructions

To remove an included target, you can use the removeIncludedTargets instruction.

kwalsh-rz commented 1 year ago

Thanks for the quick response. I'm still not fully understanding though. PatchSegment doesn't support RequestBody the way other methods do, so how do you put the request through? Are there any examples out there using PatchSegment specifically with the Go client?

mmrj commented 1 year ago

There are a couple of things going on here:

// semantic patch
// remember to append ';domain-model=launchdarkly.semanticpatch' 
// to your 'Content-type' header if using this
{
  "instructions": [{
    "kind": "removeIncludedTargets",
    "contextKind": "user",
    "values": [ "sandy" ]
  }]
}
// json patch
{
  "patch": [
    {
      "op": "remove",
      "path": "/included/0" 
// this is a 0-indexed array of the included targets,
// so recommend doing a 'getSegment' first to examine the 'included' array 
// and make sure you're removing the correct target
    }
  ]
}

Apologies for any confusion on this. I initially read your question as being just about finding semantic patch info in the docs and jumped in that direction without providing more background. Let me know if you have any additional questions.

kwalsh-rz commented 1 year ago

Thanks! That clears up part of my confusion, but I still don't understand how I would send across your examples above using the existing clients. Are you saying we just can't do this with the Go client?

If I was to use the JSON patch, I'm still not sure that what you sent above gets to what I need.

if I use this...

// json patch
{
  "patch": [
    {
      "op": "remove",
      "path": "/included/0" 
// this is a 0-indexed array of the included targets,
// so recommend doing a 'getSegment' first to examine the 'included' array 
// and make sure you're removing the correct target
    }
  ]
}

... it will remove all values in the includedContexts embedded 'values' array. I don't see a way to remove a single value from the values array. This specific problem is what led me to open this issue/question in the first place. I didn't see a way to implement it using json patch so I thought semantic would be required.

kwalsh-rz commented 1 year ago

I solved this by first calling GetSegment and figuring out the index of the items that I want to remove. I then used those values in the path of the patch segment. It's not as easy as semantic patching would have been but it works

lucywyman commented 1 year ago

Hi @kwalsh-rz! We definitely recommend using semantic patches for adding or removing targets (from the docs: To add or remove targets from segments, we recommend using semantic patch.) You can use a PatchSegmentInstruction object to send a semantic patch to the Segments API, something like this (copied from this example) should work:

package main

import (
    "context"
    "fmt"
    "os"
    openapiclient "./openapi"
)

func main() {
    projectKey := "projectKey_example" // string | The project key
    environmentKey := "environmentKey_example" // string | The environment key
    segmentKey := "segmentKey_example" // string | The segment key
    patchSegmentRequest := *openapiclient.NewPatchSegmentRequest([]openapiclient.PatchSegmentInstruction{*openapiclient.NewPatchSegmentInstruction("removeIncludedTargets", "ContextKind_example", "my_target")})

    configuration := openapiclient.NewConfiguration()
    apiClient := openapiclient.NewAPIClient(configuration)
    resp, r, err := apiClient.SegmentsApi.PatchExpiringTargetsForSegment(context.Background(), projectKey, environmentKey, segmentKey).PatchSegmentRequest(patchSegmentRequest).Execute()
    if err != nil {
        fmt.Fprintf(os.Stderr, "Error when calling `SegmentsApi.PatchExpiringTargetsForSegment``: %v\n", err)
        fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)
    }
    // response from `PatchExpiringTargetsForSegment`: ExpiringTargetPatchResponse
    fmt.Fprintf(os.Stdout, "Response from `SegmentsApi.PatchExpiringTargetsForSegment`: %v\n", resp)
}

Where this is the main line you care about:

patchSegmentRequest := *openapiclient.NewPatchSegmentRequest(
  []openapiclient.PatchSegmentInstruction{
    *openapiclient.NewPatchSegmentInstruction("removeIncludedTargets", "ContextKind_example", "my_target"),
  },
)