microsoftgraph / msgraph-sdk-go

Microsoft Graph SDK for Go
https://docs.microsoft.com/en-us/graph/sdks/sdks-overview
MIT License
240 stars 37 forks source link

Snippet generation should lead to use with url for next and skip tokens parameters in url #796

Open franciscoandrade82 opened 2 weeks ago

franciscoandrade82 commented 2 weeks ago

Describe the bug

I’m trying to query users with the Delta API in the Go SDK, but examples in Microsoft documentation don’t match available SDK entities.

Detailed Description:

From the Microsoft Delta Query Documentation:

// Documentation example for Delta queries
import (
    "context"
    msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go"
    graphusers "github.com/microsoftgraph/msgraph-sdk-go/users"
)

requestSkiptoken := "oEBwdSP6uehIAxQOWq_3Ksh_TLol6KIm3stvdc6hGhZRi1hQ7Spe__dpvm3U4zReE4CYXC2zOtaKdi7KHlUtC2CbRiBIUwOxPKLa"

requestParameters := &graphusers.UsersDeltaWithRequestBuilderGetQueryParameters{
    Skiptoken: &requestSkiptoken,
}
configuration := &graphusers.UsersDeltaWithRequestBuilderGetRequestConfiguration{
    QueryParameters: requestParameters,
}

delta, err := graphClient.Users().Delta().GetAsDeltaGetResponse(context.Background(), configuration)

In the SDK, UsersDeltaWithRequestBuilderGetQueryParameters isn’t available. The closest alternative, DeltaRequestBuilderGetQueryParameters, lacks a Skiptoken field:

type DeltaRequestBuilderGetQueryParameters struct {
    Count *bool `uriparametername:"%24count"`
    Expand []string `uriparametername:"%24expand"`
    Filter *string `uriparametername:"%24filter"`
    Orderby []string `uriparametername:"%24orderby"`
    Search *string `uriparametername:"%24search"`
    Select []string `uriparametername:"%24select"`
    Skip *int32 `uriparametername:"%24skip"`
    Top *int32 `uriparametername:"%24top"`
}

Additional Attempt:

I tried direct request configuration using the following code, but without success:

response, err := graphClient.GetClient().GetAdapter().Send(ctx, requestInfo, models.CreateUserCollectionResponseFromDiscriminatorValue, nil)
if err != nil {
    log.Fatalf("Error making direct request: %v", err)
}

Without access to Skiptoken or guidance on retrieving deltaToken, it’s challenging to perform delta queries effectively.

Expected behavior

The Go SDK should provide delta query support equivalent to the documentation examples, including options for Skiptoken and deltaToken handling. This would allow developers to correctly paginate through delta queries and manage state with each request, ensuring alignment with other Microsoft Graph SDKs.

How to reproduce

How to Reproduce:

  1. Set up a graphClient in Go using the Microsoft Graph Go SDK.
  2. Attempt a Delta query to list users using the following configuration in your code:
requestParameters := &graphusers.UsersDeltaWithRequestBuilderGetQueryParameters{
    Skiptoken: &requestSkiptoken, // Expecting Skiptoken field here
}
configuration := &graphusers.UsersDeltaWithRequestBuilderGetRequestConfiguration{
    QueryParameters: requestParameters,
}
delta, err := graphClient.Users().Delta().GetAsDeltaGetResponse(context.Background(), configuration)
  1. Observe that UsersDeltaWithRequestBuilderGetQueryParameters is missing in the SDK, and Skiptoken cannot be added.

SDK Version

1.51.0

Latest version known to work for scenario above?

No response

Known Workarounds

No response

Debug output

Click to expand log ``` ```

Configuration

No response

Other information

No response

Shaka-Man commented 6 days ago

This appears to be a common thread throughout the SDK and the Graph Explorer code generator. Here is another example:

`import ( "context" abstractions "github.com/microsoft/kiota-abstractions-go" msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go" graphusers "github.com/microsoftgraph/msgraph-sdk-go/users" //other-imports )

headers := abstractions.NewRequestHeaders() headers.Add("Prefer", "outlook.body-content-type=\"text\"")

requestParameters := &graphusers.UserItemMailFolderItemMessagesDeltaWithRequestBuilderGetQueryParameters{ Skiptoken: &requestSkiptoken, } configuration := &graphusers.UserItemMailFolderItemMessagesDeltaWithRequestBuilderGetRequestConfiguration{ Headers: headers, QueryParameters: requestParameters, }

delta, err := graphClient.Users().ByUserId("user-id").MailFolders().ByMailFolderId("mailFolder-id").Messages().Delta().GetAsDeltaGetResponse(context.Background(), configuration) `

