joukevandermaas / saule

JSON API library for ASP.Net Web API 2.
https://joukevandermaas.github.io/saule
MIT License
76 stars 37 forks source link

Deserialize kebab-cased nested attributes #169

Open atkretsch opened 7 years ago

atkretsch commented 7 years ago

Similar to #131, but for deserialization.

Given the following class structure:

public class Person : ApiResource
    {
        public Person()
        {
            Attribute("Name");
        }

        public Name Name { get; set; }
    }

    public class Name
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

...the following JSON (e.g. in a POST request):

{
    "data": {
        "attributes": {
            "name": {
                "first-name": "John",
                "last-name": "Doe"
            }
        }
    }
}

...will result in a Person class such that person.Name.FirstName == null and person.Name.LastName == null.

However, if the nested attributes are changed to UpperCamelCase (e.g. FirstName and LastName), then the result is correct (e.g. person.Name.FirstName == "John", person.Name.LastName == "Doe"). And when serializing (e.g. in a response), the result has the expected kebab-case (because of #131).

I know many examples of nested objects like this can probably be refactored as relationships, etc., but as discussed in #131 it's sometimes useful to use "value objects" for grouping of closely-related attributes. Additionally, if the default behavior for serialization is to handle kebab-casing all the way down, then it seems reasonable that the same should be true for deserialization for consistency and request/response symmetry.

From poking around the code a bit, it seems like the ResourceDeserializer would have to be changed to recursively call ToFlatStructure() for non-primitive attribute values (similar to what it does for relationships).

joukevandermaas commented 7 years ago

The solution in the serializer was to use this 'contract resolver': https://github.com/joukevandermaas/saule/blob/master/Saule/Serialization/JsonApiContractResolver.cs (see #132).

I'm guessing we could do the same for the deserializer.

atkretsch commented 7 years ago

@joukevandermaas Yes, that makes more sense than my initial idea. If you don't mind I'll take a crack at it and put up a PR.

joukevandermaas commented 7 years ago

That would be great!

esotery commented 7 years ago

Hello gentlemen, any update regarding this issue?:)

joukevandermaas commented 7 years ago

@esotery I'm still very open to a PR!

atkretsch commented 7 years ago

Unfortunately I haven't had time to take another look at this yet. Hoping I will in the near future, but in the meantime, @esotery feel free to do so yourself if you're so inclined!

esotery commented 7 years ago

Fixed. Sorry, It would have been fixed yesterday but the the internet connection dropped out.