Ya hemos hablado de zero el framework de go para hacer microservicios. Ahora vamos a bajar las herramientas para trabajar con él.
Primero, tenemos que tener go instalado. Yo tengo la versión 1.22.0
$ go version
go version go1.22.0 linux/amd64
Primero, tenemos que tener go instalado. Yo tengo la versión 1.22.0
$ go version
go version go1.22.0 linux/amd64
# Create workspaces and enter the directory
$ mkdir -p ~/workspace/api && cd ~/workspace/api
# Execute instructions generated demo service
$ goctl api new demo
Done.
Después de ejecutar la instrucción, se generará un directorio de demostración en el directorio actual que contiene un servicio HTTP minimizado, verificaremos la estructura del directorio del servicio.
$ cd ~/workspace/api/demo
$ ls
demo.api demo.go etc go.mod internal
$ tree
.
├── demo.api
├── demo.go
├── etc
│ └── demo-api.yaml
├── go.mod
└── internal
├── config
│ └── config.go
├── handler
│ ├── demohandler.go
│ └── routes.go
├── logic
│ └── demologic.go
├── svc
│ └── servicecontext.go
└── types
└── types.go
Después de completar la generación del código anterior, podemos encontrar los archivos ~/workspace/api/demo/internal/logic/demologic.go, y podemos completar el códigos entre las líneas 27 y 28:
resp = new(types.Response)
resp.Message = req.Name
Después de escribir el código anterior, podemos iniciar el servicio con las siguientes instrucciones:
# Enter service directory
$ cd ~/workspace/api/demo
# to organize dependencies
$ go mod tidy
# Run go program
$ go run demo.go
Cuando vea el siguiente resultado "Starting server at 0.0.0.0.0:888.." indica que el servicio se ha iniciado correctamente, entonces visitamos el servicio HTTP.
$ curl --request GET 'http://127.0.0.0.1:8888/from/me'
Cuando vea el resultado en la terminal {"message":"me"} en nombre de su servicio se inició con éxito.
Y listo!!
Dejo link: https://go-zero.dev/en/docs/tasks/cli/api-demo
En el mundo del desarrollo de software, la velocidad, la eficiencia y la simplicidad son pilares fundamentales. El framework Go-Zero emerge como una solución poderosa para aquellos que buscan crear aplicaciones escalables y de alto rendimiento utilizando el lenguaje de programación Go (Golang).
Pero ¿Qué es Go-Zero? Go-Zero es un framework moderno y de código abierto diseñado para acelerar el proceso de desarrollo de aplicaciones en Go. Ofrece una arquitectura robusta y flexible, proporcionando herramientas y patrones que permiten construir aplicaciones web, API y microservicios de manera eficiente.
Características Principales:
Go-Zero representa una opción valiosa para aquellos que buscan desarrollar aplicaciones en Go de manera rápida, eficiente y escalable. Su enfoque en el rendimiento y la productividad lo convierten en una herramienta atractiva para proyectos de diversos tamaños y complejidades.
Dejo link: https://github.com/zeromicro/go-zero
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go: downloading google.golang.org/protobuf v1.28.1
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go: downloading google.golang.org/grpc v1.2.1
Luego escribir el .proto :
syntax = "proto3";
option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
Este archivo, es un descriptor del servicio y nos permite generar código con el comando protoc, por ejemplo:
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./greetings/greetings.proto
Y luego podemos escribir el cliente y el servidor. Por ejemplo:
Server:
package main
import (
"context"
"flag"
"fmt"
"log"
"net"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
var (
port = flag.Int("port", 50051, "The server port")
)
// server is used to implement helloworld.GreeterServer.
type server struct {
pb.UnimplementedGreeterServer
}
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
func main() {
flag.Parse()
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
log.Printf("server listening at %v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
y el cliente:
package main
import (
"context"
"flag"
"log"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
const (
defaultName = "world"
)
var (
addr = flag.String("addr", "localhost:50051", "the address to connect to")
name = flag.String("name", defaultName, "Name to greet")
)
func main() {
flag.Parse()
// Set up a connection to the server.
conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
// Contact the server and print out its response.
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: *name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
}
Y listo!
Para probarlo, ejecutamos el server :
$ go run greeter_server/main.go
Y luego el cliente :
$ go run greeter_client/main.go
Dejo link: https://grpc.io/docs/languages/go/quickstart/
Pero, ¿Qué es bbolt? bbolt, también conocida como "BoltDB", es una base de datos embebida escrita en Go que se centra en la simplicidad, el rendimiento y la eficiencia en la utilización de recursos. A diferencia de las bases de datos tradicionales que se ejecutan como procesos separados, bbolt se integra directamente en la aplicación Go, lo que la convierte en una excelente opción para aplicaciones que necesitan un almacenamiento local y ligero sin la necesidad de un servidor de base de datos independiente.
Características Clave de bbolt son:
Para comenzar a usar bbolt en tu proyecto Go, primero debemos agregar la dependencia:
go get go.etcd.io/bbolt@latest
Vamos a importar bbolt :
import bolt "go.etcd.io/bbolt"
Luego, podemos abrir una base de datos o crear una nueva:
db, err := bolt.Open(path, 0600, nil)
if err != nil {
return err
}
defer db.Close()
A partir de ahí, puedes crear buckets (similares a tablas en una base de datos relacional), almacenar y recuperar datos, y gestionar transacciones de manera similar a otras bases de datos. El enfoque es simple y eficiente, lo que facilita el trabajo con la base de datos.
// Abre una transacción de escritura.
tx, err := db.Begin(true)
if err != nil {
log.Fatal(err)
}
defer tx.Rollback()
// Obtiene un bucket (o lo crea si no existe).
bucket, err := tx.CreateBucketIfNotExists([]byte("mi-bucket"))
if err != nil {
log.Fatal(err)
}
// Almacena un valor en el bucket.
err = bucket.Put([]byte("clave"), []byte("valor"))
if err != nil {
log.Fatal(err)
}
// Realiza commit de la transacción.
if err := tx.Commit(); err != nil {
log.Fatal(err)
}
// Recupera un valor del bucket.
valor := bucket.Get([]byte("clave"))
fmt.Printf("Valor recuperado: %s\n", valor)
bbolt es una opción atractiva para aplicaciones Go que necesitan una base de datos embebida rápida, eficiente y fácil de usar. Su diseño simple, soporte para transacciones ACID y eficiencia en el uso de recursos la convierten en una elección sólida para muchas aplicaciones. Podemos considerar a bbolt para tus proyectos Go que requieran almacenamiento de datos local y duradero.
Dejo link:
Se considera que los comentarios que aparecen antes de las declaraciones de nivel superior, sin nuevas líneas intermedias, documentan la declaración misma. Estos "comentarios de documentos" son la documentación principal de un paquete o comando de Go determinado.
Los “comentarios de documentos” son comentarios que aparecen inmediatamente antes de las declaraciones de paquete, const, func, type y var de nivel superior sin nuevas líneas intermedias. Cada nombre exportado (en mayúscula) debe tener un comentario de documento.
Los paquetes go/doc y go/doc/comment brindan la capacidad de extraer documentación del código fuente de Go, y una variedad de herramientas utilizan esta funcionalidad. El comando go doc busca e imprime el comentario del documento para un paquete o símbolo determinado. (Un símbolo es una constante, función, tipo o var de nivel superior). El servidor web pkg.go.dev muestra la documentación para los paquetes públicos de Go (cuando sus licencias permiten ese uso). El programa que sirve a ese sitio es golang.org/x/pkgsite/cmd/pkgsite, que también se puede ejecutar localmente para ver la documentación de módulos privados o sin conexión a Internet. El servidor de idiomas gopls proporciona documentación al editar archivos fuente de Go en IDE.
Por ejemplo, Cada paquete debe tener un comentario que lo presente. Proporciona información relevante para el paquete en su conjunto y, en general, establece expectativas para el paquete. Especialmente en paquetes grandes, puede resultar útil que el comentario del paquete brinde una breve descripción general de las partes más importantes de la API, vinculando a otros comentarios de documentos según sea necesario.
Si el paquete es simple, el comentario del paquete puede ser breve. Por ejemplo:
// Package path implements utility routines for manipulating slash-separated
// paths.
//
// The path package should only be used for paths separated by forward
// slashes, such as the paths in URLs. This package does not deal with
// Windows paths with drive letters or backslashes; to manipulate
// operating system paths, use the [path/filepath] package.
package path
Los corchetes en [ruta/ruta de archivo] crean un enlace de documentación.
Como se puede ver en este ejemplo, los comentarios de Go doc utilizan oraciones completas. Para un comentario de paquete, eso significa que la primera oración comienza con "Package".
Dejo link: https://go.dev/doc/comment
Veamos un ejemplo, vamos a hacer un archivo greetings con el siguiente contenido :
package greetings
import "fmt"
// Hello returns a greeting for the named person.
func Hello(name string) (message string) {
// Return a greeting that embeds the name in a message.
if name == "" {
message = "Hi!"
} else {
message = fmt.Sprintf("Hi, %v. Welcome!", name)
}
return message
}
En el directorio greetings, crearemos un archivo llamado greetings_test.go, que son las pruebas. Terminar el nombre de un archivo con _test.go le indica al comando go test que este archivo contiene test.
En Greetings_test.go, vamos a pegar el siguiente código y guardar el archivo.
package greetings
import (
"regexp"
"testing"
)
// TestHelloName calls greetings.Hello with a name, checking
// for a valid return value.
func TestHelloName(t *testing.T) {
name := "Gladys"
want := regexp.MustCompile(`\b` + name + `\b`)
msg := Hello("Gladys")
if !want.MatchString(msg) {
t.Fatalf(`Hello("Gladys") = %q, %v`, msg, want)
}
}
// TestHelloEmpty calls greetings.Hello with an empty string.
func TestHelloEmpty(t *testing.T) {
msg := Hello("")
if msg != "Hi!" {
t.Fatalf(`Hello("") = %q, want "Hi!"`, msg)
}
}
En este código, se puede ver que utilizamos el paquete "test" para hacer uso de función "Fatalf" que indica que la función no pasa el test.
Si ejecutamos go test en el directorio obtendremos :
$ go test
PASS
ok example.com/greetings 0.364s
$ go test -v
=== RUN TestHelloName
--- PASS: TestHelloName (0.00s)
=== RUN TestHelloEmpty
--- PASS: TestHelloEmpty (0.00s)
PASS
ok example.com/greetings 0.372s
Y eso es todo!
Dejo link : https://go.dev/doc/tutorial/add-a-test
Primero vamos a hacer una interfaz que nos permita obtener un saludo :
type Saludor interface {
GetSaludo() string
}
Luego vamos a implementarla en español e ingles :
type SaludorEs struct {
}
func (saludoEs SaludorEs) GetSaludo() string {
return "Hola !!"
}
Cualquier aplicación no trivial está formada por dos o más objetos que colaboran entre sí para realizar alguna lógica. Tradicionalmente cada objeto se hacía cargo de obtener sus propias referencias a los objetos a los cuales colaboraba (sus dependencias). Esto lleva a código acoplado y difícil de probar. Y para solucionar esto esta la inyección de dependencias. El contexto ingresa las dependencias de un objeto. Para mayor información pueden ir a : https://emanuelpeg.blogspot.com/2009/07/inyeccion-de-dependencias.html
Y que es Fx? Según la documentación oficial publicada por Uber, Fx es un framework para Go que:
Fx usa el patrón de inyección de constructor, tratemos de entender exactamente cómo hace que la inyección de dependencia sea fácil en Go.
Para usar Fx debemos:
El primer paso es instalar la biblioteca a través de go get go.uber.org/fx.
Y luego podemos hacer esto:
package main
import (
"context"
"go.uber.org/fx"
"go.uber.org/fx/fxevent"
"log"
"net"
"net/http"
"os"
"time"
)
func NewLogger() *log.Logger {
logger := log.New(os.Stdout, "" /* prefix */, 0 /* flags */)
logger.Print("Create NewLogger.")
return logger
}
func NewHandler(logger *log.Logger) (http.Handler, error) {
logger.Print("Create NewHandler.")
return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
logger.Print("Got a request.")
}), nil
}
func NewMux(lc fx.Lifecycle, logger *log.Logger) *http.ServeMux {
logger.Print("Create NewMux.")
mux := http.NewServeMux()
server := &http.Server{
Addr: "127.0.0.1:8080",
Handler: mux,
}
lc.Append(fx.Hook{
OnStart: func(context.Context) error {
logger.Print("Starting HTTP server.")
ln, err := net.Listen("tcp", server.Addr)
if err != nil {
return err
}
go server.Serve(ln)
return nil
},
OnStop: func(ctx context.Context) error {
logger.Print("Stopping HTTP server.")
return server.Shutdown(ctx)
},
})
return mux
}
func Register(mux *http.ServeMux, h http.Handler) {
mux.Handle("/", h)
}
func main() {
app := fx.New(
fx.Provide(
NewLogger,
NewHandler,
NewMux,
),
fx.Invoke(Register),
fx.WithLogger(
func() fxevent.Logger {
return fxevent.NopLogger
},
),
)
startCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
if err := app.Start(startCtx); err != nil {
log.Fatal(err)
}
if _, err := http.Get("http://localhost:8080/"); err != nil {
log.Fatal(err)
}
stopCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
if err := app.Stop(stopCtx); err != nil {
log.Fatal(err)
}
}
Manning nos regala Go in Action hasta el 30 de mayo, miren:
Dejo link:
$ mkdir myapp && cd myapp
$ go mod init myapp
$ go get github.com/labstack/echo/v4
$ go get github.com/labstack/echo/v4/middleware
Con esto, hemos importado las librerías necesarias si miramos el archivo go.mod :
module myapp
go 1.19
require (
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/labstack/echo/v4 v4.11.1 // indirect
github.com/labstack/gommon v0.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
golang.org/x/crypto v0.11.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/time v0.3.0 // indirect
)
Ahora vamos a hacer un pequeño programa que tenga un hola mundo :
import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"net/http"
)
func main() {
// Echo instance
e := echo.New()
// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Routes
e.GET("/", hello)
// Start server
e.Logger.Fatal(e.Start(":1323"))
}
// Handler
func hello(c echo.Context) error {
return c.String(http.StatusOK, "Hola Mundo!")
}
Y Listo!!
Dejo links:
Muy lindo todo pero la idea es hacer un hola mundo, veamos.
Para instalar se requiere Echo Go v1.13 o superior. Go v1.12 tiene soporte limitado y algunos middlewares no estarán disponibles. Asegúrese de que la carpeta de su proyecto esté fuera de su $GOPATH.
$ mkdir myapp && cd myapp
$ go mod init myapp
$ go get github.com/labstack/echo/v4
Dejo link: https://echo.labstack.com/
|
|