Building a text editor in Go: Setting up the backend

faraazahmad

Syed Faraaz Ahmad

Posted on November 10, 2019

Building a text editor in Go: Setting up the backend

Here we will be using (the programming language) Go, if you don't have it installed, you can do so from its official website. If you're also looking to learn the language on the Go (hah!), or want to brush up some of its concepts, I suggest you take a look here.

Let's start working on that backend.

For backend, we'll be using an HTTP server built in Go. So create a file named backend.go and add the following code to it.

package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, Editor")
    })

    log.Fatal(http.ListenAndServe(":3000", nil))

}
Enter fullscreen mode Exit fullscreen mode

Hold up

Hold up, let me explain.

Routing

For those who don’t know, URL routing is the practice of taking a URL pattern and mapping it to some function that does a task when a user reaches that URL. For example, if I write

http.HandleFunc("/hello", doStuff)
Enter fullscreen mode Exit fullscreen mode

and visit the '/hello' path, the function doStuff will be executed, simple enough.

http.HandleFunc does just that, registers a handler for the route whose pattern has been provided. It takes in 2 arguments, a string representing the URL pattern you want to route to, and a handler function that, in turn, takes 2 of its own arguments.

  1. A copy of an http.ResponseWriter instance, to handle send responses from the server.

  2. *http.Request, a pointer of the request made to the server, that contains information about the request, like URL parameters, message body, etc.

In the end, we have log.Fatal(http.ListenAndServe(":3000", nil)). log.Fatal is equivalent to printing and exiting the program, so any code you write after it will not be reachable. Here, try running this seperate program:

package main

import (
    "fmt"
    "log"
)

func main() {
    log.Fatal("I use Arch btw")
    fmt.Println("Yeah nobody cares")
}
Enter fullscreen mode Exit fullscreen mode

You'll get an output like this:

2019/11/10 03:27:26 I use Arch btw
exit status 1
Enter fullscreen mode Exit fullscreen mode

or if you're running on ideone, you'll get a runtime error. You can execute the line below by removing the log.Fatal line as well as "log" from the import block.

http.ListenAndServe finally starts the server and listens for requests on the port number provided, (3000) in our case, and returns an error if there is one. In case, there is an error (or if you press Ctrl+c to stop the server), log.Fatal is there to stop the print the error and stop the execution. You can learn more about http.ListenAndServe here.

Now run the server using

go run backend.go
Enter fullscreen mode Exit fullscreen mode

and visit localhost:3000 in your browser. You should see a blank page with "Hello, Editor" written. Congratulations, you have succesfully built an HTTP server in Go.

Nice

Now go (bad pun count = 2) execute a mad king or something, then come back when you're done, we'll add some functionality.

Creating routes and their handlers

Since we have 2 pages — open and edit — we'll create 2 separate routes and handlers for these.

// backend.go

// ...

func fileOpenHandler(w http.ResponseWriter, r *http.Request) {
    // do stuff
}

func fileEditHandler(w http.ResponseWriter, r *http.Request) {
    // do stuff
}

func main() {
       // ...   

    http.HandleFunc("/file/open", fileOpenHandler)
    http.HandleFunc("/file/edit", fileEditHandler)

      // ...
}
Enter fullscreen mode Exit fullscreen mode

If we visit these parts, nothing happens because the function bodies are empty. When we open these links, we want our server to serve the HTML files we've created for these paths. Luckily there's a function for that:

http.ServeFile.

Let's add that to our handlers, like so:

// backend.go

// ...

func fileOpenHandler(w http.ResponseWriter, r *http.Request) {
    http.ServeFile(w, r, "open.html")
}

func fileEditHandler(w http.ResponseWriter, r *http.Request) {
    http.ServeFile(w, r, "edit.html")
}

// ...
Enter fullscreen mode Exit fullscreen mode

That's it, now when you open localhost:3000/file/open or localhost:3000/file/edit you'll see the HTML pages you created (make sure they are in the same directory as this Go file).

Also put the handler function for the "/" into its own function and call it homeHandler. Here's the whole backend.go file:

package main

import (
    "fmt"
    "log"
    "net/http"
)

func homeHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, Editor")
}

func fileOpenHandler(w http.ResponseWriter, r *http.Request) {
    http.ServeFile(w, r, "open.html")
}

func fileEditHandler(w http.ResponseWriter, r *http.Request) {
    http.ServeFile(w, r, "edit.html")
}

func main() {
    // decare routes
    http.HandleFunc("/", homeHandler)
    http.HandleFunc("/file/open", fileOpenHandler)
    http.HandleFunc("/file/edit", fileEditHandler)

    // run server
    fmt.Println("Server listening at localost:3000")
    log.Fatal(http.ListenAndServe(":3000", nil))
}
Enter fullscreen mode Exit fullscreen mode

I'm done

Until next time ...?

Cover image by Eduardo Higareda

💖 💪 🙅 🚩
faraazahmad
Syed Faraaz Ahmad

Posted on November 10, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related