API Rant

gregaricangregarican Member Posts: 906 

Now that I am trying to export our LSR data out to move to a different solution this year, I have had to immerse myself back into the API. In this case, exporting out custom product fields. Which we heavily rely upon due to the lack of comprehensive item elements in the base record.

I remembered the known glitch that pretty much breaks traditional REST API best practices. Best practices dictate if an element can be an array, it's always passed back in the JSON response as an array. For example, if a customer can have multiple phone numbers, but only one is defined in their record. Regardless, the response should be an array. In this handicapped REST API implementation, the response is passed back as just a singleton. So a workaround there to handle the either/or array/singleton elements that are so pervasive.

The one gotcha that blew my mind today involves the custom product fields. All items display these in the web UI item view. But if an item doesn't have any field values actually defined, the API response doesn't even pass back an empty set. The custom fields node isn't even present in the API response at all. Another workaround...lol.

3 comments

  • thisconnectthisconnect Member Posts: 28

    hi @gregarican

    you are the one that holds this whole community afloat.

    i hear your rant :-)

    but probably none of the actual lightspeed programmers do...

    what you say about arrays is correct, even the image field of products is this way. you have to first check if the result is an array, before continuing. things you of course only find out when testing with 1 image en later on seeing multiple images in production...

    when will lightspeed finally see the (commercial) importance of a great API?

    this really makes or brakes a SaaS.

    still hoping they will see the light (pun intended)

    this message just as a thank you for being the most helpful member in this community!

  • gregaricangregarican Member Posts: 906 

    Thanks for the kind words! I always believe in karma, in that if I contribute to the community then if I run into some hurdle I can get a quick assist on here. So the reasons might be a bit selfish at times too. 😂

  • gregaricangregarican Member Posts: 906 

    Ran into this %^&*# quirk again. Importing vendor returns out of Retail. Hardly have any of these transactions as a rule, so I forgot that the items included in a vendor return can either be a singleton { } or an array [ { } ] in the API response. So my code choked, needing to yet again wrap my code in a custom handler. For what essentially is the Retail API breaking best practices. I can't stress this enough, whatever _can_ be an array should ALWAYS be passed back in the API response as an array. Even if the element has only a single member.

    If anyone runs into this, below is a C# class for handling it. I'm using the Newtonsoft.JSON package, but you can get the idea as to how to utilize it for other platforms. All I do is include this above any of my JSON model classes ---> [JsonConverter(typeof(JsonHelper.SingleValueArrayConverter<T>))] Where T is the type of element is being evaluated. For an example, a VendorReturn. 😃

    Hope this help anyone trying to workaround the quirks inherent in the Retail API.


        public class SingleValueArrayConverter<T> : JsonConverter

        {

           public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)

          {

             throw new NotImplementedException();

          }


          public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)

          {

             object retVal = new Object();

             if (reader.TokenType == JsonToken.StartObject)

             {

               T instance = (T)serializer.Deserialize(reader, typeof(T));

              retVal = new List<T>() { instance };

             }

             else if (reader.TokenType == JsonToken.StartArray)

             {

               retVal = serializer.Deserialize(reader, objectType);

             }

             return retVal;

          }


          public override bool CanConvert(Type objectType)

          {

             return true;

          }

        }

Sign In or Register to comment.