JSON Self referencing loop on POST call

167 views Asked by At

I'm trying to send a POST call via JsonApi with this as example:

{
    "data": {
        "attributes": {
            "booked_by_patient": true,
            "class": "PUBLIC",
            "description": "description",
            "dtend": "2022-03-16T10:30:00+01:00",
            "dtstamp": "2022-03-16T10:01:17+01:00",
            "dtstart": "2022-03-16T10:00:00+01:00",
            "location": "1231, 31311 3131",
            "new_patient": true,
            "referral_source": "",
            "status": "CONFIRMED",
            "summary": "summary",
            "text": "",
            "transp": "OPAQUE",
            "uid": null,
            "first_name": "name",
            "last_name": "last_name",
            "e_mail_address": "[email protected]",
            "phone_number_cell": "+467325324563252"
        },
        "relationships": {
            "clinic": {
                "data": {
                    "id": "2312",
                    "type": "Pizza-clinics"
                }
            },
            "organizer": {
                "data": {
                    "id": "5553",
                    "type": "Pizza-caregivers"
                }
            },
            "procedure": {
                "data": {
                    "id": "1",
                    "type": "Pizza-procedure"
                }
            }
        },
        "type": "Pizza-bookings"
    },
    "include": "booking_attendees.patient"
}

But for starters, I'm getting an error for "Self referencing loop detected for property 'data' with type 'SDKs.Pizza.Model.Clinics'. Path 'data.clinic.data'.

following another suggestion I received that I needed to add a [JsonIgnore] decorator over some models, I have done the following: (decorator over 3 last objects)

public class BookingRequest 
    {
        // public string Id { get; set; }
        public string? Uid { get; set; } = null;

        public string Type { get; } = "pizza_bookings";

        public bool BookedByPatient { get; set; } = true;

        public string Class { get; set; } = "PUBLIC";

        public string Description { get; set; } = null!;
        
        [JsonProperty(PropertyName = "dtstart")]
        public DateTimeOffset Start { get; set; }
        
        [JsonProperty(PropertyName = "dtend")]
        public DateTimeOffset End { get; set; }
        
        [JsonProperty(PropertyName = "dtstamp")]
        public DateTimeOffset Timestamp { get; set; } = DateTimeOffset.UtcNow;

        public string EMailAddress { get; set; } = null!;

        public string FirstName { get; set; } = null!;

        public string LastName { get; set; } = null!;

        public string Location { get; set; } = null!;

        public bool NewPatient { get; set; } = true;

        public string PhoneNumberCell { get; set; } = null!;

        public string ReferralSource { get; set; } = "source";

        public string Status { get; set; } = "CONFIRMED";

        public string Summary { get; set; } = "";

        public string Text { get; set; } = "";

        public string? Transp { get; set; } = "OPAQUE";

        [JsonIgnore]
        public Relationship<Clinics> Clinic { get; set; } = null!;
        [JsonIgnore]
        public Relationship<Caregivers> Organizer { get; set; } = null!;
        [JsonIgnore]
        public Relationship<Procedures> Procedure { get; set; } = null!;
    }

My current POST call is as follows:

public async Task<Booking?> CreateBookingAsync(string clinicId, string caregiverId, string procedureId, string ssn,
            DateTimeOffset start, DateTimeOffset end)
        {
            var uri = "api/pizza-bookings".AddQueryParams(new Dictionary<string, string?> {
                                                ["caregiver_id"] = caregiverId,
                                                ["patient_personal_id"] = swedishPersonalIdentityNumber
                                            }
            );

            var body = new DocumentRoot<BookingRequest>();

            var clinic = new Relationship<Clinics>() {Data = new Clinics() {Id = clinicId}};

            var organizer = new Relationship<Caregivers>() {Data = new Caregivers() {Id = caregiverId}};

            var procedure = new Relationship<Procedures>() {Data = new Procedures() {Id = procedureId}};

            body.Data = new BookingRequest() {
                Start = start,
                End = end,
                EMailAddress = "[email protected]",
                PhoneNumberCell = "123-456-789",
                FirstName = "first-name",
                LastName = "last-name",
                Clinic = clinic,
                Organizer = organizer,
                Procedure = procedure
            };

            return await _http.SendInternalAsync<DocumentRoot<BookingRequest>, Booking>(HttpMethod.Post, uri, body, new Dictionary<string, string>());
            }

the issue that I have here is that if I add the jsonIgnore the code runs, but the JSON I capture from Fiddler is the following:

{
    "data": {
        "type": "pizza_bookings",
        "bookedByPatient": true,
        "class": "PUBLIC",
        "dtstart": "2022-03-17T08:56:00+01:00",
        "dtend": "2022-03-17T09:26:00+01:00",
        "dtstamp": "2022-03-17T07:56:48.3039336+00:00",
        "eMailAddress": "[email protected]",
        "firstName": "first-name",
        "lastName": "last-name",
        "newPatient": true,
        "phoneNumberCell": "123-456-789",
        "referralSource": "source",
        "status": "CONFIRMED",
        "summary": "",
        "text": "",
        "transp": "OPAQUE",
        "clinic": {
            "data": {}
        },
        "organizer": {
            "data": {}
        },
        "procedure": {
            "data": {}
        }
    }
}
1

There are 1 answers

3
Rahul Sharma On BEST ANSWER

You can ignore the self-referencing loops while serializing by using ReferenceLoopHandling.Ignore which will not serialize an object if it is a child object of itself. You can use it by adding it in your serializer settings:

JsonConvert.SerializeObject(body.Data, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore});