Crea un sencillo servidor HTTP con Go.

Crea un sencillo servidor HTTP con Go.

Introducción

El día de hoy crearemos un muy sencillo servidor HTTP utilizando el lenguage de programación Go (también llamado Golang), aunque no me dentendré mucho a hablar acerca del lenguage, cabe mencionar que es un lenguaje de programación de alto nivel, compilado, creados y respaldado por Google.

Cabe recalcar que este no es un tutorial totalmente básico y tampoco sobre como instalar Go en sus ordenadores, así que aquí les dejará algunos recursos muy buenos para instalarlo si es que aún no lo tiene:

  1. La documentación oficial – https://go.dev/learn/
  2. Instalación de Go por DigitalOcean – https://www.digitalocean.com/community/tutorials/how-to-install-go-and-set-up-a-local-programming-environment-on-macos-es

¿Qué es un servidor HTTP?


Comenzaremos con un poco de contexto acerca de los servidores HTTP o servidor Web y para esto voy a recurrir a la definición que da Mozilla, la cual me parece muy simple pero explicativa.

En cuanto a software, un servidor web tiene muchas partes encargadas del control sobre cómo tienen acceso los usuarios a los archivos, por lo menos un servidor HTTP. Un servidor HTTP es una pieza de software que comprende URLs (direcciones web) y HTTP (el protocolo que tu navegador usa para ver las páginas web).

https://developer.mozilla.org/es/docs/Learn/Common_questions/What_is_a_web_server

Como pudimos leer de la referencia arriba, un servidor web es un software que nos permite visualizar contenido en el navegador y/o consultar información.

Servidor en Go.


Crear un servidor HTTP en Go es muy sencillo, gracias a que la librería estandar de Go es una de las más completas y ya viene con una librería HTTP que nos ayudará mucho en este caso.

Para crearlo es tan fácil como hacer lo siguiente, primero creamos una carpeta en donde sea su preferencia y como nombre go_http_server, una vez dentro del directorio de nuestro proyecto, procedemos a crear un archivo con el nombre main.go y es ahí donde estaremos trabajando, nuestro punto raíz:

package main

import (
	"fmt"
	"net/http"

func handler1(w http.ResponseWriter, _ *http.Request) {
	fmt.Fprintf(w, "Hello from Golang!!!")
}

func main() {
	http.HandleFunc("/", handler1)
	http.ListenAndServe(":8000", nil)
}

Ahora procedemos a correr nuestro primer servidor HTTP, con el siguiente comando, cabe recalcar que debemos estar al mismo nivel donde está el archivo main.go:

$ go run ./main.go

Y como resultado al dirigirnos a nuestro navegador con la dirección http://localhost:8000, se deberá mostrar el siguiente mensaje

Si te funcionó, ¡Felicidades!, acabas de crear tu primer servidor HTTP totalmente funcional en un nuevo lenguage de programación, ¿Fue díficil?, apuesto a que no, vamos por más.

Si no te funcionó, lo más seguro es que tengas un error en la instalación de GO o un error de sintáxis, sería bueno revisar y volver a correr el proyecto.

Explicando el código

Ahora procederemos a explicar a detalle cada línea de código arriba escrita, lo primero que revisarémos será:

Packages

package main

Cada programa en Go está hecho de paquetes «packages» y siempre inicia con el paquete con nombre «main».  Un paquete «package» puede tener múltiples archivos .go que conforman dicho package:

└── PROJECT_NAME
    └── src
        └── cmd
            └── main.go

Al definir en el inicio de nuestro archivo main.go la palabra package main, le estamos diciendo que ese archivo pertenece al paquete main, y podemos llamar desde cualquier otro archivo o dependencia por el nombre del paquete, como veremos más adelante.

Imports y fmt

La manera en la que podemos hacer uso de otros métodos o una funcionalidad extra ya sea de la propia librería estandar de Go o una externa, es importandola:

import (
	"fmt"
	"net/http"
)

Esta es la manera en la que podemos importar librerías y métodos auxiliares para nuestro proyecto, en este caso estamos importando dos «packages» de la librería estandar, que son fmt y net/http.
fmt es el paquete por defecto para formatear I/O, textos, números, imprimir texto en pantalla, etc.
El ejemplo más básico que se puede dar es el siguiente:

fmt.Println("Hello World!") // Imprime: Hello World!

También tenemos el método que utilizamos Fprintf la cual es una función que formatea el texto de acuerdo a un formato específico y lo muestra.

// Así es el código de la función Fprintf
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)

