Building and Events Application: Choosing the right tools
So much water has flowed under the bridge since my last blog post. Mind you that I have been working quite a lot on this project, I just didn't get around to write about it. So, let's pick up where we left off!
In my last post I talked about some of the requirements of the application and the fact that I really wanted to try to build the server side in Golang. Some of the things that I had in mind was to see if there were any appropriate frameworks out there for making a simple REST API. I also wanted to find an ORM that was simple to use and mature enough that more complicated queries wouldn't be a problem. Simply because I am lazy, and don't want to write my queries in SQL.
The framework
Looking into the possible web frameworks for exposing a REST API I ended up looking primarily at Gin and Echo. Gin is a lightweight framework with focus on performance, and especially its HTTP router and error handling are intriguing. It also has a built in JSON validator. Echo, on the other hand, is even more minimalist than Gin, and while it does not have a built in JSON validator, they do recommend the same one used by Gin. The router is also based on radix tree, just like Gin's. What excites me the most about Echo though, is its built in ability to bind incoming request data to a struct, as well as the context-based request handling.
If you take a look at the documentation for each framework, you will find that the documentation for Gin is very sparse. They do have a large community around the framework, but that is not going to cut it for me. While Echo's documentation is far from as good as it can get, it is still a whole lot better that of Gin. Furthermore, from what I can read on various forums online, it seems like there is a little too much magic going on behind the curtains with Gin, which makes it really hard to understand what is going on under the hood. For all of these reasons I decided to give Echo a try.
The ORM
As I mentioned earlier I want to use an ORM for my database queries. There are a few different options out there, all of them with different approaches. The ones I looked into are SQLBoiler, GORM and ent.
Ent seems to be an ORM that focuses primarily on representing database schemas as graph structures, which is great if you want to expose an API with query languages such as GraphQL. This is not the approach I want to take. My focus will be on making a simple REST API for my application to use.
SQLBoiler is more interesting in my opinion. It takes a database-first approach, meaning that it generates code from the schemas in your database. This means that it can create optimised code that is specific to your database. However, this also means that each time you make a change to your database schemas, you have to regenerate the code. I do have a rough idea of the structure of the schemas, but I am in no way confident that they aren't going to change over time, and they might even change quite often.
GORM seems to me to be a much more traditional ORM, especially for someone coming from Django. It takes a code-first approach, meaning that you define your database schemas by defining them as structs. It seems to be relatively user friendly, and it has OK documentation and a large community behind it. It also allows you to write raw SQL, should the ORM fall short in some cases, and you can define column constraints with tags on the struct.
I ended up going with GORM, because it is easy to get started with the schema definition, and wanted something relatively close to what I already know. I also don't see myself needing to do any graph traversals in this project.
Working on the project, I have found the ORM to be a little difficult to work with, but it might also be a learning curve thing. I'll get more into this in a later post.
The database
Looking at most of my needs and requirements, I could probably choose any old RDBMS. Especially because GORM has drivers for most of them. I do however have one very specific requirement.
When I defined the requirements in my previous blog post, I told you that the user should be able to find events near them. Defining what is nearby means knowing the location of the user, knowing the location of a given event (Both of them located in latitude and longitude), and calculating the distance between the two points.
We could choose to just store the latitude and longitude of an event in the database, query all events that match the search criteria made by the user, make the distance calculations in Go, sort the events by distance and discard the ones that are too far away, or limit by an arbitrary number. To me this seems like a waste of resources, and I would much rather that the database could make the distance calculations and return a result that has already been filtered and ordered, ready to return to the user.
So how do I get a database to make these calculations? I looked into possible solutions and other people who had the same problem and came across PostGIS. PostGIS is an extension for PostgreSQL that allows you to store, index and query geospatial data. I looked a little further at the documentation, and it turns out that making the calculations directly in the query is relatively straight forward. BINGO!
Because of this, my choice naturally fell on using PostgreSQL as my RDBMS for the project.
Final thoughts
Looking into the feasibility of using Go for my REST API, we have explored different options for frameworks, ORMs and RDBMS's. I chose to go with Echo web framework, GORM and PostgreSQL. I have since I made my choices been completely submerged in learning these new technologies, and coding away. I had forgotten just how much fun it is to build something from scratch. The process has also made me realise just how complete a framework Django is. It really does come with batteries included!
In the coming blog posts I'm going to write about my initial thoughts of programming in Go, show you some of the code I've written so far, and talk about the challenges and intricacies of the technologies I've decided to work with. Strap in, it's going to be a hell of a ride!