DEV Community

Kenta Takeuchi
Kenta Takeuchi

Posted on • Originally published at qiita.com

Summary of "Introduction to Golang HTTP router made with net/http"

This article is a translation of qiita.com.com --Self-made HTTP router made with net / http

This is a summary of the article I wrote the other day.

I wrote this article because I wish I could get more people's eyes and feedback.

I'm waiting for a star to bmf-san/goblin. :D

If you just want to see the code, see below.
bmf-san/introduction-to-golang-http-router-made-with-net-http/blob/main/trie.go

I would be grateful if you could also see the HTTP router I made.
bmf-san/goblin

What are you talking about?

It's a story about how to think and how to make your own HTTP router using only standard packages in Go.

Create your own HTTP router like the one below.
bmf-san/introduction-to-golang-http-router-made-with-net-http/blob/main/trie.go

What's interesting?

  • It will be an opportunity to deepen your understanding of net/http
  • It will be an opportunity to learn algorithms and data structures
  • You can know the contents of the HTTP router
  • You can make your own HTTP router and play with it.

Prerequisite knowledge

  • Understanding the basic grammar of Go
  • It would be nice if you had touched some kind of HTTP router

What is an HTTP router?

It is an application that connects the requested URL and the processing of the response.

route_in_client_and_server

Mapped data is required to connect the URL and the process.

Request URL Handler
GET / IndexHandler
GET /foo FooHandler
POST /foo FooHandler
GET /foo/:id FooHandler
POST /foo/:id FooHandler
GET /foo/:id/:name FooHandler
POST /foo/:id/:name FooHandler
GET /foo/bar FooBarHandler
GET /foo/bar/:id FooBarHandler
GET /foo/bar/:id/:name FooBarHandler
GET /foo/bar/baz FooBarBazHandler
GET /bar BarHandler
GET /baz BazHandler

Inside the HTTP router, such data is converted into a manageable data structure and held.

data structure

Adopt a tree structure that is just right for expressing the hierarchical structure of URLs.

tree_structure

The tree is made up of Nodes. The Node at the top is called Root, and the Node at the bottom is called Leaf. The "branch" that connects Nodes is called Edge.

The operation to add a Node to a tree is called Insert, and the operation to find a Node from a tree is called Search.

When making your own HTTP router, I think you should know at least this much.

It is even better to understand one of the basic trees in the world of algorithms and data structures, the binary search tree.

bmf-tech.com - アルゴリズムとデータ構造 - 二分探索木

In talking about my own work this time, I will adopt a tree structure based on a data structure called a trie tree.

I think that many libraries adopt some kind of tree structure in the observation range, but it seems that famous places often adopt a data structure called radix tree.

For a description of tri-trees, see bmf-tech.com - Golangでトライ木を実装する
, so I will omit it.

For an understanding of the algorithm, we also recommend Algorithm Visualizations - Trie (Prefix Tree).

Since we will implement a tree structure based on the tri-tree, if you understand the tri-tree, it will be easier to understand the implementation of the HTTP router you will make this time.

The data structure of the HTTP router that I make this time is the following tree structure.

tree_for_implementation

This tree structure represents the following mapping of URL and response processing.

Request URL Handler
GET / IndexHandler
GET /foo FooHandler
POST /foo FooHandler
GET /foo/bar FooBarHandler
GET /foo/bar/baz FooBarBazHandler
GET /bar BarHandler
GET /baz BazHandler

Since it is an introduction, it is assumed that the functions will be reduced as much as possible and simple things will be implemented.

net/http Basic knowledge

We need to know how to use net/http to extend the functionality of HTTP routers, so let's sort out the points.

net/http has features called multiplexers and handlers.

The multiplexer has the role of comparing the URL of the request with the registered pattern and calling the handler that matches the best.

The handler is responsible for returning the processing in response to the request.

Go allows you to implement an HTTP server with just a few lines of code.

package main

import (
"fmt"
"net / http"
)

func main () {
mux: = http.NewServeMux ()
mux.HandleFunc ("/", handler)

http.ListenAndServe (": 8080", mux)
}

func handler (w http.ResponseWriter, r * http.Request) {
fmt.Fprintf (w, "Hello World")
}
Enter fullscreen mode Exit fullscreen mode

From the above code, if you read the net / http code with the following points in mind, you can see what to implement.

  • Where and how the multiplexer registers handlers, and what are the specifications for matching URLs and patterns?
  • How to create a handler (whether there is a variation of handler creation, what interface should be satisfied)

Details bmf-tech.com - 第3章HTTPサーバーのコードリーディング, so please refer to it if you have time.

Implementation

As I introduced at the beginning, the HTTP router implemented this time is in the following repository.

bmf-san/introduction-to-golang-http-router-made-with-net-http

This time we will implement a simple HTTP router that "supports method-based routing".

  • Since it is a summary version, detailed explanation of the code is omitted.

Method-based routing means that you can register URLs by HTTP method.

In the function of Go standard package only, if you want to route by method, you need to implement conditional branching in the handler.

// ex.
func indexHandler (w http.ResponseWriter, r * http.Request) {
    switch r.Method {
        case http.MethodGet:
            // do something ...
        case http.MethodPost:
            // do something ...

        ...

        default: default:
Enter fullscreen mode Exit fullscreen mode

This time, we will implement it only with the goal of eliminating this trouble.

In order to achieve method-based routing, we will adopt a tri-tree-based data structure.

Since it is a simple function, a simpler data structure (such as making it possible to use the standard multiplexer function for each method) is fine, but we will adopt it in anticipation of various implementations later. (To be honest, I just simplified the implementation of bmf-san/goblin.)

The general things to do in implementing an HTTP router are as follows.

The first thing you want to do to implement is to implement the data structure.

tree_for_implementation

It is easier to work if you use the debug function of the editor (using delve in vscode) or write test code to check if it is implemented well.

For implementation details, see bmf-tech.com - 第4章HTTPルーターの実装.

Summary

HTTP routers are almost indispensable for creating web applications, and aren't they very much taken care of?

My motivation was that I wanted to make something that I used as a matter of course and use it myself.

There are already a lot of great HTTP routers out there, so I think one of the real thrills is that it's worth researching.

This time I implemented it in Go, but if I understand the mechanism, I think that it can be implemented in languages ​​other than Go.

In Go, the interface is provided in a form that makes it easy to extend the function of the standard package, so I felt that it was relatively easy to make by myself.

If you are interested in this article, I would be grateful if you could take a look at bmf-san/goblin.

Feel free to send an Issue or Pull Request. :D

Discussion (0)