En estos días he estado desarrollando un proxy inverso simple en NodeJS para un servidor en Linux que tengo con algunos servicios, por lo que para algunas pruebas necesito precisamente ver si redirecciona peticiones a distintos puertos y rutas diferentes.
Hay herramientas como Wiremock que son opensource o que funcionan muy bien, pero yo necesitaba algo más sencillo y que además pudiera en caso de ser necesario integrarlo fácil en pruebas unitarias, por ello utilize Golang para crear esta herramienta ya que puedo simplemente agregar el binario a mi proyecto y listo.
Servicio Http Rest mínimo
En Golang se puede crear un servicio rest bastante rápido y de manera muy simple:
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
type Response struct {
Message string `json:"message"`
}
func handler(w http.ResponseWriter, r *http.Request) {
// Crear una respuesta
response := Response{
Message: "Hola, este es un servicio REST en Go",
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(response); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func main() {
http.HandleFunc("/api", handler)
fmt.Println("Servidor corriendo en http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
El código anterior permite peticiones en /api de todo tipo no hay más lógica en ello.
Y basándome en esto mismo lo que hice fue crear un servicio que escuchara en varios puertos y que atendieran a distintas rutas y métodos, toda esta configuración debe ser leída desde un archivo JSON ahi se va a describir las rutas, métodos, la respuesta de los códigos de estado y cuerpo.
Ejemplo de configuración JSON
[
{
"name": "Fake server",
"notFound": {
"status": 404,
"body": {
"error": "not_found"
}
},
"port": 6000,
"paths": [
{
"path": "/login?parameter=1",
"methods": [
{
"method": "post",
"response": {
"status": 200,
"body": {
"message": "OK",
"One": 1
},
"headers": {
"Content-Type": "application/json"
}
}
},
{
"method": "get",
"description": "login fake simulate just to get the god response error",
"response": {
"status": 401,
"body": {
"message": "invalid password"
}
},
"headers": {
"Content-Type": "application/json"
}
}
]
}
]
},
{
"name": "Fake server 2",
"notFound": {
"status": 404,
"body": {
"error": "not_found"
}
},
"port": 8000,
"paths": [
{
"path": "/auth/login",
"methods": [
{
"method": "post",
"response": {
"status": 200,
"body": {
"message": "Login"
},
"headers": {
"Content-Type": "application/json"
}
}
},
{
"method": "get",
"description": "login fake simulate just to get the god response error",
"response": {
"status": 401,
"body": {
"message": "invalid"
}
},
"headers": {
"Content-Type": "application/json"
}
}
]
}
]
}
]
El ejemplo anterior es un array de objetos con las siguientes propiedades:
Settings
Propiedad | Tipo |
---|---|
Name | string |
NotFound | NotFoundModel |
Port | int |
Path | []PathModel |
NotFoundModel
Propiedad | Tipo |
---|---|
Status | int |
Body | map[string]interface{} |
PathModel
Propiedad | Tipo |
---|---|
Path | string |
Methods | []MethodModel |
MethodModel
Propiedad | Tipo |
---|---|
Method | string |
Response | ResponseModel |
ResponseModel
Propiedad | Tipo |
---|---|
Status | int |
Body | map[string]interface{} |
Headers | map[string]string |
Las más importantes son port
que va a definir el puerto donde escuchara cada servicio y path
que es la ruta que va a definir la petición para que funcione, en caso de que la ruta no este definida lo que responderá el servicio sera lo que este descrito en NotFoundModel
o en caso contrario regresara un http 500.
Dentro de cada path
hay un array de métodos http, los cuales serán los distintos métodos MethodModel
a los cuales puede responder el servidor, una ruta, por ejemplo /api puede regresar datos usando GET o POST según sea el caso.
Por último, dentro de cada MethodModel
existe un ResponseModel
que tiene el Body
y Headers
que va a retornar cada path.
Eso es todo bastante sencillo y practico para crear respuestas falsas o mocks.
Ejecutar Código
Para ejecutar el código simplemente hay que hacer go run .
y listo, el archivo JSON debe tener el nombre servers.json
o se le tiene que pasar un nombre por parámetros en la consola go run . file.json
.
Tambien dentro del proyecto y código existe un archivo makefile que tiene algunos targets para compilar a distintas plataformas y sistemas, estos targets generan un ejecutable de nombre fakeapi.exe
.
Por ejemplo, para compilar para Apple silicon el comando es: make build.darwinM
.
Para ejecutarlo simplemente hay que hacer en la consola: ./fakeapi.exe file.json
El código lo pueden encontrar en github, tengo uno similar en NodeJS pero al no ser un binario ejecutable no servía para estos propósitos. Ademas de ser mas enrreado considero que lo programe peor 😀