Golang REST API from scratch with Go Fiber, Docker & Postgres | Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome to div Rhino a channel dedicated to project-based learning I'm glad you're here in this tutorial we will learn how to create a simple rest API from scratch using go and Docker to follow along you will need to have Docker installed and running you can head over to their website to find the version that suits your environment even though we're using go in this tutorial you do not need to have it installed on your machine let's look at the most basic Docker file and Docker compose config file we'll need to get started we've opened up the terminal in vs code and changed into the directory where our projects are stored here we can create a new directory for our project and immediately change into it we've called our new project div Rhino trivia because we are building a trivia API let's go ahead and create a Docker file that will contain the instructions we'll need to build out API container and then let's also create a Docker compose.yaml file so we can manage multiple containers within our project with our project open in the editor we should see our newly created files in the sidebar let's open up our Docker file and start adding instructions we want to start building our own container from the official golang image with the version 1.19.0 specifying the version here will ensure your Dev environment is the same as mine think of this step like we're installing go on a fresh new machine the only other thing we'll need to do in this step is to set our working directory Docker containers run on Linux so here we're using Linux file system conventions it's all we need in our Docker file to get us started now let's work on our Docker compose.yaml file at the top of the file we will set the compose file version to 3.8 we will have one service to begin with and we will call it web the build property is the path to our Docker file in this case our Docker file is in the current directory so we'll use a full stop here to indicate that next we will map Port 3000 from our container with Port 3000 on our host machine and then we'll set our volume to tell Docker where we want to persist the data from this web service if we head into the terminal we can run our container using the docker compose up command because it's the first time we're running this container it'll take some time to install everything and then it exits because we aren't really doing anything other than an installation let's take a quick look at the logs we can see here that the first step in the log corresponds to the first instruction in our Docker file and the second step in the log matches the second instruction in the docker file when working with Docker we need to run all our commands within the containers bash to access this shell we can use the command on the screen if you notice the command is referencing the web service that we set up in the docker compose.yaml file now that we're inside the container's bash we can run the Go version command to verify that we have in fact installed go in the container the Go version in our Docker file matches the Go version that was printed from the container now that we know how to enter our container let's also learn how to get out of it you may have guessed that we can use the exit command to do so we've reached the first milestone in our project you're doing a great job in this section of the video we will look at installing and managing dependencies in our go container we will need to be inside the container to run the installation commands to enter the container shell we can execute the command on the screen we will be using go modules to handle our dependencies so let's initialize that now it is a good idea to name your package after the URL it can be downloaded from this project will be available on my GitHub so I'm going to use the repository URL as the name of my package please feel free to use your own URL for this step we can tell the command ran successfully because we now have a go.mod file in our project folder we'll be using the web framework called go fiber to build out our trivia rest API we can install this within our container by executing the command on the screen now let's create a folder called CMD to hold our main package and inside this folder we can create our main.go file next we can head over to the go fiber documentation and copy the hello world example they have provided then we can head back into vs code and paste the example code into our main.go file we've changed the string we're going to send but the rest of the code is the same as the go fiber example code that snippet is enough to set up a go Fiber app we can now run our main.go file with the go run command and bind to our Local Host we have to do this binding so I'll container and browser know how to talk to one another the printout in the terminal indicates that our go Fiber app is running we can head into the browser to check it out the string in the browser is coming from the snippet in our main.go file at the moment we have to enter the web service container every time we want to run our go Fiber app it would be nice if we could start up the app from the host machine instead we can do this with a few changes to our Docker file and Docker compose.yaml file let's stop our go fiber web server and head into our Docker file where we will add two new lines of instructions the first line will copy all the files from our host into the Container the second instruction will run the go mod tidy command which will ensure that all our required packages are properly installed then we can head into the docker compose.yaml file where we will add the command that launches our go Fiber app adding this command to our Docker compose.yaml file will allow us to start our go fiber web server by running the docker compose up command from our host machine we can exit our web service container and run the docker compose up command in our host terminal everything seems to be working as expected because we can see the go fiber start message print out in the logs if we head into the browser our app should be running at localhost Port 3000. let's head back into vs code and make some changes to our app in our main.go file let's add some text to our string when we go back and refresh our browser we do not see our changes being reflected with go we need to rebuild our project to be able to see our changes this can be a little cumbersome so let's introduce a way to hot reload our app so that changes are reflected whenever we refresh our browser let's head back to our Docker file to add a new instruction that will install a package called air then we also need to create a configuration file for the air package this will be a DOT file called air.tomel we don't need to populate the configuration from scratch we can head to the air repository and copy the sample file from there then we can head back into our editor and paste it into our own file the only thing we need to change is the build command we need it to be pointing to our CMD folder where our main.go file lives now that our air package has been configured let's use it we can do this by heading into the docker compose.yaml file and updating our up command to use air instead of go run next we should probably rebuild our container by running the docker compose build command because we've made a few changes to the docker file instructions if we run the docker compose up command now we should see the error message and the go fiber message printed in the logs now we can make a change in our app and see it reflected when we refresh our browser let's make another change and test it in the browser again just for good measure we've made it to our second milestone patch yourself on the back because you're doing awesome in the next few sections of the video we will work on adding a postgres service into our dockerized Go app we can close most of the files to tidy things up oops we need to edit our Docker compose.yaml file so we should probably open it back up then under our build key let's add the EnV file key and have it point to the dot EnV file this file doesn't exist yet so let's create it now we will come back to our DOT EnV file later on to add some values for now we can move on and start creating a new container for our database in our Docker compose.yaml file let's add a new service we will be using the postgres Alpine image that we can pull directly from Docker Hub because we won't be adding any extra instructions to our postgres container we do not need to create an accompanying Docker file for it nor do we need a build property here next we will map Port 5432 from our container with Port 5432 on our host machine this is the port that is typically used by postgres and then we will set a volume to tell Docker where we want to persist the data from this service we're going to use a named volume here so our postgres data is always persisted and any removals would have to be done manually now we can head back into our DOT EnV file to add some environment variables that we will use to connect to our database here we have a database user a database password and a database name without any additional steps we can already access these environment variables within our container all we have to do is add them to the environment property we will map the postgres user to the DB user variable the postgres password to the DB password variable and the postgres DB to the DB name variable these are the only environment variables we'll need for this tutorial now let's figure out how we can talk to our database we could just write raw SQL because our app is small enough but for the purposes of learning let's see how we can use an orm Library called Gom we will need to install a couple of new packages first so let's enter our web service container by executing the command on the screen once we're inside the web service shell we can install the Gom package Gom supports several databases so we will need to install the postgres driver so we can get the functionality that is specific to our use case one of the main benefits of using an orm library is that it allows us to manipulate data from a database in an object-oriented way with Gom we can use ghost structs to represent our objects these objects can also be described as models so let's create a new models directory and file to organize them within our models package let's import the Gom package that we installed earlier then we will create a customs drop type called fact we will specify that this fact is a goal model a fact will have a question field which will be of type string and an answer field which will also be of type string we will use Json struct tags to describe the corresponding lowercase Json keys for each of our struct fields we will also add Gom struck tags to alfact Fields both our Fields will be represented as text columns in the database neither column will allow null values and we will also set the default value for both columns to be null so that we can return an error if the user does not provide their own values when they create a fact now that we have our goal model set up let's work on connecting to our database we can create a new database directory and file to organize the related code within our database package let's import the Gom package then we will create a custom struct type called DB instance this DB instance type will have a DB field the type of which will be appointed to gom.db we will also create a package level variable called DB with capitals this variable will have the type of DB instance next we will create a function called connectdb within the body of this function we will start setting up the gom.open method which will open up a connection to our database the gom.open method takes two arguments the first argument will be a Gom dialector in our case this will be related to postgres the second argument will be some options so far we've been using placeholders to represent the arguments so let's start by replacing the first one for our dielector we will use the postgres.open method which takes a data source name String as its only argument we should also remember to import the postgres driver while we're here the data source name String does not exist yet so let's create it now we will set the host to DB the user will be interpolated from an environment variable that we will pass in the password will be interpolated from another environment variable the DB name will also be interpolated from yet another environment variable the port will be set to 5432 which is the typical port for postgres we will disable SSL mode and set an arbitrary time zone that is the structure of our DSN string now we can replace all the placeholder variables with their corresponding environment variables by using the OS get n function we should also remember to import the font and Os packages since we are using them now it's time to pass in some proper options as our second argument to the gom.open function we will use a pointer to gom.config and set the logger property to a default logger set to info mode now let's also check that our necessary packages have been imported the gom.open function returns a database and an error so let's do some quick error handling before we move on if we hit an error we will log the error and exit the program with an error code of 2. if there are no errors we'll just log messages to say we've connected next we will use Auto migrate to create the tables that we need from our Gom models we only have our facts model so let's pass that to Auto migrate then we should also ensure we're importing our models package at the end of our connectdb function we want to set the value of our Global DB variable to the database we just set up and with that our connect DB function is complete we can head into our main.go file and make use of it first let's ensure we're importing our database package then at the very top of func main we can call our connectdb function from our database package we've made it to our third Milestone we got a lot done and you're doing a wonderful job in the last part of this tutorial we will create some routes and some endpoints in our main.go file we will set up our routes after the line where we create our go Fiber app this setup routes function we have used does not exist yet so we will have to create it first let's create a new file for our routes this routes file is part of the main package which is why it lives in the CMD folder we will import the go fiber package then we will create the setup routes function this function takes a pointer to a go Fiber app as its only argument now we can move our existing routes from the main.go file into this dedicated routes file we can further clean this up by moving the handlers into a separate package let's create a new Handler's directory and file to organize the related code within our handlist package let's import the go fiber package then we can set up our home Handler all handlers take in the go fiber context as an argument and they return an error we can copy over the contents for this Handler from our routes package then we can use our new home Handler in our home route we will also remember to import our handlers into our routes package we have enough here to start testing our home route and endpoint we will exit our container and start up our go fiber web server by running the docker compose up command then we can head into our API client and use the get method to test our home route and endpoint we know this is working because we can see how div Rhino string come back in the response back in the editor we can take a look at the logs for a second we can see that some SQL was executed to create a fax table and a new index these queries will run for us by the auto migrate function now let's create a new route at slash fact so we can have the ability to insert new facts into the database we are using the create fact Handler but it doesn't exist yet so we will have to create it that can now handle this package we will put together the create fact Handler so we can create some new facts go fiber gives us a function called body parcel we can use this to pass a new fact the body passive function returns an error so let's do some quick error handling before we move on if we hit an arrow we will return the internal server error status code and the Json formatted error message we should also import our models package and then fix this type O2 if there are no errors we can go ahead and persist this fact to our database let's also remember to import the database package as well then we will return a success status code and our new fact formatted as Json we can test this new endpoint in our API client we will use the post method and the slash fact route then we will add some Json data into the body of our request we are sending a question and an answer for our fact once we hit the send button we will receive our response which will be our newly created fact formatted as Json we're going to head back into our routes package and repurpose our home route so that we can use it to list all our facts we will also have to go and update our home Handler so it matches this renamed list facts Handler will go and find all our facts from the database then we will return a success status code and all our facts formatted as Json we can test these changes in our API client we will use the get method and our index route once we hit the send button we will receive all our facts in the response currently we only have one fact in our list so let's post another one how many time zones does Brazil have Brazil has four time zones when we hit the send button we can see our second fact has been created and returned in the Json response now when we make a get request for all our facts we receive two facts in the response finally let's create one last fact for good measure how many time zones does Russia have Russia has 11 time zones when we hit the send button we can see our third fact has been created and returned now when we make a get request for all our facts we receive three facts in the Json response and there you have it in this tutorial we learned how to build a rest API from scratch with go and Docker we used postgres to persist our data and Docker compose to manage our containers a text version of this tutorial can be found on divrino.com and the repo can be found on my GitHub account I'll leave both links in the description for this video If you enjoyed building this project please let me know in a comment or like the video and subscribe to my channel thank you for watching I appreciate you
Info
Channel: Div Rhino
Views: 26,987
Rating: undefined out of 5
Keywords: go, golang, docker, docker compose, rest api, api, from scratch, rest, postgres, container, compose, web development, go fiber, web framework, framework, tutorial, guide, article, divrhino, div rhino, best, best tutorial
Id: p08c0-99SyU
Channel Id: undefined
Length: 21min 47sec (1307 seconds)
Published: Mon Oct 17 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.