microsoft / spring-data-cosmosdb

Access data with Azure Cosmos DB
MIT License
94 stars 64 forks source link

Issue Spring Data Rest #225

Open jannhendrik opened 5 years ago

jannhendrik commented 5 years ago

Hi, Using Spring Boot 2.0.5, Spring Data Rest 2.0.5 and Spring Data CosmosDB 2.0.5

When exposing paged resources and accessing them via RestAPI, paging does not work.

The first page is returned correctly, but onward from the second page an error is returned not a valid DocumentDbPageRequest, because continuation token is null.

If I understand the continuation token mechanism of cosmos db correctly the client of the API needs to receive the token (currently it is not returned) and send it with the request when querying again.

I wouldn't know a way to pass the continuation token through the Spring Data Rest generated endpoints, so this might be an incompatiblity.

Regards Jan

sophiaso commented 5 years ago

Hi @jannhendrik, currently in spring-data-cosmosdb the continuation token is included in the query response and wrapped into the new returned page request. code here

If possible, could you provide a reproducible sample? If too huge, only the essential part might be enough, including dependencies, Repository and controller(if used).

jannhendrik commented 5 years ago

Sorry for answering so late. Please take a look at the following requests against the example project in this repo:

Request curl -X GET \ 'http://localhost:8080/user?page=0&size=1' \ -H 'cache-control: no-cache' Response:

{
    "_embedded": {
        "user": [
            {
                "email": "xxx-xx@xxx.com",
                "name": "myName_1",
                "count": 123,
                "address": {
                    "street": "zixing road",
                    "city": "shanghai"
                },
                "roleList": [
                    {
                        "name": "creator",
                        "cost": 234
                    },
                    {
                        "name": "contributor",
                        "cost": 666
                    }
                ],
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/user/id_1"
                    },
                    "user": {
                        "href": "http://localhost:8080/user/id_1"
                    }
                }
            }
        ]
    },
    "_links": {
        "first": {
            "href": "http://localhost:8080/user?page=0&size=1"
        },
        "self": {
            "href": "http://localhost:8080/user{&sort}",
            "templated": true
        },
        "next": {
            "href": "http://localhost:8080/user?page=1&size=1"
        },
        "last": {
            "href": "http://localhost:8080/user?page=2&size=1"
        },
        "profile": {
            "href": "http://localhost:8080/profile/user"
        },
        "search": {
            "href": "http://localhost:8080/user/search"
        }
    },
    "page": {
        "size": 1,
        "totalElements": 3,
        "totalPages": 3,
        "number": 0
    }
}

Also the same 'user' is also returned for page two.

Request: curl -X GET \ 'http://localhost:8080/user?page=1&size=1' \ -H 'cache-control: no-cache' Resposne: and

{
    "_embedded": {
        "user": [
            {
                "email": "xxx-xx@xxx.com",
                "name": "myName_1", **// should return myName_2**
                "count": 123,
                "address": {
                    "street": "zixing road",
                    "city": "shanghai"
                },
                "roleList": [
                    {
                        "name": "creator",
                        "cost": 234
                    },
                    {
                        "name": "contributor",
                        "cost": 666
                    }
                ],
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/user/id_1"
                    },
                    "user": {
                        "href": "http://localhost:8080/user/id_1"
                    }
                }
            }
        ]
    },
    "_links": {
        "first": {
            "href": "http://localhost:8080/user?page=0&size=1"
        },
        "prev": {
            "href": "http://localhost:8080/user?page=0&size=1"
        },
        "self": {
            "href": "http://localhost:8080/user{&sort}",
            "templated": true
        },
        "next": {
            "href": "http://localhost:8080/user?page=2&size=1"
        },
        "last": {
            "href": "http://localhost:8080/user?page=2&size=1"
        },
        "profile": {
            "href": "http://localhost:8080/profile/user"
        },
        "search": {
            "href": "http://localhost:8080/user/search"
        }
    },
    "page": {
        "size": 1,
        "totalElements": 3,
        "totalPages": 3,
        "number": 1
    }
}

To my understanding the cosmos DB SQL API needs a continuation token to continue any earlier request. So if page > 0 is requested and no continuation token is provided a bad request should be thrown. Also as I stated earlier the continuation token needs to be returned (at least) in 'last' and 'next' page.

Regards Jan

sophiaso commented 5 years ago

Hi @jannhendrik, will check the issue if page > 0 is requested and no continuation token is provided a bad request should be thrown.

About how to use, you can refer one sample about how to use pagination for this spring-data-cosmosdb library.

The pagination query does return the continuation token in response json field requestContinuation:

    "pageable": {
        "sort": {
            "sorted": false,
            "unsorted": true
        },
        "requestContinuation": "-RID:g3c5AIwS92gCAAAAAAAAAA==#RT:1#TRC:1",
        "offset": 0,
        "pageNumber": 0,
        "pageSize": 1,
        "unpaged": false,
        "paged": true
    },
    "last": false,
    "totalPages": 3,
    "totalElements": 3,
    "size": 1,
    "number": 0,
    "sort": {
        "sorted": false,
        "unsorted": true
    },
    "numberOfElements": 1,
    "first": true

For above response, next page can be queried with:

http://localhost:8080/user?page=1&size=1&requestContinuation=-RID%3Ag3c5AIwS92gCAAAAAAAAAA%3D%3D%23RT%3A1%23TRC%3A1

The requestContinuation parameter has to be encoded as special characters exist in the continuation token.

You can write some REST API endpoint as:

    @GetMapping("/user")
    public Page<User> getUsers(DocumentDbPageRequest pageable) {
        return userRepository.findAll(pageable);
    }

The pageable should be a DocumentDbPageRequest in order to process the requestContinuation token.

jannhendrik commented 5 years ago

Okay, but usage with @RestRepository exposed endpoints is not possible? Sorry i should have statet that ealier.

Am Mi., 17. Okt. 2018 um 04:12 Uhr schrieb weiping <notifications@github.com

:

Hi @jannhendrik https://github.com/jannhendrik, will check the issue if page > 0 is requested and no continuation token is provided a bad request should be thrown.

About how to use, you can refer one sample https://github.com/Microsoft/spring-data-cosmosdb/blob/master/samplecode/example/src/main/java/example/springdata/cosmosdb/Application.java#L79-L88 about how to use pagination for this spring-data-cosmosdb library.

The pagination query does return the continuation token in response json field requestContinuation:

"pageable": {
    "sort": {
        "sorted": false,
        "unsorted": true
    },
    "requestContinuation": "-RID:g3c5AIwS92gCAAAAAAAAAA==#RT:1#TRC:1",
    "offset": 0,
    "pageNumber": 0,
    "pageSize": 1,
    "unpaged": false,
    "paged": true
},

For above response, next page can be queried with:

http://localhost:8080/user?page=1&size=1&requestContinuation=-RID%3Ag3c5AIwS92gCAAAAAAAAAA%3D%3D%23RT%3A1%23TRC%3A1

The requestContinuation parameter has to be encoded as special characters exist in the continuation token.

You can write some REST API endpoint as:

@GetMapping("/user")
public Page<User> getUsers(DocumentDbPageRequest pageable) {
    return userRepository.findAll(pageable);
}

The pageable should be a DocumentDbPageRequest in order to process the requestContinuation token.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/Microsoft/spring-data-cosmosdb/issues/225#issuecomment-430464554, or mute the thread https://github.com/notifications/unsubscribe-auth/AGsuTF4-OQKnVF3mov9VOACQVSnSlCoPks5ulpIZgaJpZM4XXYTD .

sophiaso commented 5 years ago

Hi @jannhendrik The @RestRepository is not supported.