Introduction
In this post, we’re going to look through creating a simple web application in Go using a dev container, which will host a simple “Hello World” page, and then we can extend that with a page with submits a form.
Setting up the dev container
To get started here, we’re going to use dev containers with vscode, so our first step is to create a new folder for our project, and then open that folder in vscode. We can then create a new dev container by running the “Add Dev Container Configuration Files…” command and using the “Go” template. This will create the .devcontainer folder for us along with the default setup which will cover our needs. We can then re-open the folder in the container by running the “Reopen in Container” command in vscode.
Setting up the project
As our project is so simple, we can actually get away with using a single file for the application. So let’s start by creating a new file called main.go in the root of our project. We can then add the following code to that file:
| |
This will create a simple web application which will server a simple page. This is made up of several parts:
package and import statements
The package statement here defines the package which this code will live inside. This is similar to the concept of namespaces in other languages. In this case, we’re using the main package, which is the default package for any executable code.
The import statements then load in additional packages which we’ll be using in our code. For this little project, we only need a few things so far:
html/template- This is the package which we’ll use to render our HTML templates, which can take an HTML file with some placeholders, which we’re then able to fill using our own data dynamicallylog- This is the package which we’ll use to log any errors which occurnet/http- This is the package which we’ll use to create our web server
type definitions
After this, we have a type definition. This will define a type for use to use when passing data from our Go code to our template which will be written in HTML. In this case, we’re defining a type called IndexData which will have two properties, PageTitle and QueryParam, both of which are string properties.
main function
The main function is the entry point for our application. This is setup to add our handlers for requests, configure our logging, and start the web application on the port we’d like to use.
indexHandler function
This function handles any requests which come through to our web application. This is broken up into a few parts:
- Load in the template using
template.ParseFiles - If there is an error with the template, log it and return
- Get the query parameters from the request
- Create an instance of our
IndexDatatype, and populate it with the data we want to pass to our template - Execute the template using our
IndexDataand return the response to the user as HTML
With this, we can load a simple HTML page, and also load in a query parameter from the URL that the user has requested. For example, if the user went to http://localhost:8080?QueryParam=Hello, then the QueryParam property in our IndexData type would be set to Hello, which can then be passed to our template and rendered on the page.
Creating the template
Next, we’ll need to create a template file to use to render the HTML for this page. For this, we can create a new folder called templates in the root of our project, and then create a new file called index.html in that folder. We can then add the following code to that file:
| |
Running the application
At this point, we’re able to run our application and see the results. To do this, open up the terminal inside of your dev container, and then run the following command:
| |
This will run the main.go file and start up the web application. You can then open up a browser and navigate to http://localhost:8080 to see the results.
Configuring tasks.json to run the application
As we’re probably going to want to run this application a lot, now would be a good time to setup a tasks.json file to make this easier in vscode. We can do this by creating a new file called .vscode/tasks.json in the root of our project, and then adding the following code to that file:
| |
This will mean that if we run the command “Run Test Task” in vscode, it will open a new terminal and run the go run main.go command for us.
Adding a template with a form
Now that we can render an HTML file and use a query parameter, let’s add a new page which will allow us to submit a form. To do this, let’s first setup our new template file. This will be similar to the index.html file, but we’ll add a form to it. We can create a new file called add.html in the templates folder, and then add the following code to that file:
| |
Note: the action in the form element denotes where the form will be posted to when the submit button is pressed
In this template, we’re using three values from a model:
Value1- This is the first value which the user will enter, and it will be bound to the firstinputelement. Note that thenameof this element isvalue1, which will be used to identify the value when the form is submittedValue2- This is the second value which the user will enter, and will work likeValue1Result- This is the result of the addition of the two values, and will be displayed to the user
Adding a handler for the new page
Next, we can add a new handler for our new page. We can do this by returning to our main.go file and adding a few extra parts to it.
Adding a new type definition
First, we’ll add a new type definition to handle this page. We can do this by adding the following code to the file:
| |
This will define a new type to use as a model for this page. It containers three properties, all of which are integers, Value1, Value2, and Result.
Creating our handler
Next, we can add a new handler for this page. We can do this by adding the following code to the file:
| |
This works in a similar manner to the indexHandler function, but there are a few differences:
- Rather than loading in the
index.htmltemplate, we’re loading in theadd.htmltemplate - We’re getting the values from the form using
r.FormValuerather thanr.URL.Query, this is because we want to look at the posted form rather than the query parameters - We’re converting the values from strings to integers using
strconv.Atoi. Values which come from the form are always strings, so we need to convert them to the correct type before we can use them - Once we have those values as integers, we can add them together and store the result in the
Resultproperty of ourAddDatatype
Setting up the handler to be called
Finally, we can add our new handle to the main function by adding the following code to the function:
| |
Note: this should go above the indexHandler function, as this takes priority
At this point, we should be able to re-run our application and go to the /add page. We should see a form which allows us to enter two numbers, and then displays the result of adding them together. When the page is returned, the values which we entered will be displayed in the form, so we can easily change them and see the result change.
Code
You can find the code for this post on GitHub: https://github.com/cwrenhold/go-web-hello-world