KevinDockx / JsonPatch

JSON Patch (JsonPatchDocument) RFC 6902 implementation for .NET
MIT License
174 stars 28 forks source link

JSONPatch WCF REST API getting invalid payload error #79

Closed KavyaShetty closed 7 years ago

KavyaShetty commented 7 years ago

I am trying to use JSONPatch in my WCF REST API(ASP.NET v4.5). My operation contract is as below:-

[OperationContract]
[WebInvoke(UriTemplate = "/{raceId}/participants", Method = "PATCH")]
void UpdateRace(string id, JsonPatchDocument<ParticipantContract[]> participantsContract);

And implementation as follows:-

public void UpdateRace(string id, JsonPatchDocument<ParticipantContract[]> participantsContract)
{
    //Someoperation
}

My data is like the below format where I want to perform add, update delete, move and swap operations on the participants array.

{
    "raceId" : 1
    "participants": [
        {
            "id": "abc",
            "car": "Mercedes",
            "model": "F1 W08 EQ Power",
            "teamname": "Mercedes-AMG Petronas Motorsport",
            "driver": {
                "id": "111",
                "firstname": "Lewis",
                "lastname": "Hamilton",
                "age": "29"
            },
            "codriver": {
                "id": "222",
                "firstname": "Valtteri",
                "lastname": "Bottas",
                "age": "32"
            }
        },
        {
            "id": "def",
            "car": "Ferrari",
            "model": "SF70H",
            "teamname": "Scuderia Ferrari",
            "driver": {
                "id": "333",
                "firstname": "Sebastian",
                "lastname": "Vettel",
                "age": "30"
            },
            "codriver": {
                "id": "444",
                "firstname": "Kimi",
                "lastname": "Räikkönen",
                "age": "37"
            }
        }
    ]
}

On JSON deserialization I am getting below error:-

{
    "summary": "Bad Request",
    "details": "Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'ParticipantContract' because the type requires a JSON object (e.g. {\"name\":\"value\"}) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON object (e.g. {\"name\":\"value\"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.\r\nPath '', line 1, position 1."
}

Can you help me with what I am missing in this?

KevinDockx commented 7 years ago

Could you try defining a jsonpatchdoc on Race instead of on an array of ParticipantContract? In that, you could then update the contracts for that race.

KavyaShetty commented 7 years ago

I have updated as below:-

[OperationContract]
[WebInvoke(UriTemplate = "/{raceId}/participants", Method = "PATCH")]
void UpdateRace(string id, JsonPatchDocument<RaceContract> raceContract);

And implementation as follows:-

public void UpdateRace(string id, JsonPatchDocument<RaceContract> raceContract)
{
            var raceData = GetRaceContract(id);
            raceContract.ApplyTo(raceData);
            UpdateRace(id, raceData)            
}

My Postman request payload is as below:-

[
    {
        "op": "replace",
        "path": "/participants/1",
        "value": {
            "driver": {
                "firstname": "Daniel",
                "lastname": "Ricciardo"
            }
        }
    }
]

I do not want to fire seperate replace for each entity. But I am getting below error:-

{
    "summary": "Internal Server Error",
    "details": "Unexpected server error. Please contact your administrator with error id: 053b7045-65c3-4f16-8654-564ff78a9680",
    "stackTrace": "Collection was of a fixed size.\r\n   at System.Array.System.Collections.IList.RemoveAt(Int32 index)\r\n   at Marvin.JsonPatch.Adapters.ObjectAdapter`1.Remove(String path, T objectToApplyTo, Operation`1 operationToReport)\r\n   at Marvin.JsonPatch.Adapters.ObjectAdapter`1.Replace(Operation`1 operation, T objectToApplyTo)\r\n   at Marvin.JsonPatch.JsonPatchDocument`1.ApplyTo(T objectToApplyTo, IObjectAdapter`1 adapter)\r\n "
}

I am expecting my data to be updated as:-

{
    "raceId" : 1
    "participants": [
        {
            "id": "abc",
            "car": "Mercedes",
            "model": "F1 W08 EQ Power",
            "teamname": "Mercedes-AMG Petronas Motorsport",
            "driver": {
                "id": "111",
                "firstname": "Lewis",
                "lastname": "Hamilton",
                "age": "29"
            },
            "codriver": {
                "id": "222",
                "firstname": "Valtteri",
                "lastname": "Bottas",
                "age": "32"
            }
        },
        {
            "id": "def",
            "car": "Ferrari",
            "model": "SF70H",
            "teamname": "Scuderia Ferrari",
            "driver": {
                "id": "333",
        "firstname": "Daniel",
        "lastname": "Ricciardo",
                "age": "30"
            },
            "codriver": {
                "id": "444",
                "firstname": "Kimi",
                "lastname": "Räikkönen",
                "age": "37"
            }
        }
    ]
}
KavyaShetty commented 7 years ago

Any thoughts on the above error?

KevinDockx commented 7 years ago

What's the underlying type you're trying to patch? If I look at the error, it seems it's an array (which has a fixed size). To those, you cannot add objects to / remove objects from, as it would change the size of the array. Could you try working on a List?

kavya-xpx commented 7 years ago

My RaceContract has a large set of DataMembers that are arrays. And it is being already consumed in a variety of operations. Changing each and every datamember to array won't be possible. Any other suggestion so that the other functionalities do not get impacted?

KevinDockx commented 7 years ago

As long as it's an array (fixed size), the patch won't be able to manipulate the size of the array, so I'm afraid the scenario you're trying to achieve isn't possible without changes those classes...

KevinDockx commented 7 years ago

I'll close this as it seems to be solved - if it needs to be reopened, just ask :)