GraphQL Kiva API Examples

311 views
Skip to first unread message

Paul Ericksen

unread,
May 13, 2016, 7:41:43 PM5/13/16
to build...@googlegroups.com
This afternoon, I've been playing around with a GraphQL endpoint to query Kiva data.

GraphQL, in many people's opinion, is the successor to REST because of how flexible it is.

Generally a GraphQL API has only one endpoint and then it's up to the developer to describe the shape of the response it wants.

For example, this query:

{
  loan(id: 1052446) {
    id
    name
    basket_amount
    funded_amount
    activity
    sector
    use
    location {
      country_code
    }
    terms {
      scheduled_payments {
        due_date
        amount
      }
    }
    themes
  }
}

returns this: 

{
  "data": {
    "loan": {
      "id": 1052446,
      "name": "Stephen's Group",
      "basket_amount": 0,
      "funded_amount": 50,
      "activity": "Agriculture",
      "sector": "Agriculture",
      "use": "to purchase a solar light, as well as hybrid seeds and fertilizer to improve harvests of maize.",
      "location": {
        "country_code": "KE"
      },
      "terms": {
        "scheduled_payments": [
          {
            "due_date": "2017-01-01T08:00:00Z",
            "amount": 1050
          }
        ]
      },
      "themes": [
        "Green",
        "Rural Exclusion"
      ]
    }
  }
}

Where the API consumer gets to describe what it wants and only gets that.

I have only implemented a sector search at the moment just to get things started, but this query:
{
  loans(sectors:"Education") {
    id
    name
    activity
  }
}

Produces these results:
{
  "data": {
    "loans": [
      {
        "id": 1063117,
        "name": "Wilson",
        "activity": "Higher education costs"
      },
      {
        "id": 1067095,
        "name": "Soukna",
        "activity": "Primary/secondary school costs"
      },
      {
        "id": 1067054,
        "name": "Mouna",
        "activity": "Primary/secondary school costs"
      }
   ...
   ]}}

I don't have any paging support yet so large result-sets can take a few seconds. With the way react/relay is headed, you'll soon be able to declaratively state what data a component on the screen needs and then the container gathers all of the requirements from various components and makes the appropriate consolidated query to the endpoint. 

I know there's discussion within Kiva about a refreshed version of the API, there are GraphQL adapters in PHP that you could bridge between KC queries/objects. Allowing the consumer of the data to dictate the response shape would be very valuable. :D Just make everything available and let the end-developer decide, maybe s/he wants to just pull the ids for similar loans, or just the image, country and name to display in a tiny list... or maybe the full objects.

If you want to play with it, go here (there's a fully interactive query builder with code-completion, etc) and use the "docs" sidebar to explore the options I have so far. To see the setup for that, the code is here. That /graphql endpoint shows that editor on a GET but you can POST to it with your own query from code and get just a json response.

Paul

Kevin O'Brien

unread,
May 13, 2016, 7:45:04 PM5/13/16
to build...@googlegroups.com
Pretty interesting stuff. We'll have to look into GraphQL.

--
You received this message because you are subscribed to the Google Groups "build-kiva" group.
To unsubscribe from this group and stop receiving emails from it, send an email to build-kiva+...@googlegroups.com.
To post to this group, send email to build...@googlegroups.com.
Visit this group at https://groups.google.com/group/build-kiva.
For more options, visit https://groups.google.com/d/optout.

Abhishek Bhatnagar

unread,
May 14, 2016, 7:24:23 PM5/14/16
to build...@googlegroups.com

That's good information. It's also worth noting that graphQL is going to be more in line with how modern js platforms are likely to deal with front-end models. Facebook is a big pusher for it.

Paul Ericksen

unread,
May 14, 2016, 10:41:50 PM5/14/16
to build...@googlegroups.com
I added a bunch more stuff....

To show off more features of GraphQL (query variables, aliased results, fragments, multiple queries, nesting), I set up this example with comments. (It should be noted that KL won't display these results after those loans referenced are no longer fundraising since it doesn't keep non-fundraising loans).

I've added some support for partners, doing searching by an array of "ids" for both partners and loans, and i made it so that the "similar" field on the loan does a proxy call to Kiva's API to get the ids (then the example query will find the similar loans of the similar loans, so the slowness is mainly attributed to the number of queries it's making to Kiva due to the nesting). The "loans" field now also can take an argument of "criteria" (rather than just "sectors" which contains both loan and partner criteria, and the "partners" field only takes partner criteria. 

Just browse around the Docs sidebar thingy to see what else I've added and what options are available.

Paul

Kevin O'Brien

unread,
May 14, 2016, 11:54:05 PM5/14/16
to build...@googlegroups.com
Thanks Paul! 

Cool stuff :)

Paul Ericksen

unread,
May 17, 2016, 6:24:10 PM5/17/16
to build...@googlegroups.com
With GraphQL, everything is a field and every field can accept arguments. Fields are either scalar types or objects.

So, with every field being able to take arguments you can do something like (not implemented, for illustration only):

   loan(id:<someid>) { 
     posted_date(format:"mm/dd/yyyy")
    }
}

