Translate

Mostrando las entradas con la etiqueta Echo. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Echo. Mostrar todas las entradas

jueves, 30 de noviembre de 2023

Testear endpoints en go con echo

Supongamos que tenemos unos endpoints hechos con echo:

package handler


import (

    "net/http"

    "github.com/labstack/echo/v4"

)


type (

    User struct {

        Name  string `json:"name" form:"name"`

        Email string `json:"email" form:"email"`

    }

    handler struct {

        db map[string]*User

    }

)


func (h *handler) createUser(c echo.Context) error {

    u := new(User)

    if err := c.Bind(u); err != nil {

        return err

    }

    return c.JSON(http.StatusCreated, u)

}


func (h *handler) getUser(c echo.Context) error {

    email := c.Param("email")

    user := h.db[email]

    if user == nil {

        return echo.NewHTTPError(http.StatusNotFound, "user not found")

    }

    return c.JSON(http.StatusOK, user)

}


Lo que queremos hacer es un test de unidad que testee este comportamiento, y podemos hacerlo así: 


package handler


import (

    "net/http"

    "net/http/httptest"

    "strings"

    "testing"


    "github.com/labstack/echo/v4"

    "github.com/stretchr/testify/assert"

)


var (

    mockDB = map[string]*User{

        "jon@labstack.com": &User{"Jon Snow", "jon@labstack.com"},

    }

    userJSON = `{"name":"Jon Snow","email":"jon@labstack.com"}`

)


func TestCreateUser(t *testing.T) {

    // Setup

    e := echo.New()

    req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(userJSON))

    req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)

    rec := httptest.NewRecorder()

    c := e.NewContext(req, rec)

    h := &handler{mockDB}


    // Assertions

    if assert.NoError(t, h.createUser(c)) {

        assert.Equal(t, http.StatusCreated, rec.Code)

        assert.Equal(t, userJSON, rec.Body.String())

    }

}


func TestGetUser(t *testing.T) {

    // Setup

    e := echo.New()

    req := httptest.NewRequest(http.MethodGet, "/", nil)

    rec := httptest.NewRecorder()

    c := e.NewContext(req, rec)

    c.SetPath("/users/:email")

    c.SetParamNames("email")

    c.SetParamValues("jon@labstack.com")

    h := &handler{mockDB}


    // Assertions

    if assert.NoError(t, h.getUser(c)) {

        assert.Equal(t, http.StatusOK, rec.Code)

        assert.Equal(t, userJSON, rec.Body.String())

    }

}


Y listo!! 


Dejo link: https://echo.labstack.com/docs/testing

miércoles, 4 de octubre de 2023

Agregando Swagger a nuestro proyecto Echo


Luego de crear nuestro proyecto con echo, vamos a agregar swagger

Empezamos agregando la librería de swag 


go get -d github.com/swaggo/swag/cmd/swag

go install github.com/swaggo/swag/cmd/swag@latest


Luego ejecutamos Swag en la carpeta raíz del proyecto Go que contiene el archivo main.go, Swag analizará los comentarios y generará los archivos necesarios (carpeta docs y docs/doc.go).


swag init


y luego agregamos echo para swagger


go get -u github.com/swaggo/echo-swagger


Y ahora tenemos swagger en nustro proyecto echo : 


package main


import (

"github.com/labstack/echo/v4"

"github.com/swaggo/echo-swagger"


_ "github.com/swaggo/echo-swagger/example/docs" // docs is generated by Swag CLI, you have to import it.

)


// @title Swagger Example API

// @version 1.0

// @description This is a sample server Petstore server.

// @termsOfService http://swagger.io/terms/


// @contact.name API Support

// @contact.url http://www.swagger.io/support

// @contact.email support@swagger.io


// @license.name Apache 2.0

// @license.url http://www.apache.org/licenses/LICENSE-2.0.html


// @host petstore.swagger.io

// @BasePath /v2

func main() {

e := echo.New()


e.GET("/swagger/*", echoSwagger.WrapHandler)


e.Logger.Fatal(e.Start(":1323"))

}


En mi caso solo tengo que agregar : 

el import : 

import (_ "myapp/docs")

y el router : 

e.GET("/swagger/*", echoSwagger.WrapHandler)

y tengo estos 2 servicios con su documentación  : 

// HealthCheck godoc
// @Summary Show the status of server.
// @Description get the status of server.
// @Tags root
// @Accept */*
// @Produce json
// @Success 200 {object} map[string]interface{}
// @Router /health/check [get]
func HealthCheck(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]interface{}{
"data": "Server is up and running",
})
}

// Info godoc
// @Summary Show the info of server.
// @Description get the info of server.
// @Tags root
// @Accept */*
// @Produce json
// @Success 200 {object} computer.SysInfo
// @Router /health/info [get]
func Info(c echo.Context) error {
return c.JSON(http.StatusOK, computer.Info())
}

Y se genero el siguiente swagger.json :

