DEV Community

Cover image for Building a text editor in Go: Setting up the backend
Syed Faraaz Ahmad
Syed Faraaz Ahmad

Posted on • Updated on

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

Top comments (8)

Collapse
 
mike_congdon profile image
Mike Congdon

I'm all for shoe-horning languages I like to do things that they aren't optimised for to create tools that already exist!

But actually, I am. And this is pretty cool.
I think it might make more sense to use one of the Go Gui libraries to do this though (speaking of things the language isn't optimised for).

Looks good so far!

Collapse
 
faraazahmad profile image
Syed Faraaz Ahmad

Thank you! I totally hear you, but I want the series to be super friendly for beginners and IMO HTML is the easiest way to hack together a basic UI.

Maybe I'll create another series about GUI programming in Go 😉

Collapse
 
theantichris profile image
Christopher Lamm

When will the next part be available?

Collapse
 
faraazahmad profile image
Syed Faraaz Ahmad

Soon! I'll be done with my semester exams in a week so it'll be out around that time.

I'm really glad you like this series! What would you say I need to improve?

Collapse
 
rohansawant profile image
Rohan Sawant

Nice! An informative read! You GO Syed! 🔥

Collapse
 
faraazahmad profile image
Syed Faraaz Ahmad

Thank you! I'll Go write the next part 😉

Collapse
 
phpcoder profile image
Slava Semushin

http.ListenAndServe finally starts the server and listens for requests on the port number provided, (8081) in our case

There is a typo: it's 3000.

Collapse
 
faraazahmad profile image
Syed Faraaz Ahmad

Thank you! it's fixed now