Azure / azure-functions-durable-js

JavaScript library for using the Durable Functions bindings
https://www.npmjs.com/package/durable-functions
MIT License
128 stars 46 forks source link

Azure Function CosmosDB input binding is reformatting a string field containing a date and losing precision #518

Open Camios opened 1 year ago

Camios commented 1 year ago

We have a HTTP-triggered Azure Function which has an input binding to return a Doc object deserialized from a Cosmos DB.

Here's the trigger, input and output bindings

[FunctionName("Bar")]
public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Function, "post", Route = "Bar/{partitionKey}/{docId}")] HttpRequest request,
    [CosmosDB(
        databaseName: "db",
    collectionName: "coll",
    ConnectionStringSetting = "CosmosDbReadWriteConnectionString",
    Id = "{docId}",
    PartitionKey = "{partitionKey}")] Doc document,
    [CosmosDB(
        databaseName: "EditorList",
    collectionName: "coll",
    ConnectionStringSetting = "CosmosDbReadWriteConnectionString")] IAsyncCollector<Doc> documentsOut)
public class Doc
{
    //...
    public string CreatedAt {get; set}
    //...
}

Foo has a string CreatedAt property (string for historical reasons) which may be null or have values that are timestamps in the ISO8601 standard including fraction of seconds and timezone. e.g. "2022-03-08T01:18:18.8444397Z"

We expected the string value to be copied unmolested to the object's string property. However, when the object is deserialized the input binding step is (incorrectly) re-formatting the date to "08/03/2022 01:18:18". Worse the data loss is written back to database via the output binding.

I consider it incorrect, because it is losing the fraction of seconds and the timezone (it is now ambiguous about the timezone).

Why is the binding's deserializer doing any reformatting when the input and destination data types are both a string?

I got a colleague to compare this behaviour with what the CosmosDB SDK's DocumentClient does using the Newtonsoft JSON serializer and we found it doesn't reformat the value.

The same colleague also tested changing the input binding type from Foo to dynamic and the re-formatting is not done.

We also tested changing Foo's CreatedAt from string to DateTime and the complete precision of the original string is kept.

The only thing not doing the right thing is the Cosmos binding when a string is the destination field type.

davidmrdavid commented 1 year ago

@hossam-nasr: could you take a look at this one? We should probably sync about this too. I have some context on similar serialization issues.