Introducción: por qué Go es la elección ideal para una API REST
Go (o Golang) es un lenguaje de programación compilado de Google que combina el rendimiento de C++ con la simplicidad de Python. Si desea crear una API REST rápida, confiable y fácil de mantener, Go es una de las mejores opciones. En este artículo, escribiremos en 30 minutos una API REST completa en Go que puede crear, leer, actualizar y eliminar registros (CRUD). Sin frameworks complejos, solo la biblioteca estándar net/http y un poco de código.
Al final del artículo, tendrá un servidor HTTP listo que responde a las solicitudes en formato JSON y funciona sin dependencias externas. ¡Comencemos!
Paso 1: Configuración del proyecto y estructura
Para empezar, asegúrese de tener Go instalado (versión 1.16+). Cree un nuevo directorio para el proyecto e inicialice el módulo:
mkdir go-rest-apicd go-rest-apigo mod init go-rest-apiLa estructura del proyecto será simple: un solo archivo main.go. Colocaremos todo el código en él para no complicar el ejemplo. En proyectos reales, por supuesto, dividirá el código en paquetes, pero para aprender es ideal.
Paso 2: Definir la estructura de datos y el almacenamiento global
Nuestra API gestionará una lista de libros. Crearemos una estructura Book y un slice simple para almacenar datos en memoria (en lugar de una base de datos).
package main
import ( "encoding/json" "log" "net/http" "strconv" "strings")
type Book struct { ID int `json:"id"` Title string `json:"title"` Author string `json:"author"` Year int `json:"year"`}
var books []Bookvar nextID int = 1Aquí, books es nuestra «capa de datos» temporal, y nextID es un contador para asignar automáticamente ID a los nuevos libros.
Paso 3: Implementar los manejadores de solicitudes HTTP (CRUD)
Ahora viene la parte interesante: escribiremos funciones manejadoras para cada método HTTP. Usaremos el enrutador estándar http.NewServeMux.
3.1. Obtener todos los libros (GET /books)
func getBooks(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(books)}3.2. Crear un nuevo libro (POST /books)
func createBook(w http.ResponseWriter, r *http.Request) { var newBook Book if err := json.NewDecoder(r.Body).Decode(&newBook); err != nil { http.Error(w, "Invalid JSON", http.StatusBadRequest) return } newBook.ID = nextID nextID++ books = append(books, newBook) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(newBook)}3.3. Obtener un libro por ID (GET /books/{id})
En ServeMux estándar no hay soporte para rutas dinámicas, por lo que extraeremos el ID de la URL manualmente.
func getBook(w http.ResponseWriter, r *http.Request) { idStr := strings.TrimPrefix(r.URL.Path, "/books/") id, err := strconv.Atoi(idStr) if err != nil { http.Error(w, "Invalid ID", http.StatusBadRequest) return } for _, book := range books { if book.ID == id { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(book) return } } http.Error(w, "Book not found", http.StatusNotFound)}3.4. Actualizar un libro (PUT /books/{id})
func updateBook(w http.ResponseWriter, r *http.Request) { idStr := strings.TrimPrefix(r.URL.Path, "/books/") id, err := strconv.Atoi(idStr) if err != nil { http.Error(w, "Invalid ID", http.StatusBadRequest) return } var updatedBook Book if err := json.NewDecoder(r.Body).Decode(&updatedBook); err != nil { h