Si vous avez déjà travaillé avec des frameworks Web comme Express.js, vous savez à quel point ils peuvent être pratiques et faciles à utiliser. Imaginez maintenant cette simplicité dans Go, avec ses performances et sa robustesse. Eh bien, cela m'a motivé à créer express-go, un micro-framework inspiré d'Express.js, et le meilleur de tout : je l'ai construit en 19 heures ! Le voyage a été intense, mais chaque seconde en valait la peine. Laissez-moi vous raconter comment tout cela s'est passé. Lien du référentiel officiel
Tout a commencé quand j'ai pensé : "Ce serait cool d'avoir quelque chose de simple comme Express.js, mais avec les performances de Go !". Go est déjà connu pour être minimaliste et performant, mais lorsqu'il s'agissait d'écrire des serveurs Web, j'avais l'impression qu'il manquait encore quelque chose de plus facile à utiliser comme Express.js.
Alors au lieu de me plaindre, j'ai décidé de me salir les mains et de faire bouger les choses. J'étais déterminé à créer un micro-framework qui me permettrait de configurer des routes, de gérer les requêtes et les réponses HTTP rapidement et facilement.
J'ai commencé avec la structure de base : une application Go qui pouvait écouter les requêtes HTTP et, selon le parcours, remplir différentes fonctions.
La première chose que je devais faire était de configurer le routage. J'aurais aimé qu'il soit possible de définir des itinéraires de la même manière qu'Express.js, où vous spécifiez une URL et une fonction pour gérer cet itinéraire.
Voici la magie des itinéraires :
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) }
L'idée ici était simple : je voulais une feuille de route (map[string]func) où la clé était l'URL et la valeur était la fonction qui gérerait la requête.
L'une des choses que j'ai le plus appréciées dans Express.js était la facilité d'utilisation des gestionnaires de routes. J'ai donc adopté l'idée que chaque route serait juste une fonction qui recevrait deux paramètres : la requête et la réponse. Dans Go, c'est un peu plus de travail, car la bibliothèque standard nécessite beaucoup de travail manuel, j'ai donc écrit quelques abstractions pour faciliter les choses.
Traitement des demandes
Les requêtes HTTP dans Go impliquent de nombreuses structures et méthodes, j'ai donc encapsulé tout cela dans une structure appelée Request, avec des méthodes pratiques pour obtenir les paramètres de requête, les en-têtes et le corps de la requête.
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 }
Maintenant, au lieu de traiter directement la http.Request, je peux faire quelque chose comme :
app.Route("/greet", func(r *req.Request, w *req.Response) { name := r.QueryParam("name") if name == "" { name = "Guest" } w.Send("Hello, " + name + "!") })
Cela rend les choses beaucoup plus propres et plus lisibles !
Après les demandes, il était temps de faciliter l'envoi des réponses. La réponse avait également besoin d'une touche de simplicité pour que je puisse envoyer rapidement du texte ou des 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) }
Au terme de ces 19 heures de travail, j'ai réussi à créer express-go : un micro-framework rapide et facile à utiliser, où configurer les itinéraires et envoyer des réponses est aussi simple qu'Express.js, mais avec tout la puissance et les performances du Go.
Voici un exemple complet de la façon dont tout cela s'articule :
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 }
Simple, propre et pertinent. Je suis fier de dire que j'ai pu construire cela en moins d'une journée, et ce qui est cool, c'est qu'il offre suffisamment de flexibilité pour les petits projets, sans toute la complexité des frameworks plus grands.
Créer l'express-go en 19 heures a été un voyage amusant et stimulant. Je me suis concentré sur la résolution des problèmes réels auxquels j'ai été confronté avec les serveurs Go et j'ai essayé de rendre tout aussi intuitif que possible. Bien sûr, il y a encore du travail à faire, mais il y a de quoi jouer !
Si vous êtes curieux, jetez un œil au code et n'hésitez pas à contribuer. Après tout, créer des outils comme celui-ci est bien plus cool lorsque nous pouvons partager le processus !
Maintenant, si tu veux bien m'excuser, je vais prendre un café... après 19 heures, je le mérite, non ?
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!