{
    "swagger": "2.0",
    "info": {
        "contact": {}
    },
    "paths": {
        "/health/check": {
            "get": {
                "description": "get the status of server.",
                "consumes": [
                    "*/*"
                ],
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "root"
                ],
                "summary": "Show the status of server.",
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    }
                }
            }
        },
        "/health/info": {
            "get": {
                "description": "get the info of server.",
                "consumes": [
                    "*/*"
                ],
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "root"
                ],
                "summary": "Show the info of server.",
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/computer.SysInfo"
                        }
                    }
                }
            }
        }
    },
    "definitions": {
        "computer.SysInfo": {
            "type": "object",
            "properties": {
                "disk": {
                    "type": "integer"
                },
                "hostname": {
                    "type": "string"
                },
                "platform": {
                    "type": "string"
                },
                "ram": {
                    "type": "integer"
                },
                "ram available": {
                    "type": "integer"
                },
                "ram free": {
                    "type": "integer"
                },
                "uptime": {
                    "type": "integer"
                }
            }
        }
    }
}

Dejo link : https://github.com/swaggo/echo-swagger

lunes, 2 de octubre de 2023

Crear un proyecto en Go y Echo


Vamos a crear un proyecto con echo y go. Echo es un framework web minimalista y de alto rendimiento para Go. Está diseñado para ser simple y eficiente, lo que lo hace adecuado para el desarrollo rápido de API REST. Echo es especialmente apreciado por su rendimiento y facilidad de uso.


$ 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: 

https://echo.labstack.com/docs

https://github.com/labstack/echo

martes, 7 de febrero de 2023

Hacer un endpoit para saber el estado del host con echo en Golang parte 2


Todo muy lindo en el post anterior peeeeroo nos falto saber el estado del server, para ello vamos a utilizar la librería : "github.com/shirou/gopsutil". La idea es saber si tiene memoria libre, si el micro esta a full, etc. (estado de los recursos) 

Vamos a necesitar una estructura que contenga toda la información a mostrar : 


type StatusInfo struct {

RuntimeOS            string `json:"runtimeOS"`

TotalMemory          string `json:"total_memory"`

FreeMemory           string `json:"free_memory"`

PercentageUsedMemory string `json:"percentage_used_memory"`


TotalDiskSpace           string `json:"total_disk_space"`

UsedDiskSpace            string `json:"used_disk_space"`

FreeDiskSpace            string `json:"free_disk_space"`

PercentageDiskSpaceUsage string `json:"percentage_disk_space_usage"`


CpuIndexNumber string `json:"cpu_index_number"`

VendorId       string `json:"vendorId"`

Family         string `json:"family"`

NumberOfCores  string `json:"number_of_cores"`

ModelName      string `json:"model_name"`

Speed          string `json:"speed"`


Hostname                 string `json:"hostname"`

Uptime                   string `json:"uptime"`

NumberOfProcessesRunning string `json:"number_of_processes_running"`


Os       string `json:"os"`

Platform string `json:"platform"`


HostId string `json:"host_id"`

}

Y con la librería gopsutil podemos llenar el struct: 


func status(c echo.Context) error {

runtimeOS := runtime.GOOS

// memory

vmStat, err := mem.VirtualMemory()

dealwithErr(err)


diskStat, err := disk.Usage("/")

dealwithErr(err)


// cpu - get CPU number of cores and speed

cpuStat, err := cpu.Info()

dealwithErr(err)


// host or machine kernel, uptime, platform Info

hostStat, err := host.Info()

dealwithErr(err)


var sInfo StatusInfo


sInfo.RuntimeOS = runtimeOS

sInfo.TotalMemory = strconv.FormatUint(vmStat.Total, 10) + " bytes "

sInfo.FreeMemory = strconv.FormatUint(vmStat.Free, 10) + " bytes"

sInfo.PercentageUsedMemory = strconv.FormatFloat(vmStat.UsedPercent, 'f', 2, 64) + "%"


sInfo.TotalDiskSpace = strconv.FormatInt(int64(diskStat.Total), 10) + " bytes "

sInfo.UsedDiskSpace = strconv.FormatInt(int64(diskStat.Used), 10) + " bytes"

sInfo.FreeDiskSpace = strconv.FormatInt(int64(diskStat.Free), 10) + " bytes"

sInfo.PercentageDiskSpaceUsage = strconv.FormatFloat(diskStat.UsedPercent, 'f', 2, 64) + "%"


sInfo.CpuIndexNumber = strconv.FormatInt(int64(cpuStat[0].CPU), 10)

sInfo.VendorId = cpuStat[0].VendorID

sInfo.Family = cpuStat[0].Family

sInfo.NumberOfCores = strconv.FormatInt(int64(cpuStat[0].Cores), 10)

sInfo.ModelName = cpuStat[0].ModelName

sInfo.Speed = strconv.FormatFloat(cpuStat[0].Mhz, 'f', 2, 64)


sInfo.Hostname = hostStat.Hostname

sInfo.Uptime = strconv.FormatUint(hostStat.Uptime, 10)

sInfo.NumberOfProcessesRunning = strconv.FormatUint(hostStat.Procs, 10)


sInfo.Os = hostStat.OS

sInfo.Platform = hostStat.Platform


sInfo.HostId = hostStat.HostID


return c.JSON(http.StatusOK, sInfo)

}


