Click to play video
Congratulations! You made an HTTP request parser and, honestly, that's the hardest part of this course. But of course, we're not done yet. Now let's build the actual server interface that handles the requests and sends responses.
In Bun (JavaScript, I know, sorry), they have a very simple server implementation that looks like this in code:
const server = Bun.serve({
port: 8080,
async fetch(req) {
return new Response("Bun!");
}
}
It's fairly similar to Go's http.ListenAndServe:
server := &http.Server{
Addr: ":8080",
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Go!")
}),
}
server.ListenAndServe()
We're going to follow a similar pattern, with a few differences that I'll point out as we get to them.
In this step we'll be upgrading from a tcplistener to an actual httpserver! It will accept valid requests and send valid responses. That said, for now, no matter what request is sent, the response will always be the same.
const port = 42069
func main() {
server, err := server.Serve(port)
if err != nil {
log.Fatalf("Error starting server: %v", err)
}
defer server.Close()
log.Println("Server started on port", port)
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
<-sigChan
log.Println("Server gracefully stopped")
}
As you can see, we've settled on a server.Serve function. This is where all the magic happens. It accepts a port and starts handling requests that come in. In a future step we'll allow it to accept a handler function, but for now, we're going to hardcode the response.
Notice the sigChan code. This is a common pattern in Go for gracefully shutting down a server. Because server.Serve returns immediately (it handles requests in the background in goroutines) if we exit main immediately, the server will just stop. We want to wait for a signal (like CTRL+C) before we stop the server.
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 13
Hello World!
Run and submit the CLI tests with your server running.