As well as the similar results for deltatoken:

`import ( "context" msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go" graphusers "github.com/microsoftgraph/msgraph-sdk-go/users" //other-imports )

requestParameters := &graphusers.UserItemMailFolderItemMessagesDeltaWithRequestBuilderGetQueryParameters{ Deltatoken: &requestDeltatoken, } configuration := &graphusers.UserItemMailFolderItemMessagesDeltaWithRequestBuilderGetRequestConfiguration{ QueryParameters: requestParameters, }

delta, err := graphClient.Users().ByUserId("user-id").MailFolders().ByMailFolderId("mailFolder-id").Messages().Delta().GetAsDeltaGetResponse(context.Background(), configuration) `

They result in Go complaining that SkipToken and DeltaToken are undefined.

baywet commented 5 days ago

Hi everyone, Thank you for using the SDK and for reaching out.

This is an issue with the code snippets generation logic, it needs to be special cased. The guidance is for client to treat next and delta links as opaque and NOT to attempt at parsing them in case the format changes in the future.

Instead, the SDK allows using a raw URL to build the request like so:

graphClient.Users().Delta().WithUrl("https://previousLink").GetAsDeltaGetResponse(context.Background(), configuration)

You can also use the page iterator

Let us know if you have any additional comments or questions.

@rkodev to special case the snippet generation across languages in DevX API

franciscoandrade82 commented 4 days ago

Hello! Thank you for your reply.

I am using this example to iterate through the users, and I will change it to use the delta when resuming the list. I want to query my users every 5 minutes, so the function needs to return the delta for the next iteration.

The problem is that both DeltaLink and NextLink are nil in the iterator. Can you please help?

func GetAllUsers(graphClient *client.GraphClient, pageSize int32) {
    // Set query parameters for the request
    query := graphusers.DeltaRequestBuilderGetQueryParameters{
        Select: []string{"displayName"}, // we only want to fetch the display name of users
        Top:    &pageSize,
    }

    // Set request configuration options
    options := graphusers.DeltaRequestBuilderGetRequestConfiguration{
        QueryParameters: &query,
    }

    // Fetch users from the Graph API
    users, err := graphClient.GetClient().Users().Delta().Get(context.Background(), &options)
    if err != nil {
        log.Fatalf("failed to fetch users: %v", err)
    }

    // Initialize page iterator
    pageIterator, err := graphcore.NewPageIterator[*graphmodels.User](
        users,
        graphClient.GetClient().GetAdapter(),
        graphmodels.CreateUserCollectionResponseFromDiscriminatorValue) //CreateMessageCollectionResponseFromDiscriminatorValue)
    if err != nil {
        log.Fatalf("Error creating page iterator: %v\n", err)
    }

    // Add custom headers to the iterator
    headers := abstractions.NewRequestHeaders()
    headers.Add("Prefer", "outlook.body-content-type=\"text\"")
    pageIterator.SetHeaders(headers)

    // Iterate over all pages
    err = pageIterator.Iterate(
        context.Background(),
        func(user *graphmodels.User) bool {
            fmt.Printf("%s\n", *user.GetDisplayName())
            // Return true to continue the iteration
            return true
        })
    if err != nil {
        log.Fatalf("Error iterating over messages: %v\n", err)
    }

    fmt.Println(pageIterator.GetOdataDeltaLink()) // returns nil
    fmt.Println(pageIterator.GetOdataNextLink())  // returns nil
}

Thank you!

baywet commented 3 days ago

Thank you for the additional information.

Can you pass CreateUsersDeltaGetResponseFromDiscriminatorValue instead of CreateUserCollectionResponseFromDiscriminatorValue and see if you get a delta link please?

franciscoandrade82 commented 3 days ago

Hello @baywet,

Thank you for the suggestion.

The CreateUsersDeltaGetResponseFromDiscriminatorValue is unavailable, at least in the models or users packages. I can only find it in education.

image

franciscoandrade82 commented 3 days ago

Well, but it worked!

import (
    grapheducation "github.com/microsoftgraph/msgraph-sdk-go/education"
)

...

pageIterator, err := graphcore.NewPageIterator[*graphmodels.User](
        users,
        graphClient.GetClient().GetAdapter(),
        //graphmodels.CreateUserCollectionResponseFromDiscriminatorValue) //CreateMessageCollectionResponseFromDiscriminatorValue)
        grapheducation.CreateUsersDeltaGetResponseFromDiscriminatorValue)
    if err != nil {
        log.Fatalf("Error creating page iterator: %v\n", err)
    }

The GetOdataDeltaLink is not nil!

Thank @baywet