// Y así la utilizamos nosotros en nuestro código
fmt.Fprint(w, "Hello from Golang!!!")

Dónde:
w io.Write: Es un estandar específico para entradas y salidas (Input & Output)
format string: Contiene una cadena de texto
a …interface{}: Variables constantes utilizadas en el código
Me gustaría tocar más fondo en este tema pero se haría súper extenso, así que más adelante seguiré sacando más artículos sobre la librería estandar de Go.

Funciones

Las funciones son generalmente bloques de código que se encuentran en nuestro programa y nos da la oportunidad de re-utilizar código y casi todo en Go son funciones, así que mucho ojo.

func handler1(w http.ResponseWriter, _ *http.Request) {
	fmt.Fprintf(w, "Hello from Golang!!!")
}

Crear nuestro servidor y hacer que «funcione» no basta, necesitamos poder hacer peticiones y obtener una respuesta «Request & Response», y eso es lo que hacemos en el código de arriba.
Definimos una nueva función con la palabra reservada func y seguido el nombre de dicha función handler1, la cual requiere 2 argumentos, w que es una instancia de http.ResponseWrite y un puntero a http.Request. Este segundo argumento lo estamos ignorando de momento ya que no estamos accediendo a la información de la petición (se ignora con _).

Pero, espera un poco, ¿De dónde sale que necesito un ResponseWriter y Request?. Que buena pregunta, y la respuesta se contesta a continuación.

Punto de entrada

Todo programa escrito en Go, requiere de una función especial llamada «main», la cual será el punto de entrada para correr nuestro servicio, CLI, servidor, programa, etc. Este es el nombre que el lenguage busca para poder correr el programa entero.

Ya teniendo en cuenta eso, ahora si, vamos con lo interesante:

func main() {
	http.HandleFunc("/", handler1)
	http.ListenAndServe(":8000", nil)
}

Como podemos observer en el código de arriba, dentro de nuestra función main, estamos definiendo dos cosas http.HandleFunc y http.ListerAndServe.
El primero HandleFunc lo que hace es registrar un handler, o lo que vendría siendo como un endpoint para nuestro servidor.
El segundo ListenAndServe escucha en la dirección de la red TCP y luego llama a Serve con el controlador para manejar solicitudes en las conexiones entrantes.

Pero vayamos un poquito más a fondo, sólo un poco:

// Este es el código de http.HandleFunc
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))

Al observar el código de arriba, podemos observar que HandleFunc recibe 2 cosas:
1. Pattern: El endpoint, por ejemplo /index
2. handler: Que no es más que una función que requiere 2 argumentos, un ResponseWriter y un Request.
¿Ya te acordaste?, en el punto previo a este, hablamos de que nuestro handler1 recibe esos mismos 2 argumentos, pero en este caso como instancia y puntero respectivamente de http.

Pero estarás diciendo si ya, mucho texto.
Entonces vamos con lo final, HandleFunc requiere un handler para poder tener hacía donde mandar la petición y por ende, obtener una respuesta para el usuario, para eso creamos nuestro handler1 el cual sólo pintará el texto «Hello from Golang!!!» y es por eso que primero le pasamos nuestra ruta "/" (raíz) y nuestro handler (handler1).

Por último, lo que hacemos es levantar nuestro servidor con ListenAndServe, pasar el puerto que queremos escuchar (8000) y voilà, ya tenemos un servidor web que nos responde al hacer una petición a nuestra ruta raíz (/).

Y así de rápido en 15 líneas creamos un servidor en Go! ❤️

Conclusión


A pesar de ser aparentemente algo muy sencillo, Go tiene unas herramientas muy potentes ya incorporadas, incluso es posible realizar un servicio web completo únicamente con el paquete de net/http, incluso una API sin requerir librerías o código externo.
Cabe mencionar que esto es tan solo una pequeña parte de todo lo que este gran lenguaje tiene por ofrecernos, poco a poco estaré escribiendo más y más cosas sobre ello y poder aprender juntos.
Si te gustó, te pido por favor que me dejes un comentario, o me sigas en mis redes sociales, y me hagas llegar tu opinión y propuestas para más temas adelante, muchas gracias ❤️.