Writing a blog in go!
# Preface
I started this tutorial before the contest opened, but because of school and other complications I was only able to post it today. I hope you see how much effort I put into it and give it an upvote, even though I'm probably submitting too late to win.
### Note
The repl at the bottom might not work, for reasons that will become clear to you if you follow the tutorial. However, don't worry, as the code in it is still functional, and if you follow the tutorial in your own repl you'll be able to make it work!
Anyway, without further adieu, here it is!
### If you have trouble viewing this on repl.it, I also have it in a [Github Gist](https://gist.github.com/vityavv/be3d8df8063f21051e8b5bbeb844a4aa)
# Writing a blog in go!
## [CODE](https://repl.it/@vityavv/BisqueStickyActivemovie)
## About this tutorial
* __Why go?__ - *Go is a really fast and underappreciated programming language. It is surprisingly simple, especially compared to other low-level languages like rust and c++, and it's very very easy to make web servers in it*
* __What is this tutorial based on?__ - *This is based on [scms](https://github.com/vityavv/scms), a CMS I wrote a while ago that is extremely simple*
* __Will this tutorial cover all of the features in scms?__ - *Since this is only a short, one-part tutorial, it will **not** cover the API, SQL database, Markdown (you can't install go packages yet, anyway), or drafts.*
## Before the tutorial
Before the tutorial, you should have a basic understanding of Go. [Tour of Go](https://tour.golang.org/welcome/1) should help you out!
## Getting started - managing articles
First, let's make a file to manage our articles.
Each article will be a *json* file that looks like this:
```json
{
"title": "The title of the article",
"content": "The content of the article"
}
```
So, let's make a *struct* in our new file, `articles.go`, to reflect this:
```go
type Page struct {
Title string `json:"title"`
Content string `json:"content"`
}
```
You may be wondering "Why can't we just have `title string` and `content string`? Well, `json.Unmarshal` (we'll talk about this function in a bit) only puts values into capitalizd struct values, so we have to make them capitalized and then use *tags* to tell json.Unmarshal what to put there. Anyway, before we begin making our functions, we have to get one more thing out of the way:
```go
var pages map[int]Page = make(map[int]Page)
```
One option when making a blog like this is to load the json file each time you get it. However, we're smarter than that. We can store each article in memory beforewards to make the application much faster, and easier to make. As a downside, the more articles you have, the more memory you're going to use. However, articles are just text, which should not take up that much space. Another concern here is why I used `map[int]Page` instead of `[]Page`. I did this because each article will have an ID as it's name... and if an article gets deleted, or if they're somehow out of order in the next function, it will be harder to compensate. Even if you decided to make a slice and just skip the deleted files, imagine this scenario: someone has three articles, 1.json, 2.json, and 3.json, but they delete 2.json. There's a bunch of links to the third article, but they all break because it gets deleted from the slice! However, if map is used, you can avoid this problem.
Finally, we can get to making our first function, and the most important of them all: the `FileInit` function. The `FileInit` function should be run at the beginning to load each article into the pages map we made earlier. Let's break it down to it's basic parts.
The first couple of lines are:
```go
files, err := ioutil.ReadDir("./articles")
if err != nil {
log.Fatal(err)
}
```
This is a new import! Make sure you have your file set up correctly, with `package main` at the top, and then in your imports add `io/ioutil`, used for reading and writing files. Now, let me explain what these lines do: they get a list of the files inside of the `articles` *directory*, or folder. The next three lines are basic error handling, which also use the `log` package.
**For the rest of the tutorial, I will be ommitting error handling for sake of brevity. Every time you see a variable called err, assume that following that line is error handling as shown above**.
After we get that list, we do this:
```go
//for every file in the articles folder
for _, file := range files {
//The following line reads the file we are on
pageFile, err := ioutil.ReadFile("articles/" + file.Name())
//Notice the err above, which means that in the real code I did error handling after it
//This line makes a new page, called page
var page Page
//This line "Unmarshals" the json found in the file we read into the page. There is error handling after this one too
err = json.Unmarshal(pageFile, &page)
//In this following line, we get the page number. This includes a new import, "strconv", which I use to convert strings to numbers and vice versa. Here, I get the file name, take away the ".json" at the end, and then convert it to a number (int).
pageNum, err := strconv.Atoi(file.Name()[:len(file.Name())-len(".json")])
//finally, I add the page to our map
pages[pageNum] = page
}
```
I've annotated the code so you can read through it, but basically it reads each file and puts it in the pages map. That's pretty much it, for the `FileInit` function!
Our next function will be a function called `GetFrontPage`. The front page of our blog will have our five most recent articles on it. Here it is, annotated:
```go
//The function doesn't take anything, but it returns a slice of pages. The reason you see (fpPages []Page) in the return is because it already defines fpPages in the begining of the function, and then I can just type "return", without anything, and it will return the fpPages variable. This is a really cool feature of go
func GetFrontPage() (fpPages []Page) {
//make a new slice of pages, with the *capacity* to hold 5, but a length of zero. This is some weird memory managament wizzard magic I saw online, but lengths and capacities are covered extensibly in the tour of go (have you read that yet? ;)
fpPages = make([]Page, 0, 5)
//Woah! Where did this getPageNumbers come from? I'll explain, right after this
pageNumbers := getPageNumbers()
//this for loop counts down backwards from the last element in the page numbers to the fifth-to-last
for i := len(pageNumbers) - 1; i > len(pageNumbers) - 6; i-- {
//Sometimes there's less than 5 elements, so we have to make sure that the page actually exists
if i >= 0 {
//this uses the built-in append to add the new page to the fpPages slice
fpPages = append(fpPages, pages[pageNumbers[i]])
} else {
//in case it doesn't exist, it just adds an empty page struct, which makes everything the nil value.
fpPages = append(fpPages, Page{})
}
}
//as discussed earlier, I just have to type return, since the computer already knows that I'm returning fpPages
return
}
```
But where did this function, `getPageNumbers`, come from? Well, as discussed earlier, we don't always have the page numbers as 1, 2, 3, 4, and 5. Sometimes they're out of order, and with gaps in them. So, I wrote a helper function to get me the page numbers. Have a look:
```go
//As before, using implicit returning by already defining pageNumbers
func getPageNumbers() (pageNumbers []int) {
//As before, magic wizzardry. This is actually pretty similar to get front page. I make pageNumbers into a slice of ints, the capacity equal to how many pages are there
pageNumbers = make([]int, 0, len(pages))
//when using range with maps, you do "key, value := range <map>". Here, I only need the keys, so I can omit the values.
for key := range pages {
//Pretty simple: I add the key to the pageNumbers slice
pageNumbers = append(pageNumbers, key)
}
//New import! "sort" sorts stuff, as you can probably guess. This basically sorts the numbers.
sort.Ints(pageNumbers)
//Implicit return! Yay!
return
}
```
We only a couple of functions left. An imediately obvious one is the function to get a single article:
```go
//here, it takes the id of the article and returns two things: the page, and the error. This is standard practice for how go handles errors
func GetArticle(id int) (Page, error) {
//make sure the page exists with this one simple trick!
page, exists := pages[id]
if !exists {
//Another part of error handling: if there's an error, return the nil value for the first return and the error for the second. This line also includes a new import - "errors" - to make errors extremely easily
return Page{}, errors.New("Page not found!")
}
//finally, we return the page that exists and nil (the null value for an error) as the error, because there's no error
return page, nil
}
```
Another obvious one is to get all of them, so we can have links to them! However, this one is blatently obvious.
```go
func GetAllArticles() map[int]Page {
return pages
}
```
And finally, we come to our missing links. This function is called `CreateArticle`, and it creates a new article, writes it to the file, and adds it to our pages array. Here it is, annotated:
```go
//This function takes the title and the content of the article
func CreateArticle(title, content string) {
//Here, we create a new page, with the title and content aptly set
newPage := Page{
Title: title,
Content: content,
}
//Here, we make a json string out of our new page. Note the "err", which means that I had error handling after this line but omitted it
json, err := json.Marshal(newPage)
//Here, we get our page numbers, from before. They're already sorted!
pageNumbers := getPageNumbers()
//Finally, we get our new page number, by taking the last page number and adding one to it.
newPageNumber := pageNumbers[len(pageNumbers)-1] + 1
//We add the page to our pages map
pages[newPageNumber] = newPage
//Finally, we add the json to our article, converting the page number to a string and putting it in the right format. The 0600 you see there is for permissions. It basically means that the person who made the file can read and write to it, and nobody else. This is the same number that the wiki tutorial uses, by the way. Also, notice the "err"
err = ioutil.WriteFile("articles/" + strconv.Itoa(newPageNumber) + ".json", json, 0600)
}
```
And our final function, much simpler, is to remove an article. Here it is:
```go
//Notice here that we return the error type
func DeleteArticle(id int) error {
//When you assign <map>[<key>] to two values, the second value will contain a boolean saying whether the first one exists or not. We can use this to check if we have our article, and if not, return a new error saying "Article not found"
if _, exists := pages[id]; !exists {
return errors.New("Article not found")
}
//delete is built in to go. It is used to delete things from maps. Our pages variable is a map[int]page, so taking the int id and deleting it from pages would delete the article
delete(pages, id)
//Here, instead of doing the traditional "err := os.Remove(...)", we can instead return it, since we know that os.Remove returns an error. We can let whoever is using the function (which is going to be us, coincedentally) deal with it instead
return os.Remove("articles/" + strconv.Itoa(id) + ".json")
}
```
And with that, we are done with our articles file!
## Part two: Serving the pages
### Part 2.1: The templates
Go is a wonderful programming language for so many reasons, but one of them is that it has built in HTML templates! With that in mind, I created three different templates for the three main pages that will go into our blog, using Go's `html/template` module. In part 2.2, I'll talk about how I use these, but before I do that.
By the way, if you're viewing these files in the GitHub Gist, they are just called `blahblahblah.html`, but in the repl, and the final application, all of them are in the `templates` folder.
First, we have the front page. As discussed previously, the front page has the five latest articles on it. To do that, I have this code:
```html
<!DOCTYPE html>
<html>
<head>
<title>My blog!</title>
</head>
<body>
<h1>My blog!</h1>
<hr>
<!-- Here, we use range, because we pass a slice of articles to the template. This basically means that for everything between {{range .}} and {{end}}, "." will be defined as the article that we are on. -->
{{range .}}
<!-- Here, we make sure that the article exists by making sure it has a title. Previously, if we had less than five articles, we would put null articles in there, so this is to make sure that we don't have a bunch of extra space at the end of our page -->
{{if ne .Title ""}}
<!-- here, "." is defined as an instance of our Page type, so we can just access its properties like this -->
<h2>{{.Title}}</h2>
<p>{{.Content}}</p>
<hr>
{{end}}
{{end}}
<a href="/archive">See all articles</a>
</body>
</html>
```
Second, is our archive, which lets us see links to every single article. Since we use GetAllArticles() here, and that returns a map, we can use the map keys to provide links to each article.
```html
<!DOCTYPE html>
<html>
<head>
<title>My Blog - Archive</title>
</head>
<body>
<h1>My Blog - Archive</h1>
<ul>
<!-- Here, we have an unordered list using range. The reason we don't just have {{range .}} is because we need the key too, for the link -->
{{range $key, $value := .}}
<li><a href="/articles/{{$key}}">{{$value.Title}}</a></li>
{{end}}
</ul>
<a href="/">Back home</a>
</body>
</html>
```
And finally, our simplest page, the article page, which shouldn't really need annotation:
```html
<!DOCTYPE html>
<html>
<head>
<title>My Blog!</title>
</head>
<body>
<h1>{{.Title}}</h1>
<p>{{.Content}}</p>
<a href="/">Back home</a>
</body>
</html>
```
That's it for our templates!
### Part 2.2: Serving
Now that we have our files, we have to serve them to the user through our webpage! We do this with the help of one very special package, `net/http`! In clasical low-level languages, the default http solution is usually either non-existent or very hard to use. However, with go, it is actually quite easy to use `net/http`, even easier than `express` for node.js in some cases (e.g. built-in form parsing). Anyway, it handles a lot like `express`, but if you don't know `express`, don't worry about it, because I will be going through each line of code, step by step.
The file we will be writing to is `main.go`. Our first function will be the simplest and most important---the `main` function
```go
func main() {
//Initialize our files. Covered in part one, we need to put this at the top so it caches (loads) all of the files
FileInit()
//We add a *handler*, more on this in a sec, for any url that starts with /articles/. This includes /articles/1, /articles/2, and /articles/abacabadabacaba. The handler is articleFunc, a function which we will also discuss shortly
http.HandleFunc("/articles/", articleFunc)
//We add a handler for anything starting with "/", that doesn't start with "/articles/", and that handler is httpFunc.
http.HandleFunc("/", httpFunc)
//finally, we open up the server on port 8080. In a real environment, you'd use 80 for http. However, since we are using repl.it (or if you're simply testing this on your computer), we put any number we want above 1000. 8080 is a common testing number, as are 3000 and 8000. We use log.Fatal here (log is an import!) so that if http.ListenAndServe returns an error, we can stop the program and output the error.
log.Fatal(http.ListenAndServe(":8080", nil))
}
```
while this is a simple function, it packs a lot of information. Let's look at `http.HandleFunc`. `http.HandleFunc` will set a function as a handler, meaning that it will call that function when the specified url is encountered. Since we have `"/articles/"` set to `articleFunc`, every time the server gets a request for `/articles/...`, it will call articleFunc with its parameters. If the request doesn't start with `/articles/...`, it will use the next one, which in our case is `/`, the catch-all, and it will call `httpFunc`. Here's the two functions:
```go
//this func has to take the http.ResponseWriter (the thing we use to respond to the request) and a pointer to http.Request (the thing with all of the information from the request) as arguments, and returns nothing, as defined by http.HandleFunc
func articleFunc(w http.ResponseWriter, r *http.Request) {
//first, we get the article number. we do this by getting the URL and taking the "/articles/" part away from it
num := r.URL.Path[len("/articles/"):]
//Then, we see if the last character is "/", and if so, we remove it. We use single quotes here because when we access a single character of a string, it turns into a uint8, and we can convert single characters to uint8s by using single quotes around them.
if num[len(num) - 1] == '/' {
//Subtracting the last element, a slash
num = num[:len(num) - 1]
}
//here, we convert the string to a number. If you go to /articles/1, you're fine, but if you go to /articles/abc, the function errors, leading us to the next if statement
pageNum, err := strconv.Atoi(num)
if err != nil {
//I chose not to omit this one because here instead of log.Fatal, we use http.NotFound, giving it our w and r.
http.NotFound(w, r)
}
//Get the article from previous
page, err := GetArticle(pageNum)
if err != nil {
//the only error that returns is "Page not found" so we can safely assume that there's a 404
http.NotFound(w, r)
} else {
//then, we simply execute the templat---wait a sec, executing templates? We didn't talk about this yet! Well, hang on, and in just a sec I'll show you this wizardry.
executeTemplate(w, "article.html", page)
}
}
```
And here's `httpFunc`, the simpler one:
```go
func httpFunc(w http.ResponseWriter, r *http.Request) {
//first, we make a switch, a more efficient set of if statements
switch r.URL.Path {
//"/" and "/index.html" are both the same thing, so we do the same thing for them
case "/", "/index.html":
//oh, there's that pesky executeTemplate function again! I promise I'll get to it, just hang tight! Anyway, our front page uses the GetFrontPage function.
executeTemplate(w, "frontPage.html", GetFrontPage())
//finally, we return out of the case, to end the function.
return
//pretty much the same thing as above
case "/archive", "/archive.html":
executeTemplate(w, "archive.html", GetAllArticles())
return
}
//Finally, if we haven't returned, that means that our thing was not found, so that's exactly what we do: error!
http.NotFound(w, r)
}
```
Now I've got you hooked---surely, you are wondering "What is this `executeTemplate` function? How does it work?!?"---here, we use another wonderful built-in method of Go: the built in HTML Templates! Wait... we've heard this one before, haven't we? Well here we are, putting our wonderful templates to good use. We start with this line, at the beginnning (after all of the imports, of course)
```go
//make sure you import "html/template"
var templates = template.Must(template.ParseGlob("./templates/*.html"))
```
Basically, with this line, we make a templates variable and set it to all of the templates in our templates folder (ParseGlob). The `template.Must` part is basically just a convinient wrapper around it saying that if there's an error, the app should exit immediately with that error. Since this happens at the very start and at no other time, this is OK! Anyway, let's look at our `executeTemplates` function to see how we managed to pull this off:
This function takes three parameters. It needs the http.ResponseWriter from our http funcs so that it can write the response to them. It also needs to know what template is being executed. Finally, it needs the content. Since the content and template are different each time, we use an "interface{}", meaning we don't really know the type. In fact, we don't have to know the type at all, because ExecuteTemplate takes a "interface{}" for its content, so as long as we match everything up when we call the function, we should be fine.
```go
//I was going to put the above paragraph right here as a comment but I realized it was getting too long
func executeTemplate(w http.ResponseWriter, templ string, content interface{}) {
//We use templates.ExecuteTemplate() to execute the specific template we want out of the ones we loaded. You can see how this is used in the useage of the function in previous functions.
err := templates.ExecuteTemplate(w, templ, content)
if err != nil {
//Here, instead of killing the server, we give them the error, and a 500 internal server error.
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
```
That's pretty much it for our main.go file... *so far...*
# Part 3 - Administration!
This is our final and hardest part, and that is being able to delete and create articles without booting into the repl. Since you can't get packages for go yet, you have to do some work arounds, which I spent a lot of time finding out, so you're going to have to carefully follow these steps:
* Make yourself an explorer ([how](https://repl.it/talk/announcements/Become-an-Explorer/6180))
* Open the command pallete by making sure the editor is in focus and pressing F1
* Type in shell, press enter
* Type in: `go get golang.org/x/crypto/bcrypt`
* Press enter. You might get an error, ignore it (unless it leads to further issues)
Why are we doing all this? Well, we can't just store our password in plain text! We have to make sure that it is protected securely, and the way to do that is to use the bcrypt library (there are some others you can use too, but bcrypt is pretty much the industry standard). Other than the first step, which you only need to do once, you may have to do this every time you load up your repl, because of how repl.it works, unfortunately.
Anyway, with that out of the way, let's look at how we're going to do things.
We will have a "/dashboard" page, pretty similar to our "/archive" page, but this time we will add buttons to delete articles and to create new ones. This part is pretty simple, so we can add this case to our switch inside of `httpFunc`:
```go
case "/dashboard", "/dashboard.html":
executeTemplate(w, "dashboard.html", GetAllArticles())
return
```
The dashboard itself, though, will be a little bit more complicated. It utilizes javascript to make a "DELETE" request to the server when articles are deleted, but you don't have to worry about knowing javascript, because I can walk you through it:
```html
<!DOCTYPE html>
<html>
<head>
<title>My Blog - Archive</title>
</head>
<body>
<h1>My Blog - Archive</h1>
<!-- Button links to the "/new" page, for making new articles -->
<a href="/new">New article</a><br>
<!-- same as before, with the article, except... -->
<ul>
{{range $key, $value := .}}
<!-- Here, we have a button element, and when it is clicked, it calls the del function in our javascript with the paramater being our key. -->
<li><a href="/articles/{{$key}}">{{$value.Title}}</a> | <button onClick="del({{$key}})">Delete</button></li>
{{end}}
</ul>
</form>
<a href="/">Back home</a>
<script>
//Here's our del function! Javascript doesn't care about types, but the equivalent in go would be "func del(key int) {"
function del(key) {
//The prompt function creates a dialog box asking for a password
password = prompt("Please enter your password");
//We create a new formData object to turn our password into formdata that go can then use
let formData = new FormData();
formData.append("password", password)
//We use fetch to make the request. The key there will be replaced with whatever the key that's passed to the function is
fetch(`/delete/${key}`, {
//For our options, we set the method to DELETE (as to be fancy), and our body to the formData from earlier
method: "DELETE",
body: formData
//javascript async mumbo jumbo that translates to "get the text from it"
}).then(r => r.text()).then(r => {
//if it isn't successful then we alert the error, otherwise we reload the page to reflect the change.
if (r !== "Article successfully deleted") {
alert(r);
} else {
location.reload();
}
//finally, if something goes wrong, we alert that too
}).catch(alert);
}
</script>
</body>
</html>
```
See? That wasn't so hard. But wait, how do we handle these requests? Well, let me introduce you to the next function in our `main.go` file, `deleteFunc`. This will also introduce us to how go's `bcrypt` library works. To use this function, put `http.HandleFunc("/delete/", deleteFunc)` in your main function, anywhere above the "/" handler.
```go
//The function is formatted like a normal http.HandlerFunc
func deleteFunc(w http.ResponseWriter, r *http.Request) {
//Here, we get the key by removing "/delete/" from the path.
strKey := r.URL.Path[len("/delete/"):]
//We use strconv to convert the key to an actual key.
key, err := strconv.Atoi(strKey)
//If, of course, the key isn't an int, we error with a 400, meaning there was a bad request
if err != nil {
http.Error(w, "That's not a valid key", http.StatusBadRequest)
//And stop executing
return
}
//Now, if the method is DELETE (which it should be)...
if r.Method == "DELETE" {
//We make sure that the form sent has a password value. If not, we error, again with a 400.
if r.FormValue("password") == "" {
http.Error(w, "Password is missing", http.StatusBadRequest)
//Otherwise...
} else {
//Remember this line. This is how we use bcrypt to check passwords. Also, remember "pwHash," because we'll talk about that in a second. Anyway, as you can probably guess, this converts the two strings to byte slices before comparing them, because that's what bcrypt uses
err := bcrypt.CompareHashAndPassword([]byte(pwHash), []byte(r.FormValue("password")))
//Instead of returning a boolean, bcrypt will return an error if they don't match. http.StatusUnauthorized, yet another constant, is 401.
if err != nil {
http.Error(w, "Password does not match", http.StatusUnauthorized)
} else {
//Finally, the user has been authenticated, and we can use our DeleteArticle function from earlier to delete the article with that key
err = DeleteArticle(key)
if err != nil {
//If you look back to our DeleteArticle function, you'll remember that we error with Article not found when an article isn't found. Now, we can check this!
if err.Error() == "Article not found" {
http.Error(w, "Article not found", http.StatusNotFound)
} else {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
} else {
fmt.Fprint(w, "Article successfully deleted")
}
}
}
} else {
http.Redirect(w, r, "/", http.StatusFound)
}
}
```
If you try running that code in it's current state, you will notice that it errors. In fact, it will say that `pwHash` is not defined! So, let's fix that.
* First, go to a website that generates bcrypt hashes, and put in the password you want to do. [Here's a site that does it!](https://www.browserling.com/tools/bcrypt)
* Then, make a `.env` file in your repl.
* Inside of that file, put `PASSWORD=<your bcrypt hash>`, where `<your bcrypt hash>` is replaced with the hash that the website generated
* Last two steps! Put `var pwHash = os.Getenv("PASSWORD")` at the top of your file, and...
* Put the following code at top of your *main* function
```go
if pwHash == "" {
log.Fatal("There is no password set! Please create a file called .env and make the contents \"PASSWORD=asdf\", with your password bcrypt hashed instead of asdf ")
}
```
Now, if you've done all of these steps correctly, you should have a working dashboard, where you can delete articles! But, there is *one more thing*. We need to be able to add *new* pages as well! Let's first make a page, called `new.html`, where the user can put in a new article:
```html
<!DOCTYPE html>
<html>
<head>
<title>My Blog - New!</title>
</head>
<body>
<h1>New Article</h1>
<!-- This <form> tag makes it so that when someone clicks the submit button, it makes a POST request to the /new page with the information in the form -->
<form method="POST" action="/new">
<label for="title">Title</label>
<!-- Here, we use the required attribute to make sure that the user inputs it. However, this is not enough! We also have some checks on the server side which make sure the title (and password) are sent -->
<input name="title" type="text" required><br>
<label for="content">Content</label><br>
<textarea name="content" rows="20" cols="100" required></textarea><br>
<label for="password">Password</label>
<input name="password" type="password" required><br>
<!-- When the user clicks on the following button, the browser will make a POST request to the server to make the new article! -->
<button type="submit">Submit</title>
</form>
</body>
</html>
```
Finally, we have to handle the article. However, you might notice that I made the form make a POST request to `/new`. Isn't the page called `/new.html`? When we handle this, we're going to check the request type. If it's a post request, we process it. If it's any other type of request, including a GET request, we will send the page. Here's how we handle it, the final part to our program:
```go
//You may notice that we are indented, and it starts with a case statement. This is because this part goes into our main "httpFunc" from earlier.
case "/new", "/new.html":
//Here's where we make the aforementioned check
if r.Method == "POST" {
//We have to make sure that the form actually sent over all of the information. r.FormValue("thing that wasn't sent") returns an empty string, so we can check on that
if r.FormValue("content") == "" || r.FormValue("title") == "" || r.FormValue("password") == "" {
http.Error(w, "Either the content, title, or password are missing", http.StatusBadRequest)
} else {
//Assuming it passes, we move on to the next step, checking the password, just like last time in our deleteFunc
err := bcrypt.CompareHashAndPassword([]byte(pwHash), []byte(r.FormValue("password")))
if err != nil {
http.Error(w, "Password does not match", http.StatusUnauthorized)
} else {
//Finally, we create our article.
CreateArticle(r.FormValue("title"), r.FormValue("content"))
//And send the user to the front page
http.Redirect(w, r, "/", http.StatusFound)
}
}
} else {
//If you hop back up to where that { was opened, you'll see this was right after "if r.Method == "POST" {", so this is the part where we serve the page, as the request was *not* a POST but rather a GET (or something else, we don't care)
executeTemplate(w, "new.html", []string{})//this last one doesn't matter, we aren't using anything in the template
}
return
```
And that's it! We are done with our Blog!
## Next Steps
I left a challenge in the tutorial! Take a look at `DeleteArticle` and `GetArticle` in our `articles.go` file, and see how they differ from the other functions in that file. They both return an `error` as their last (or only) return value! Your goal is to reformat all of the other functions to return an `error` as well, instead of using `log.Fatal()`, which kills the blog. Finally, every time these functions are used, make it so that if there was an error, it returns an error to the client with an HTTP code 500 (Internal Server Error), like in our `executeTemplate` function (main.go) or our `deleteFunc` function (main.go).