ホームページ  >  記事  >  バックエンド開発  >  Express-Go を数時間で書いた方法

Express-Go を数時間で書いた方法

Patricia Arquette
Patricia Arquetteオリジナル
2024-10-20 06:14:02325ブラウズ

How I Wrote Express-Go in Hours

Express.js のような Web フレームワークを使用したことがある場合は、それがいかに便利で使いやすいかをご存知でしょう。では、パフォーマンスと堅牢性を備えた Go のこの使いやすさを想像してみてください。それが、Express.js からインスピレーションを得たマイクロ フレームワークである Express-go を作成する動機になりました。そして何よりも、19 時間で構築できました。その旅は激しいものでしたが、一秒一秒に価値がありました。それがどうやって起こったのかお話しましょう。公式リポジトリのリンク

アイデア

すべては、「Express.js のようなシンプルで、しかも Go のパフォーマンスを備えたものがあれば素晴らしいだろう!」と考えたことが始まりでした。 Go はミニマリストでパフォーマンスが高いことですでに知られていますが、Web サーバーを作成することになると、Express.js のような使いやすいものがまだ欠けていると感じました。

そこで私は、不平を言う代わりに、自分の手を汚して何かを起こそうと決心しました。私は、ルートを設定し、HTTP リクエストとレスポンスを迅速かつ簡単に処理できるマイクロ フレームワークを作成することに決めました。

旅の始まり

基本的な構造から始めました。これは、HTTP リクエストをリッスンし、ルートに応じてさまざまな機能を実行できる Go アプリケーションです。

最初の目的地: ルート

最初に行う必要があるのは、ルーティングを設定することでした。 Express.js と同じように、URL とそのルートを処理する関数を指定してルートを定義できればいいのにと思います。

これがルートの魔法です:

type App struct {
    routes map[string]func(req *req.Request, res *req.Response)
}

func NewApp() *App {
    return &App{
        routes: make(map[string]func(req *req.Request, res *req.Response)),
    }
}

func (a *App) Route(path string, handler func(req *req.Request, res *req.Response)) {
    a.routes[path] = handler
}

func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if handler, exists := a.routes[r.URL.Path]; exists {
        request := req.NewRequest(r)
        response := req.NewResponse(w)
        handler(request, response)
    } else {
        http.NotFound(w, r)
    }
}

func (a *App) Listen(addr string) error {
    return http.ListenAndServe(addr, a)
}

ここでのアイデアは単純でした。キーが URL で、値がリクエストを処理する関数であるルート マップ (map[string]func) が必要でした。

ハンドラーの魔法

Express.js で最も気に入ったことの 1 つは、ルート ハンドラーの使いやすさでした。そこで、各ルートはリクエストとレスポンスという 2 つのパラメータを受け取る単なる関数になるという考えを採用しました。 Go では、標準ライブラリでは多くの手動作業が必要になるため、これはもう少し手間がかかります。そのため、作業を容易にするためにいくつかの抽象化を作成しました。

リクエストの処理
Go の HTTP リクエストには多くの構造とメソッドが含まれるため、クエリ パラメーター、ヘッダー、リクエスト本文を取得するための便利なメソッドを含めて、これらすべてを Request という構造体にカプセル化しました。

type Request struct {
    Req  *http.Request
    Body string
}

func NewRequest(req *http.Request) *Request {

    bodyBytes, _ := io.ReadAll(req.Body)
    bodyString := string(bodyBytes)

    return &Request{
        Req:  req,
        Body: bodyString,
    }
}

func (r *Request) QueryParam(key string) string {
    params := r.Req.URL.Query()
    return params.Get(key)
}

func (r *Request) Header(key string) string {
    return r.Req.Header.Get(key)
}

func (r *Request) BodyAsString() string {
    return r.Body
}

ここで、http.Request を直接処理する代わりに、次のようなことができます。

app.Route("/greet", func(r *req.Request, w *req.Response) {
    name := r.QueryParam("name")
    if name == "" {
        name = "Guest"
    }
    w.Send("Hello, " + name + "!")
})

これにより、内容がよりすっきりして読みやすくなります。

応答が簡単

リクエストの後は、返信を簡単に送信できるようにする必要がありました。テキストや JSON をすばやく送信できるように、応答にも少しのシンプルさが必要でした。

type App struct {
    routes map[string]func(req *req.Request, res *req.Response)
}

func NewApp() *App {
    return &App{
        routes: make(map[string]func(req *req.Request, res *req.Response)),
    }
}

func (a *App) Route(path string, handler func(req *req.Request, res *req.Response)) {
    a.routes[path] = handler
}

func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if handler, exists := a.routes[r.URL.Path]; exists {
        request := req.NewRequest(r)
        response := req.NewResponse(w)
        handler(request, response)
    } else {
        http.NotFound(w, r)
    }
}

func (a *App) Listen(addr string) error {
    return http.ListenAndServe(addr, a)
}

結果

この 19 時間の作業の終わりに、私は Express-go を作成することができました。これは高速で使いやすいマイクロフレームワークで、ルートの構成と応答の送信は Express.js と同じくらい簡単ですが、すべての機能が備わっています。囲碁のパワーとパフォーマンス

使用例:

すべてがどのように組み合わされるかを示す完全な例を次に示します。

type Request struct {
    Req  *http.Request
    Body string
}

func NewRequest(req *http.Request) *Request {

    bodyBytes, _ := io.ReadAll(req.Body)
    bodyString := string(bodyBytes)

    return &Request{
        Req:  req,
        Body: bodyString,
    }
}

func (r *Request) QueryParam(key string) string {
    params := r.Req.URL.Query()
    return params.Get(key)
}

func (r *Request) Header(key string) string {
    return r.Req.Header.Get(key)
}

func (r *Request) BodyAsString() string {
    return r.Body
}

シンプル、クリーン、要点を絞ったもの。これを 1 日もかからずに構築できたことを誇りに思います。また、素晴らしい点は、大規模なフレームワークのような複雑さをまったく感じることなく、小規模なプロジェクトに十分な柔軟性を提供できることです。

最後の反省

19 時間で特急号を作るのは楽しくてやりがいのある旅でした。私は Go サーバーで直面した実際の問題を解決することに重点を置き、すべてをできるだけ直感的にできるように努めました。もちろん、やるべきことはたくさんありますが、遊べることはたくさんあります!

ご興味がございましたら、コードをご覧になり、お気軽に貢献してください。結局のところ、プロセスを共有できれば、このようなツールを構築する方がずっとクールになります!

それでは、失礼しますが、コーヒーを飲みに行きます...19 時間経ったので、飲むのは当然ですよね?

以上がExpress-Go を数時間で書いた方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。