I'm migrating from the Microsoft.Azure.DocumentDB.Core SDK to the new Microsoft.Azure.Cosmos SDK (version 3.2).
The older SDK returns the ContinuationToken in the ResponseContinuation property and looks like this:
+RID:knNRALdSjOBBAQAAAAAAAA==#RT:1#TRC:10#RTD:fUTWI3DNPK3FpLhdCXlVBTMxMjouMTouMjlVMjg7MTQ7MTkvMTE6ODgyOFsA#ISV:2#IEO:65536#FPC:AgEAAAAKAAyBIwBA3L8PAAQ=
The new SDK returns it in the ContinuationToken property as a JSON string representing a "CompositeToken" object and looks like this:
[{"compositeToken":{"token":"+RID:xS0oAMD5rWYLAAAAAAAAAA==#RT:1#TRC:2#RTD:fUTWI3DNPK3FpLhdCXlVBTMxMjouMTouMzhVMTE7NTc7NDUvNjc2NDozNFsA#ISV:2#IEO:65551#FPC:AQkAAAAAAAAADQAAAAAAAAA=","range":{"min":"","max":"FF"}},"orderByItems":[{"item":"2019-09-27T00:46:34.5653923Z"}],"rid":"xS0oAMD5rWYLAAAAAAAAAA==","skipCount":0,"filter":null}]
When I pull out just the token:
+RID:xS0oAMD5rWYLAAAAAAAAAA==#RT:1#TRC:2#RTD:fUTWI3DNPK3FpLhdCXlVBTMxMjouMTouMzhVMTE7NTc7NDUvNjc2NDozNFsA#ISV:2#IEO:65551#FPC:AQkAAAAAAAAADQAAAAAAAAA=
I get the following error:
Invalid JSON in continuation token +RID:xS0oAMD5rWYLAAAAAAAAAA==#RT:1#TRC:2#RTD:z9path31ttPskBzzyJFdBTQ0NDQ0AA==#ISV:2#IEO:65551#FPC:AQkAAAAAAAAADQAAAAAAAAA= for OrderBy~Context, exception: Unexpected character encountered while parsing value: +. Path '', line 0, position 0.
But if I pass in the entire composite token it works. I'm a little confused since both SDKs are just warppers for using the CosmosDB service so why the difference? I'd like to just use the shorter token object if I can as it is much smaller and easier to manage when exposed as an API. The new CompositeToken is being encoded by Swagger and adds the / character in front of every quote like so:
[{/"compositeToken/":{/"token":/"+RID:xS0oAMD5rWYLAAAAAAAAAA==#RT:1#TRC:2#RTD:fUTWI3DNPK3FpLhdCXlVBTMxMjouMTouMzhVMTE7NTc7NDUvNjc2NDozNFsA#ISV:2#IEO:65551#FPC:AQkAAAAAAAAADQAAAAAAAAA=/",/"range/":{/"min/":/"/",/"max/":/"FF/"}},/"orderByItems/":[{/"item/":/"2019-09-27T00:46:34.5653923Z/"}],/"rid/":/"xS0oAMD5rWYLAAAAAAAAAA==/",/"skipCount/":0,/"filter/":null}]
Which means I have to decode the string properly in order to use it which seems like an additional burdon on API consumers. Am I missing something? There does not seem to be much documentation on what this CompositeToken does with the new SDK and why we have this change.
EDIT
I've found that if I add .Replace("\"", "'") to the returned ContinuationToken in the new SDK I now have a version of the token that my API consumers can use to pass in for the next page since the single quotes won't be automatically encoded. However I am not sure this is the cleanest way to handle it and wanted to get some opinions. Non of the samples in the GitHub project goes into this. I was also wondering what the additional properties such as "range" and "orderByItems" are used for in the composite token as it is not clearly documented.
EDIT 2
Turns out that replacing double quotes with single quotes works when I use Swagger UI but not when I use Postman. Very strange. The same exact call that works in Swagger (using the single quote version of the compositeToken) gives me the following error when I use Postman:
Response status code does not indicate success: 400 Substatus: 0 Reason: (Invalid JSON in continuation token [{'compositeToken':{'token':' RID:xS0oAMD5rWYLAAAAAAAAAA== for OrderBy~Context, exception: Unterminated string. Expected delimiter: '. Path '[0].compositeToken.token', line 1, position 58.).
EDIT 3
Here is how the raw continuationToken looks when it is returned by both SwaggerUI as well as Postman. As you can see the string has double quotes in it so the consumer gets the results with additional backslashes added in the string in order to escape the double quotes. Obviously just passing it back as is results in an invalid JSON error which requires that either the user or the service has to correct for it.
Is there a best practice for managing this? Was also thinking about extracting the just the "token" property and passing that back to the user (as this is what the previous SDK used) and then injecting it back into a CompositeToken string when passed back since it appears as though the remaining properties of the CompositeToken never change (Perhaps this is what the previous SDK did?) - but I am concerned this may break in the future if this format evolves.
EDIT 4
For reference, here is what the continuationToken looked like in the previous SDK:
EDIT 5
I figured out why the token that had the double quotes replaced with single quotes did not work in Postman. It seems there is a known bug where Postman strips out any characters after the first hash symbol on string parameters: https://github.com/postmanlabs/postman-app-support/issues/6023 since there are multiple "#" in the token this will always truncate the input when passed in via Postman as a querystring. Works fine when passed into the body.