New Web (API) Foundations (Part Three)
Published: 2021-10-18
Author: Teddi
Lets recap what we’ve discussed so far.
Firstly we’ve looked at how version one of the API exists and is wrote in Python but never really got the love and attention it needed and in return, gave the same lacking love and attention.
Secondly we identified a set of hard requirements of what language / basis we want to be using and settled on Golang.
Next, we’re looking at functional requirements and more the underlying “how” things will get passed around!
For the longest time you’ve had various ways of interacting with systems across the internet, the core of that being “I send request with a given message payload and I get a response back”. For the sake of brevity we’re just going to assume that REST was our only option previously. It’s lightweight enough and a reasonable design pattern that most engineers roll with it anyways.
In many ways REST is nice, especially if designed properly. You have things like your HTTP Verbs (or methods) such as GET
and POST
alongside URL paths which can describe the route in a sense, or even pass in key information, for example: mywebsite.com/<this/is/user/1>
which could describe the user behind ID 1. Each endpoint is typically clearly defined and often requires the person hitting them to be specific and maintain an idea of what they’re going for on their end.
The downside to REST however is it can feel very piecemeal: you may have to hit from as few as 1 to as many as 10 or 11 endpoints just to get the information you want. Furthermore with REST based endpoints you’re always going to get the format in a defined, rigid structure every time; you don’t care about certain data? Well tough because it’s getting loaded and provided unless it exists on another endpoint. Adding on to this you often have to remember to group your endpoints and depending on the language / framework used there may be a degree of repetitiveness or just boilerplate that is consistently in your way.
Don’t get me wrong: REST still very much has its place and I still actively use it but for scale or a public API it often leans on external tools to help it.
The initial plan was to potentially use a REST pattern with Golang given that Go makes it incredibly easy, especially with routers like Gorilla Mux and Chi out there. Although Go makes things performance-wise far smoother all I was really doing was changing the language: there was no under the hood improvements or design changes which meant I wasn’t necessarily making my life any easier and given the internet has moved on a fair bit since I last checked the standards for best practises as a developer I figured I’d go see what other options were available.
Enter GraphQL
GraphQL is somewhat of a distinct flavour change from REST. GraphQL doesn’t so much compete with the ideas of REST and instead changes the discussion from “how do I get my information from this REST API with these endpoints and what verbs do I need” to “we don’t care about that, I’m giving you a request of a data model in JSON, give me back a response in JSON”. And well I mean it actually does what it says on the tin in that respect. Furthermore the goal of GraphQL is to create a modelled representation of data, so if a user say has an inventory and achievements then under REST those would likely be two separate GET
endpoints. In GraphQL they’re simply just two additional fields you ask for and the back-end should do the legwork in making that data available for you in one move. Potentially three requests have been squashed into one, very nice!
Example request in GraphQL:
{
hero {
name
}
}
Example Response:
{
"hero": {
"name": "Luke Skywalker"
}
}
So fairly standard stuff really.
GraphQL isn’t without its problems; especially in Golang where you have a few major libraries to work from and then after that you’re sort of on your own. The question for Golang and GraphQL for me then became:
- Are any of these libraries sane and play to the strengths of Golang?
- Can we build a wrapper in GMod to sanely interact with GraphQL?
- Context: in GLua there exists no (known) GraphQL interface
- Does this makes more or less work?
The answers after some prototyping and testing were as follows:
- Yes, one of the libraries works very nicely with Golang and provides code-generation meaning we can type out something smaller and get much more in return!
- Requests are mostly just JSON blobs so yes, we can!
- Surprisingly, less work!
At this point it seems fairly magical and because of how the library (gqlgen) and Golang work together, intercepting requests for an authentication level seems fairly trivial so how about we now try building something which works!
To recap, at this stage the idea is to see if we can make this work within the confines of GraphQL and Go which at the time was very much an unknown. Bigger yet was the risk that this might not even work properly with GMod which could mean some of this very much going to waste.
Thankfully that didn’t happen and in the next post we can look at how this came about, alongside with some unexpected pitfalls and lessons learned along the way!