GetCouponsForProductFamily API

Mar 20, 2015 at 3:54 AM
I needed to pull my lists of Chargify Products / Components / Coupons into my database, and discovered that Chargify does not publish an API that lets you get a list of your Coupons without already knowing the Coupon name or id in advance.

Well apparently there IS an undocumented API https://subdomain.chargify.com/product_families/{product_family_id}/coupons.format" which will return the list of Coupons for a given ProductFamily.

I implemented the API in my project by inheriting from ChargifyConnect and calling some of the non-public methods using reflection.

Here is the code for the class in VB.NET (porting to C# will be straightforward for anyone who might need it in C#).
Public Class ChargifyConnect
    Inherits ChargifyNET.ChargifyConnect

    Public Sub New(siteUrl As String, apiKey As String, password As String)
        MyBase.New(siteUrl, apiKey, password)
    End Sub

    Public Function GetCouponsForProductFamily(productFamilyId As Integer) As IDictionary(Of Integer, ICoupon)
        Dim DoRequest = GetType(ChargifyNET.ChargifyConnect).GetMethod("DoRequest", BindingFlags.Instance Or BindingFlags.NonPublic, Type.DefaultBinder, New Type() {GetType(String)}, Nothing)
        Dim str = CType(DoRequest.Invoke(Me, New Object() {String.Format("product_families/{0}/coupons.{1}", productFamilyId, If(Me.UseJSON, "json", "xml"))}), String)

        Dim dict = New Dictionary(Of Integer, ICoupon)

        If str.IsXml() Then
            Dim LoadFromNode = GetType(Coupon).GetMethod("LoadFromNode", BindingFlags.Instance Or BindingFlags.NonPublic, Type.DefaultBinder, New Type() {GetType(XmlNode)}, Nothing),
                xmlDocument = New XmlDocument()

            xmlDocument.LoadXml(str)

            If xmlDocument.ChildNodes.Count = 0 Then
                Throw New InvalidOperationException("Returned XML not valid")
            End If

            For Each childNode As XmlNode In xmlDocument.ChildNodes
                If childNode.Name = "coupons" Then
                    For Each xmlNodes As XmlNode In childNode.ChildNodes
                        If xmlNodes.Name = "coupon" Then
                            Dim coupon = New Coupon

                            LoadFromNode.Invoke(coupon, New Object() {xmlNodes})

                            If dict.ContainsKey(Coupon.ID) Then
                                Throw New InvalidOperationException("Duplicate id values detected")
                            End If

                            dict.Add(Coupon.ID, Coupon)
                        End If
                    Next
                End If
            Next
        ElseIf str.IsJSON() Then
            Dim Parse = GetType(JsonArray).GetMethod("Parse", BindingFlags.Static Or BindingFlags.NonPublic, Type.DefaultBinder, New Type() {GetType(String), GetType(Integer).MakeByRefType()}, Nothing),
                dummy = 0,
                index = 0,
                jsonArray = DirectCast(Parse.Invoke(Nothing, New Object() {str, dummy}), JsonArray)

            While index <= jsonArray.Length - 1
                Dim jsonCoupon = TryCast(jsonArray.Items(index), JsonObject)

                If jsonCoupon.ContainsKey("coupon") Then
                    Dim item = TryCast(jsonCoupon("coupon"), JsonObject),
                        coupon = New Coupon(item)

                    If dict.ContainsKey(Coupon.ID) Then
                        Throw New InvalidOperationException("Duplicate ID values detected")
                    End If

                    dict.Add(coupon.ID, coupon)
                End If
                index += 1
            End While
        End If

        Return dict
    End Function

End Class