Uso una función para mostrar el error : 


func dealwithErr(err error) {

if err != nil {

fmt.Println(err)

}

}



Y por último agregamos un endpoint en nuestro main: 


func main() {

e := echo.New()

        ....

e.GET("/status", func(c echo.Context) error {

return status(c)

})

e.Logger.Fatal(e.Start(":1323"))

}

Si vamos a localhost:1323/status podemos obtenere una salida como esta : 

{"runtimeOS":"linux","total_memory":"20769558528 bytes ","free_memory":"2220945408 bytes","percentage_used_memory":"75.97%","total_disk_space":"745407905792 bytes ","used_disk_space":"7737049088 bytes","free_disk_space":"737670856704 bytes","percentage_disk_space_usage":"1.04%","cpu_index_number":"0","vendorId":"GenuineIntel","family":"6","number_of_cores":"1","model_name":"11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz","speed":"4700.00","hostname":"crespo","uptime":"262837","number_of_processes_running":"462","os":"linux","platform":"ubuntu","host_id":"c47f72aa-2ce5-414b-97ad-d51759c9a406"}



sábado, 4 de febrero de 2023

Hacer un endpoit para saber el estado del host con echo en Golang


Me quedo relargo el titulo... pero esa es la idea, hacer uno o más endpoints que me digan si el host responde para saber ante un problema que hacer. 

Para esto usamos echo y hacemos algo tan fácil como esto: 

func main() {

e := echo.New()

e.GET("/health", func(c echo.Context) error {

return c.String(http.StatusOK, "Ok")

})

e.Logger.Fatal(e.Start(":1323"))

}


Ahora si hacemos un pedido por el método GET a la url /health y nos contesta, esta todo bien y si no bueno vamos a tener que investigar. 

Supongamos que queremos saber información del host, por X motivo en este caso podemos utilizar una librería llamada "github.com/zcalusic/sysinfo" 

Primero agregamos el endpoint : 


func main() {

e := echo.New()

e.GET("/health", func(c echo.Context) error {

return c.String(http.StatusOK, "Ok")

})


e.GET("/info", func(c echo.Context) error {

return info(c)

})

e.Logger.Fatal(e.Start(":1323"))

}


Ahora programamos la función info : 


func info(c echo.Context) error {

var si sysinfo.SysInfo

si.GetSysInfo()


return c.JSON(http.StatusOK, si)

}


Y listo, igual esto no es taaaannn útil, sería mejor saber tambien el estado del server, pero eso es para otro post. 



martes, 3 de enero de 2023

Echo, Framework web de alto rendimiento, extensible y minimalista para Golang


Echo, es un framework web para golang que nos brinda : 

  • Enrutador HTTP altamente optimizado con asignación de memoria dinámica cero que prioriza rutas de manera inteligente.
  • Creación de un API RESTful robusta y escalable, fácilmente organizada en grupos.
  • Se puede instalar automáticamente certificados TLS de Let's Encrypt.
  • La compatibilidad con HTTP/2 mejora la velocidad y proporciona una mejor experiencia de usuario.
  • Muchos middleware integrados para usar o definir el suyo propio. El middleware se puede configurar a nivel de raíz, grupo o ruta.
  • Enlace de datos para la carga útil de la solicitud HTTP, incluidos JSON, XML o datos de formulario.
  • API para enviar una variedad de respuestas HTTP, incluidos JSON, XML, HTML, archivo, adjunto, en línea, flujo o blob.
  • Representación de plantillas utilizando cualquier motor de plantillas
  • Manejo de errores HTTP central personalizado. API fácilmente extensible.


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


Si está trabajando con Go v1.14 o anterior, use:


$ GO111MODULE=on go get github.com/labstack/echo/v4

Veamos exponer un servicio enel golang : 

package main

import (
"net/http"
"github.com/labstack/echo/v4"
)

func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.Logger.Fatal(e.Start(":1323"))
}

Y lo corremos de esta manera : 

$ go run server.go

Dejo link: https://echo.labstack.com/

martes, 29 de septiembre de 2020

Con que framework debo desarrollar un sistema web??


Esta pregunta me la hizo un alumno y quiero compartir mi respuesta. 

Existen muchas opciones pero es bueno ir por donde va la industria, es decir utilizar lo más usado. Claramente hoy en día se utiliza un framework backend + un framewor front.Comunicados por Apis Rest.  

Por front podemos elegir : Angular, React o Vue , el mercado esta ahí. 

Por back tenes muchas opciones: java - spring boot, solución super probada y te va andar muy bien.

dot net - dot net core con MVC, un poco más nuevo pero anda muy bien y se usa mucho. 

Python: Django, viejito pero bueno,

Javascript con node y express. 

Y si te interesa arriesgarte y optar por algo nuevo tenes Go, con Echo o otros frameworks.