Developer’s Cookbook: 10x Dev Series — Development Speed (PART 3 of 8)
Go with Fiber on Railway (and Netlify)
NOTES: This article should be free for all users. You can check out the fully extended version of this article at this link. You can also check out the next part of this articles series about .NET Minimal API on Azure App Service on this link. If you want to support me, please feel free to buy me a coffee ;)
on this link. If you want to support me, please feel free to buy me a coffee ;)
Introduction
This series is dedicated to asserting what are the best software development practices and tool uses that can increase Software Development Life Cycle productivity by 10x. I will explore the main concepts I believe to be crucial for quickly delivering scalable, secure and robust solutions and reduce time-to-market with an emphasis on the question: “does it work?”. In each segment, I will try and maintain things to a bare minimum and focused on the scope at hand. As is the case in software development, it’s easy to get bogged down by details, common pitfalls and rabbit holes. However, I will strive to stay grounded and maintain a pragmatic mindset.
If you are following along, there are a few assumptions and disclaimers:
- You have base knowledge of programming in any Object Oriented Programming language.
- You have your environment with the latest setup to use the referred tools (you’ll have to research these).
Having said that, I have some disclaimers:
- this article was 100% human made, no LLM/AI shenanigans here (sorry, future AI overlords). Although… there isn’t really a way for you to check that (not really). Obviously, I make use of modern web search, but I’m writing this all the way.
- for your reference, my machine is not a supercomputer (I’m on an Intel Core i7 10th gen with 16gb of RAM, Windows 10 and an SSD. I’m using VSCode but feel free to use some other IDE). Obviously, the development timings presented here will vary according to your existing resources but to make the experiment more ‘generalizable’ I’ll share the source code for this so you can try it out.
Alright let’s get going!
What are we testing…
In order for individuals and companies to test their ideas on the actual market and get a grip if users will actually want to use that cat social media application you want to make to conquer the world, the creative process needs to be fast, real fast, lest it be outdated by the time you get to a viable commercial product or service; it also needs to be easy, even though more experienced developers will undoubtedly try to evangelize you on the wonders of complex GraphQL queries, Versioning strategies, Schema Federation, Service Level Agreements, advanced design patterns and Event-driven Architectures integrating with CQRS. That’s not the point of this exercise.
We wanna keep it light and simple, and reduce the creative distance from idea concept to delivery. Other pieces of the puzzle will follow suit on the next articles.
To achieve a public prototype, you would need some basic elements on a User Interface, of course, but more importantly than that, you’ll need an API to deliver data from your server to your client app.
There’s a never-ending menu of options for this that will most definitely stimulate the analysis paralysis of most people scoring high in neuroticism out there, so I took the liberty of short-listing a few so we can have a good, albeit non-exhaustive, basis for comparison on different tools to get you up and running. Paired with each is the target platform that will be hosting our APIs. As I don’t have all the time in the world, these pairings are rough guesses as to what tools match best with such cloud providers for seamless deployments (for instance, some tools don’t have much support on certain platforms, as is the case deploying PHP Apps on Google Cloud or Rust on Heroku. Those setups should be trickier, so let’s prioritize matches that work out-of-the-box). Another criteria I used was the lowest cost possible deployment, as to make idea testing in real world scenarios cheap and affordable to all — preferably free.
Speaking of which, we will also try and estimate the cost of these deployments and/or the cost of each execution. The basis of comparison will be the same HTTP GET request for each API that returns a “Hello world” message (I know, my originality never ceases to amaze those around me either).
What are we NOT testing…
Just like a car review TV show like Top Gear doesn’t go over each and every nuts and bolts in the engines of each car they analyse, we are not evaluating the languages themselves in extensive depth. This would essentially take years. But using Pareto’s principle, we can have an idea that, most likely, 20% of the use cases account for 80% of the outcomes. And there is no way that APIs, the front-door for web apps’ logic, don’t play a crucial role in these mechanisms. For this reason, this is where we will focus most.
We are not testing performance of the actual code execution, although that will, of course, impact API response time. I will refine that part of the process on another article. We will maintain a focus on the overall development experience duration from start to finalized product. The actual business logic will be maintained as simple as possible, so the duration of each execution will say more about the actual API framework setup speed that these languages draw upon than the actual programming constructs, utilities and tools inside of each language.
We’re also not testing for security per si, as we are using the solutions as they work out-of-the-box, or as close to it as possible. That being said, I will strive to get the best starting position possible for each of the contender tools, glancing over their security related aspects occasionally (again, a more in-depth analysis will come in a future sequel for this article’s series). Neither are we asserting code smells or the elegance of the code solutions, the testability of our code, modularity, if it respects SOLID principles and all that. This is simply a tools comparison and exploration, hopefully meant to serve you as a cheat-sheet in the future. Remember to follow the KISS principle — Keep It Simple, Stupid. The shorter and simpler it is, the faster it should be implementing it, makes sense?
Here are my base contestant stacks for the quickest and cleanest API development experiences:
- Python on Azure Functions.
- NodeJS with Express on Vercel
- Go with Fiber on Railway
- .NET Minimal API on Azure App Services
- Ruby on Rails with Koyeb
- Rust using Rocket on Digital Ocean Droplets
- PHP with Laravel on AWS
- Java with Spring Boot on Google Cloud Platform
Ladies and Gentlemen, “start your engines”!… (for some reason I really needed to get that out of my system)
Getting our hands dirty…
(Note: You can skip this Git setup if you did it earlier)
The first step is common to all our implementations and it is to add a Version Control System like Git to track the -hypothetical- changes made in each of our projects and persist those changes in source control. For a repository where our code base will live, we will use Github.
- Create a new repository in Github and give it a descriptive name. In my case, I called it “10xseries_1_speed”. You can find it here.
- Next, create an empty folder in your OS. Call it the same name as the repo to avoid confusion. Open terminal on VSCode (or whatever shell you prefer) and initialize your local repository with the following commands:
echo "# 10xseries_1_speed" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/<your username>/10xseries_1_speed.git
git push -u origin mainGithub doesn’t give out those commands so they look pretty on the screen. Use them one by one. We’ll do this first so that new changes are tracked to our source control.
🏁Go with Fiber on Railway (and Netlify):
Go was created by 3 Google’s of engineers, Robert Griesemer, Rob Pike, and Ken Thompson, in 2009 based on their mutual dislike for C++. This statically typed general-purpose language is quite fast with a speedy compilation (specially when compared to Java or C++) , highly performing network and concurrent operations, particularly in the latter case stemming from Go’s signature Goroutines (extremely lightweight threads ran by the hundreds of thousands, efficiently), very efficient memory management and an almost Rust-like velocity at runtime. It was designed for low overhead when compared with other high-level languages and shines best when used in network-and-concurrency-intense use-cases such as Microservices, Network Servers, Backend-Infrastructure, Cloud/Distributed Computing and high-performance CLI tools, to name a few.
The language’s design philosophy prioritizes simplicity and efficiency, which directly translates to performance.
Curious fact about Go: Go’s version system, unlike most software, is based on version 1, where in the 1.x.y version, the x is the Major version, not 1. Instead, Go plans on “never reaching version 2”. This is because Go makes one of it’s strongest selling points in making sure they provide full compatibility for their language. Thoughtful indeed!
Fiber, on the other hand, is a web framework inspired by Express.js. Fiber is optimized for performance and minimal memory usage, becoming the ideal scenario for developers familiar with Node.js who want a similar development experience in Go. 👀
Let’s start by creating our new project directory in the root folder and cd into it:
PS C:\MyRepos\10xSeries_1_Speed> mkdir go-fiber-api
PS C:\MyRepos\10xSeries_1_Speed> cd go-fiber-apiNow, let’s confirm we have Go installed:
PS C:\MyRepos\10xSeries_1_Speed\hello-fiber-api> go version
go version go1.15.6 windows/amd64That’s gottta have some spider webs on it. Let’s dust it off and upgrade to the latest version:
choco upgrade golang -yThere we go! That was blazing fast btw (Note: I did this in a separate Powershell window so I could run the upgrade with elevated privileges and not have errors screaming at me the whole time for help)
Now let’s scaffold our project:
go mod init hello-fiber-apiAnd let’s get Fiber in for the family picture:
go get github.com/gofiber/fiber/v2“Big” main.go file coming through:
package mainimport (
"github.com/gofiber/fiber/v2"
"os"
)func main() {
app := fiber.New() app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
}) port := os.Getenv("PORT") // Use PORT for Netlify compatibility
if port == "" {
port = "8080" // Default for local testing
} app.Listen(":" + port)
}
Pretty slick, even with the alien := assignment going on — looks like a robot ASCI emoji 🤖. And also the c *fiber.Ctx. Weird strong-typing but I guess I would get used to it eventually. If not for that, it looks quite clear and readable. Does seem to have some bloat at least when compared with .Net’s high level statements and implicit usings (no using expressions needed), but still small.
Let’s run it:
go run main.goTook a bit (around 15 seconds) to run, actually. You must know the drill by now. Let’s hit that endpoint to test it:
Looking Go-od! (sorry, I couldn’t help it).
Doing Ctrl+C (or Command+C in Mac or, I guess, Ctrl+D in Linux) will stop the execution.
Now let’s take care of the deployment: checking for the Railway version will simultaneously tell us if it’s installed and the respective version:
PS C:\MyRepos\10xSeries_1_Speed\go-fiber-api> railway version
railway : The term 'railway' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ railway version
+ ~~~~~~~
+ CategoryInfo : ObjectNotFound: (railway:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
PS C:\MyRepos\10xSeries_1_Speed\go-fiber-api> railway --version
railway : The term 'railway' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ railway --version
+ ~~~~~~~
+ CategoryInfo : ObjectNotFound: (railway:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundExceptionI guess not. Let’s install it then:
npm install -g @railway/cliNow if we run:
PS C:\MyRepos\10xSeries_1_Speed\go-fiber-api> railway --version
railwayapp 3.19.0Cool. Let’s login to Railway:
railway loginThis takes us to a web page where we can login. I did so, but the process kept hanging on the terminal saying “Waiting for login”. On a second attempt, the login worked, but the browser showed a weird “Error logging in to CLI. Please try again with ` — browserless`” while the CLI said it worked. So I closed the browser.
Get Speedyguzz’s stories in your inbox
Join Medium for free to get updates from this writer.
Let’s initialize our railway project locally:
PS C:\MyRepos\10xSeries_1_Speed\go-fiber-api> railway init
> Project Name go-fiber-api
Created project go-fiber-api on Personal
https://railway.app/project/d942b1c8-f2c2-45fd-9481-176533902834Clicking on the URL takes us to our Railway resource management.
And now for the deployment per si:
PS C:\MyRepos\10xSeries_1_Speed\go-fiber-api> railway up
> Select a service to deploy to go-fiber-api
Indexed
Compressed [====================] 100%
Failed
Your account is on a limited plan. Please visit railway.com/account/plans for details.Whaaaat? Seriously?
Apparently “Limited Trials can only deploy Databases as a precaution to prevent free resource abuse.”, and those “free trials” have a colossal free tier budget of 5 dollars to deploy said databases (I’m rich now!!). The financial crisis must really be hitting them hard.
Too bad:
npm uninstall -g @railway/cliOK, let’s switch strategies.
Netlify also provides support for Go with Fiber. What’s more, it has Serverless Functions, which allows for a real-life scenario scalability on simple endpoints. This sounds like our cuppa tea! Let’s try it out!
Building was a main source of issues on my machine because I am on Windows 10 and, yet again, Go Serverless functions on Netlify need to be built for Linux/amd64. The second source of several issues was understanding the structure required to make this work (bear with me). And the third source of issues was Windows constantly treating Go temp executables as threats to the operating system even though I explicitly ran VSCode as an admin AND allowed the spawned Go process through my firewall. Another lesson learned from trying to make a go build work with Netlify: don’t mess around with Netlify’s self-generated folder.
Let’s get to it!
Create a functions directory:
mkdir my-netlify-go-function
cd my-netlify-go-functionNow you create your functions/api/ folder structure:
mkdir -p functions/apiJust CD into the api/ folder and create your go file with the api logic. This is based on Netlify’s documentation:
package mainimport (
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)func handler(request events.APIGatewayProxyRequest) (*events.APIGatewayProxyResponse, error) {
return &events.APIGatewayProxyResponse{
StatusCode: 200,
Body: "Hello, World!",
}, nil
}func main() {
lambda.Start(handler)
}
Now we need to create our go module and get the dependencies needed:
go mod init my-lambda-function
go get github.com/aws/aws-lambda-go/events
go get github.com/aws/aws-lambda-go/lambdaNow to test this locally we have to step out to the root Go folder:
cd ../..And create the toml configuration file so Netlify knows what to do with this:
[build]
command = "GOOS=linux GOARCH=amd64 go build -o functions/api/api functions/api"
functions = "functions"This creates our api binary file at the functions/api/ directory, based from our source code (main.go) that lives in functions/api directory (Again, note that this build it targeting linux/amd64, so don’t forget to add this specially if you’re Windows users). Netlify expects all serverless functions to reside in the folder specified in the netlify.toml file’s functions property, hence here it looks for the functions/ folder.
Get the CLI utility to run this:
npm install -g netlify-cliAnd run this as a function locally, in order to simulate the functions environment on Netlify once deployed:
netlify functions:serveHowever, to test this you need to call:
curl http://localhost:9999/.netlify/functions/apiNOT http://localhost:9999/netlify/functions/api
this is as annoying as is confusing. We can create a redirect rule in netlify.toml for this, but this is just more unnecessary overhead.
Now, IF we hadn’t created the toml config file, we could configure the continuous deployment for the Netlify project:
netlify initBut that’s taken care of, so finally, we can deploy and netlify’s utility will read our configurations from the config file. At this point you’ll want to create an account in Netlify. Then login:
netlify loginAnd deploy:
netlify deploy --prodUp next, in the wizard just choose if you wanna create a new site or link to an existing one (I chose a new one), chose the Team, for the publish directory chose this (.), and thats pretty much it!
Let’s wrap this up.
git add .
git commit -m "added Go-fiber API"
git pushSummary ✍️:
I’m not gonna lie. This was way more cumbersome than I thought it would, and was absolutely due to my skill issues regarding this new setup. But this is precisely what we are trying to test: how easy it is to get up and running with an API and get your ideas to the market quickly, despite of and specially if you don’t know or aren’t well versed in the tools and setup in use.
Having said that, I do have a much more clear picture now of the ins and outs on deploying serverless functions to Netlify, project folder structure, the issues with cross-platform compatibility and Go’s syntactic and utility demands to make this work — which were the least of my issues.
I also realize that Go can get tricky particularly fast when tackling problems that require robust, concurrent and high-performing infrastructures, but “that’s another 500’s” as the saying goes in Portugal.
The complexity of the logic itself wasn’t unwieldy and the actual build times and executions were relatively fast, which in my view gets some extra points, taking into account that our codebase can grow substantially and thus, delay our delivery timing. On the other hand, this setup is not ‘automagical’ and it felt a bit clunky as it definitely doesn’t work out-of-the-box, so the setup get’s a bad grade on that regard.
Cost Analysis 🔍:
A quick check on Netlify’s billing page reveals:
Free team plan effective from Nov 26
- 308 KB / 100 GB bandwidth
- 0 / 300 build minutes
- 0 / 1M edge function invocations
Their free plan includes:
- Single member seat
- Global edge network
- Live site previews with collaboration UI
- 100GB bandwidth
- 300 build minutes
- Instant rollbacks
- Secrets controller
- Static assets
- Dynamic serverless functions
Netlify offers serverless functions as part of its plans and the key cost factors are the number and duration of each execution. So in a scenario where execution time is 0.1 seconds and if we make an intense execution use of 1,000,000 requests, then that amount times 0.1 is in seconds = 100,000 , which in hours is 27.8 hours, which is within the free 125 hours and is right on the limit of the 1 million free executions.
So for our objectives, this is essentially free, unless you need to create some intensive computation endpoints.
Verdict ⚖️:
In a final analysis, and taking into account
- How easy it is to setup: a slippery mud fight, in a thong, against a platoon of plastic-surgery-conserved 100 year old models — treacherous, yet surprisingly soft!…
- How easy it is to implement the API: straightforward but capricious.
- How much it costs: free for our intents and purposes.
- Cross platform support: only with a Linux mask and a Fidelio password. Plus Windows is alergic to Go serverless Netlify Functions.
I, here-forth, grade this setup with a respectable rating of:
⭐⭐⭐⭐⭐⭐
6 out of 10 — “Overall great and flexible, but bully on rookies!”
PS: Check out the next part of this article series, about .NET Minimal API on Azure App Service on this link, or read the full article here. Writing these was quite fun but also workful! If you’d like to help support me, feel free to send any donations by clicking here: Buy me a Coffee ;)