"loan" is just a field on Query. "posted_date" is a field on Loan.

So, in the case of KL's GraphQL interface, I could just make my own type (used only for graphQL queries) called "formattableDate" where it has all the smarts built in to return the default date string when no arguments or format using the string given. That type could then be used for all of the dates so every date field of every type has that ability.

Additionally, you could make queries, like this ...

    loan(id:<someid>){
       terms {
          scheduled_payments(lastOnly:true) { due_date(format:"mm/yyyy") } 
       }
    }
}

Or:

loan(id:<someid>){
    terms {
      scheduled_payments(greaterThan:"now") { due_date } 
    }
}
}

Then just have some code to interpret the incoming arguments when processing the query.

Another Kiva-domain example, would be descriptions. Have a "description" field that when it has no arguments returns a description object (with a field for the language and the text) where it defaults to english but falls back to the original language when no english translation, if you pass it a language as an argument "description(lang:"en")" you could have it return only the matching description and "null" if none match. Then you could also have a "descriptions" field that returns an array of description objects. Since most users would probably only ever want the "description" field, it reduces data transfer by allowing it to be specified but doesn't restrict the more advanced apps from having access to the full descriptions array if they want it. Behind the scenes, Kiva's KC objects don't change at all, you're just introducing a thin layer to access that data. You could then also have a "description_text" field that returns a string and takes arguments for preferred language and to tell it to truncate after X characters (for use in a list of results). 

One of the things GraphQL hopes to achieve is to remove the need to version an API, you just add new stuff and people use it or they don't. Like you can initially support just the simple "scheduled_payments" field that returns an array of payment objects (due_date, amount) and then later add the ability to pass optional arguments (like those shown above) and no existing users would get broken. There's no penalty for adding anything new or adding more arguments to an existing field. You just can't change types or remove stuff once people are using it.

It has support for deprecating fields as well, where you indicate that it's deprecated and what the reason is, and that will show up in tools like GraphiQL (where it won't show up in the auto-complete and will give warnings if you use it and you can choose to return results or just null if it's removed permanently).

As GraphQL continues to expand, you'll see more options for different execution strategies, where I know that for Ruby, there are parallel execution libraries where the field resolution can all happen asynchronously, but then all fields must be resolved before the result (outer promise) is resolved. I'm sure there are many queries on Kiva's pages where the execution is just sequential, where parallel execution would greatly reduce response times.

Side note: If you look at Kiva's "similar" loans endpoint, that feature was obviously intended only for use for the block of loans that display at the top when looking at a loan that is no longer fundraising, because the algorithm will most times return the loan being queried as another loan similar to itself. (Loan A's similar loans are A, B, C... it really shouldn't include itself.)

Paul
Reply all
Reply to author
Forward
0 new messages