the ugly organization - we write ugly code

desu

#30 por que? si en el security group puedo definir las reglas para que solo entre http? https://github.com/uglyorganization/aws/blob/400a9fe49228797b12fe50fc4e3f249b805e2122/backend-lxd.tf#L92

que problemas hay?

lo puse en alb en lugar de una nat ha propósito. si es una api que va a recibir trafico. para despues hacer llamadas a otros backends, db y demas privados si que necesitaria una NAT.

si alguien te quiere putear por http, haciendo ataques a paths, ddos y similares te va a putear a la instancia o al alb por igual. nada lo solucionaras con una nat privada.

1 respuesta
aren-pulid0

#31 si tienes un ataque DDoS el ALB es mucho más difícil de tumbar que una instancia EC2, te falta el WAF

2 1 respuesta
desu

#32 en AWS no usas el shield de la misma manera en ambos? el shield funciona a nivel de network.

de hecho una diferencia entre ALB y ELB es como puedes prevenir ataques en rutas en el ALB y en ELB no, si no me falla la memoria, que mire esto el anyo pasado.


tienes razon, te pregunte por si se me escapaba algo. no lo monte asi para simplificar el networking, ya he compartido que no fui capaz de montarlo todo como queria. por eso no puse el https tampoco, para simplificar y tener una primera version corriendo.

en mi caso, siempre he trabajado con las ec2 privadas siempre si. y ahora con AWS tienes el SSM que va fino y no necesitas un bastion...

aren-pulid0

ah y ojo que el ALB cambia de IP de vez en cuando

1 respuesta
desu

#34 tratare de seguirlo en otro momento, he archivado todo y estoy destruyendo el terraform.

ahora voy a hacer la solucion con api gateway + lambda.

  • AWS proporciona un proxy automatico para transformar las respuestas: https://github.com/awslabs/aws-lambda-go-api-proxy
  • esto esta bien porque puedes re-usar el mismo codigo y repositorio para desplegar como binario en un contenedor normal o tener una lambda
  • por ejemplo con tener dos puntos de entrada en el codigo y dos workflows distinto es suficiente, por tanto no existe un acoplamiento excesivamente grande en codigo

esta solución tampoco la he hecho nunca con API Gateway, a ver que tal, yo solo he usado lambdas que consumen y producen de SQS/SNS.

  • hacer el operacional como digo no es nada facil con terraform, si haces un destroy pues que me destruya todo no? pues no. y con esto nopretendo criticar a la herramienta, la herramienta resuelve un problema, y tratar de usarla para mas cosas... pues quizas no es lo mejor o requiere mas scripting de lo que crees.

  • El tema de tener cloudtrail logs con s3 me va abufar todo el free tier de s3, asique cuidado! podemos tener todo gratis? @juan4k4 no ya te contesto solo con este detalle. Con AWS diria y empezar una startup, diria que hay que presupuestar minimo unos 100 euritos al mes para arrancar. que 1200 euros de capital inicial no es nada.
squ4r3

terraform lo que no puede es cargarse las restricciones de AWS. un bucket de S3 tiene que estar vacío para poder ser borrado, lo hagas via terraform o via consola.

si tienes un bucket con muchos archivos puedes hacer un lifecycle policy que vaya marcando para delete los archivos más viejos de X tiempo y así no tienes que borrar todo, solo esperar un poco y se borra todo solo.

1 1 respuesta
desu
#36squ4r3:

terraform lo que no puede es cargarse las restricciones de AWS

pero podria gestionarlo por ti, algunas herramientas lo hacen. aunque requieran configurar sns o un mecanismo de callback. para saber cuando pueden proceder.

a mi que terraform no haya borrado el contenido del bucket me parece bien. me gusta.

lo he posteado porque no estaba seguro de que haria. y en el caso de las subnets y la IGW que no domino pues puede ser un dolor de huevos si en lugar de borrar quieres hacer un update y no dominas al 100% de aws.

a veces usar herramientas como terraform que meten defaults para cosas que no saben como van en lugar de crear las cosas a mano es contra producente. quizas el aprendizaje que saco es que una buena practica es que deberiamos hacer las cosas a mano primero para entenderlo y despues automatizar.

#36squ4r3:

si tienes un bucket con muchos archivos puedes hacer un lifecycle policy que vaya marcando para delete los archivos más viejos de X tiempo y así no tienes que borrar todo, solo esperar un poco y se borra todo solo.

bueno yo en esto, que borro un monton de buckets, hasta un par de millones de objetos suelo tirar de script con list y un for la verdad. algun delete falla pero en 15-20 minutos te borra todo.

cuando tienes muchos elementos, tengo buckets que pasan de los 5PB en prod xd, pues un lifecycle siempre si.


gracias por comentar, manyana no podre hacer update, pero vamos, el objetivo de esta semana es usar un poco los productos de AWS para despues sacar alguna conclusion sobre como evolucionar backend y la facildiad de desarrollo. siguiendo con el focus puesto en terraform y devops.

si alguien ve que me he dejado algo super critico como el NAT de antes para proteger todo mejor, pues que lo comparta y me lo apunto para preparamelo.


otra decision interesante es donde pushear los contenedores y artefactos, use github packages, pero tambien tenemos ECR. creo que ambos estan ok, y por encima de docker.

1 respuesta
JuAn4k4

#37 Con el policy te ahorras requests, es verdad que es barato pero vaya. El API gateway a mi me parece excesivamente caro, y si le sumas lambda todavía más. Es todo un saca cuartos de la leche. Nosotros miramos de hacer un servicio que teníamos con esas dos cosas y SNS, y nos salía a 2-3M€/mes, cuando estábamos pagando por lo mismo en máquinas EC2 con mal performance unos 10-20K€/mes. Casi nada.

1 respuesta
desu

#38 ya nosotros con 50k req/s también miramos un día y ni recuerdo la burrada que era.

lambdas y estas cosas solo son para negocios con poco tráfico. frontends y api básicos.

GaN2

#14 haberla la hay pero TF no está pensado para eso, se usa para hacer el despliegue de la infraestructura y mantener el estado de la misma de cara a evitar cambios manuales. Quieres cambiar el tipo de instancia? Lo cambias a nivel de código, despliegas y TF se encarga de ello. Quieres aumentar un disco a nivel de tamaño o tipo? Tres cuartos de lo mismo. Quieres migrar una VM a otra subnet? Igual.

Hay empresas que hacen los despliegues con TF y luego no mantienen el estado, vamos que básicamente solo lo usan para desplegar. Bajo mi punto de vista hay mil opciones mejores que usar TF porque me parece matar moscas a cañonazos pero allá cada uno

2 respuestas
desu

#40 bueno lo elegí como experimento y para aprender un poco de terraform básico.

a mi las herramientas de hashi me gustan ya lo sabéis xq mi colegui las creó y es muy de mi filosofía de ingeniería.

un principio que también me gusta seguir para aprender es WHAT YOU CANNOT BUILD YOU DONT UNDERSTAND. Gastar un par de euros en aws para aprender son euros bien invertidos. Aunque no siga la mejor manera o metodología. Espero inspirar a alguien han hacerse sus networks también y experimentar como yo.

Después de montar la lambda con api gateway voy a diseñar CLIs. Es un campo que como backends mucha gente infravalora y solo piensa en apis http/rcp. Tener una buena CLI me parece más importante que tener un swagger con openapi.

1
desu

Sobre APIs y CLI.

  • entender la "carga cognitiva" es lo mas importante: https://blog.sbensu.com/posts/apis-as-ladders/
  • tenemos que entender una API como un cuento para crios, no puedes hablar de que hizo Juan sin antes haber introducido quien es Juan
  • no hacer REST ni OOP
  • hacer APIs declarativas RPC sobre HTTP, o RPC, claras, filosofia unix de hacer algo muy claro, scope minimo y directo.
  • hacer breaking changes siempre que puedas y lo antes posible, no es lo mismo romper algo con 2 clientes que con 30 clientes.
  • versioning con changes declarativos: https://stripe.com/blog/api-versioning
  • y por favor siempre incluir un campo "type" en cada DTO para parsear facil.
  • los que no poneis campos "type" en los DTO sois equivalentes a hacer c o cpp sin tipado y resolver en runtime todo.

Sobre SDKs.

  • Por desgracia lo voy a decir, AWS es un gran ejemplo para empresas medio-grandes.
  • SDK requiere un equipo dedicado (5-10 personas). Lo puedes pagar? Pues di NO a las SDK.
  • Si eres una startup di NO a las SDK. Te lo pide un cliente? le das una CLI o le ofreces ayuda a integrar la API HTTP.
  • https://www.reddit.com/r/aws/comments/l69b5c/how_dose_aws_manages_all_of_their_sdks/
  • Declarativo, automatizado, control de cambios, no REST, no OOP que permite lo anterior, usan XML por algo.

Y no terminaras con esta porqueria, que ni HTTP basico:

1
K
#40GaN2:

Hay empresas que hacen los despliegues con TF y luego no mantienen el estado, vamos que básicamente solo lo usan para desplegar.

Vamos, que no usan la gracia de la herramienta en si xD

aren-pulid0

buenas lecturas has puesto hoy, gracias!

Kaledros

Los SDK de AWS no sé como serán, pero si son parecidos a los de la API del storefront son para pegarse un tiro en los huevos.

1 respuesta
desu

#45 Que este bien o no la API, no comento.

Para hacer SDKs es necesario siempre un equipo especializado, como AWS. Si no lo puedes permitir no hagas SDK. Y necesitas que ese equipo siga esas mismas propiedades que permiten tener cosas estáticas, auto-generables y escalables. Y un ejemplo de éxito parecido es el ecosistema web de clojure, que copia la manera en que AWS usa su dsl y pipelines de generar SDKs para tener servicios, middleware y demás código TODO declarativo, compilable, evaluado, verificado, optimizado, autogenerado... etc

Si tu tienes una API HTTP (rest, o grpc, rest-like intercambiable) y decides hacer una SDK vas perdido. "Pero tengo 10 usuarios que se lo implementan a mano, si lo hago yo les simplifico la vida..." Vas perdido. Si hubiese una manera de hacer lo que AWS hace para todas las API del mundo de manera genérica, fácil, adaptable ya existiría un producto que lo hiciese. En su lugar ellos tienen su equipo de 15 ingenieros manteniendolo.

Y un campo similar es la documentación, la documentación debe tratarse como un problema especifico, no un subproblema derivado del desarrollo. De nuevo, es muy fácil de entender. Todos los equipos de desarrollo del mundo tienen este problema, si hubiese una manera de resolver esto para todos ya existirá el producto mágico. No existe, por tanto requiere una solución especifica para cada equipo y producto.


Documentacion mal hecha.

Estoy mirando servicios de urlshorteners a modo de ejemplo. Es algo super simple y facil no? Me sorprende que tanta gente haga las cosas mal.

Getting started de la documentacion.

Ejemplo 1)

  • Entro a la pagina principal, ahi veo la documentacion, esto esta bien. https://shrtlnk.dev/developer
  • Primera pagina de la documentacion. https://shrtlnk.dev/developer/documentation
  • Horrible, que se supone que tengo que hacer para usar tu producto? Dame un CURL funcional que pueda probar o no me digas nada.
  • Si el CURL funcional para tu hello world necesita preparar configuracion previa, dame todo el codigo que necesite para preparar esa configuracion.

Ejemplo 2)

Ejemplo 3)

  • https://cleanuri.com/docs
  • Bien, no requiere token ademas. Me da un ejemplo de request y response. Bien.
  • Mal, hay un apartado de notas con "edge cases". Dame ejemplos de peticiones con estos casos de uso que pueda probar, dame los "test cases" que tienes en tu codigo. Mal, muy mal.
  • Necesita Mejorar

Ejemplo 4, PRODUCTO DE GITHUB)

  • https://github.blog/2011-11-10-git-io-github-url-shortener/
  • Vemos ejemplos de hello world. Bien.
  • Vemos ejemplo para edge cases / use cases especificos. Bien.
  • Faltan ejemplos y casos de uso para cubrir toda la API, pero es un blog post. Un blog post tiene mejor calidad didactiva para usar un producto que los 3 ejemplos anteriores.

Ejemplo 5)

  • https://docs.kutt.it/
  • esta tiene trampa, se ve muy bonita y parece el tipico openapi para hacer peticiones... no es cierto, no es usable, no puedes hacer peticiones ni copy/pastearlas...
  • suspendido y punto negativo por pretencioso

Ejemplo 6)

Ejemplo 7)

  • https://developers.rebrandly.com/docs/api-custom-url-shortener
  • me encanta, este es como el Ejemplo 5, parece que esta super bien documentado porque hay muchas cosas. En la practica falta casi todo lo que necesitarias para implementarla.
  • no puedes copy/pastear features, y tienen como 10 features que debes aprender a usar y entender a base de prueba y error.
  • eso si, tienes paginas y paginas de texto que no sabes si funciona, esta deprecated o es la version 2.

Ejemplo 8)

  • https://tinyurl.com/app/dev
  • una openapi! y es usable! y le puedes poner tus tokens!
  • BIEN. LA UNICA QUE MERECE SER CONSIDERADA. Luego ya veremos si funciona o no o si es lo que queremos. Pero empezando por la documentacion. Es la unica que esta bien... Y fijaros que es un puto openapi!! que se hace "solo" y la mayor dificultad es settear las URL por entorno y poco mas.

Ejemplo 9)

  • https://urlbae.com/developers
  • puse un screenshot arriba, en lugar de devolver errores con status code 400 o 500 te devuelve 0 o 1 en un campo "error".
  • ni me leo la documentacion de esta porqueria.

Ejemplo 10)

  • https://owo.vc/api
  • No funciona el link... producto deprecated o no valido. Como este ejemplo hay unos cuantos en la lista. La leccion? Nada es para siempre y menos en software. Estaras diez mil horas haciendo una API perfecta que quizas el Lunes tu CTO decide cortar. El mundo real es asi.
1 respuesta
Kaledros
#46desu:

Para hacer SDKs

Mierda, soy idiota, no sé por qué estaba pensando en usar, no en hacer. Y no, hacer tu propio SDK no debería contemplarse salvo en casos muy concretos y muy justificados y por gente que sepa muy bien lo que hace. Es decir, nunca.

1 respuesta
desu

#47 Fíjate en el post #46 donde evalué 10 ejemplos de "urlshortener" y su documentación.

Si algo como documentar 3-4 endpoints, el 99% de la gente hace mal, imagínate hacer una SDK. Ya realizar esta API con 3-4 endpoints a muchos se les atraganta y no usan status code, o te devuelven fumadas incomprensibles... Que requieren 10 paginas de texto como el Ejemplo 7...

Si hacer el "hello world" de las API/backends tiene esta dificultad, imagínate hacer una SDK para un producto empresarial grande. Carga cognitiva, cambios compatibles en el tiempo, facilidad de uso, documentación y usabilidad, requerimientos de backend como rendimiento, reliability, escalabilidad, modularidad etc

desu

Errores mal hechos.

No voy a abrir el saco de excepciones, enums de monadas (rust, elm, haskell) vs tuplas (golang, C, python). Lo voy a cerrar rápido:

  • excepciones son mala practica siempre, "checked or unchecked", ambas mal joden la stack.
  • devuelve un Result<E, T>, un Option<T> o una tupla (resultado, error) o "a la c", como tu lenguaje lo implemente pero usa el stack bien.

Vengo a comentar el mayor error que veo en producción y me encontré de hecho el otro día en AWS. Los errores que no entiende ni su puta madre. Alguno me dirá que hacer buenos mensajes de error es difícil, como también es difícil hacer documentación clara. Difícil no significa que no se pueda hacer ni que existan ideas esenciales que tenemos que seguir.

Error: que, como, quien, donde, porque
Error: que, como, quien, donde, porque
Error: que, como, quien, donde, porque

El error que me tiraba AWS es curioso porque esta MUUUUY mal a todos los niveles:

An error occurred (AccessDeniedException) when calling the SendCommand operation: User: arn:aws:sts::***:assumed-role/github-backend-lxd/GitHubActions is not authorized to perform: ssm:SendCommand on resource: arn:aws:ssm:eu-west-1::document/AWS-RunShellScript because no identity-based policy allows the ssm:SendCommand action
Error: Process completed with exit code 254.

De nuevo, un claro ejemplo de mucho texto, poco contenido. Me gustaría re-escribirlo y decir, esto debería ser así. Pero el problema de diseño es mas grave.

El problema era que al crear la policy para permitir el SSM Y ADEMAS restringir las instancias para el SCRIPT DE ARRANQUE, al hacerlo todo en un statement, estaba asignando restricciones para todas las acciones, para todas las condiciones. Y esto resulta que no es posible, tuve que hacer 1 policy con 2 statements con restricciones separadas. AWS debería fallar en tiempo de crear la policy pero no lo hizo.

Este es el primer error. Código genérico que re-usan para crear todas las policies que después en runtime falla porque hay un "edge-case" que no han validado o se han dejado. Desconozco si tienen checks para todo, para este caso se ve que no. El error debería haber llegado mucho antes al crear la policy diciéndome, "error en crear policy, no puedes asignar esta restricción de recursos a estas acciones porque no se puede asignar el arranque a restricciones de instancias". Que, como, donde, cuando y porque. En el backend se sabe perfectamente porque eso no esta permitido.

Primer error? Los errores que no deberían haber existido. Por tener una validación mal o un código genérico, he creado código que después puede fallar en runtime. Solución? Si no puedes crear algo incorrecto, lo incorrecto nunca fallara.

Segundo error, no responderme a las 5 preguntas. Atentos a la magia:

  • error 400
  • error 400, crear policy
  • error 400, crear policy, "statement invalido"
  • error 400, crear policy, no puedes asignar "esta restricción" a "estas acciones"
  • error 400, crear policy, no puedes asignar "esta restricción" a "estas acciones", porque "esta restricción" no es compatible con "esta acción".

Y fijaros que este código es modular y autogenerable para cualquier restricción y acción, así que entiendo que AWS se ha fumado ese error que me paso a mi concreto. Dudo que AWS no tenga validaciones o un parseo de sus statements porque a veces me ha dado algún error.

Y el mismo problema lo encontramos en los logs, he visto millones de lineas de logs que no responden a las 5 preguntas. Y los logs son PRIVADOS, en los logs puedes hacer esto:

  • %timestamp%, %env%, %service%, %pod%, error 400, %user_Id%, %request_Id%, crear policy, %policy_id%, no puedes asignar "esta restricción" a "estas acciones", porque "esta restricción" no es compatible con "esta acción" %LINEA_DE_CODIGO_VALIDACION%.

Os pongo otro ejemplo tipico:

  • error al crear el stack
  • request_id error 400, create_stack, al crear el stack en la region region_id

Y seguramente tu codigo sera algo asi:

fun my_super_code_to_create_stack(stack, region_id):
   new_stack, error = internal.create_stack(stack, region_id)
   if error:  log
   else: return new_stack

Que puedo logear? En este ejemplo me falta la request_id no? Pues se la pasamos.

fun my_super_code_to_create_stack(request_Id, stack, region_id):
   new_stack, error = internal.create_stack(stack, region_id)
   if error:  log
   else: return new_stack

El aprendizaje con estos dos snippets es simple, el código y las funciones no hacen magia, hacen lo que tu les dices con lo que tu les dices, a veces necesitamos variables para métricas o logs, pásalas a la función, no pasa nada tranquilo, tus 5 strings no van a hacer bottleneck :) Me encuentro en mucho código que la gente se olvida de pasar las cosas abajo el stack para poder loggear. No seas así y pasa las ids que después te salvaran el culo si algo peta.

Conclusión responder a las 5 pregunta siempre. Si es algo interno mete todos los datos que tengas disponibles. Esto es un log, no una métrica. No seas racano.

1
desu

Entre el curro y otras cosas hoy he estado liado. Estaba mirando librerías similares a Gin.

  • echo: https://echo.labstack.com/docs/quick-start

  • chi: https://go-chi.io/#/

  • gin: https://gin-gonic.com/

  • Para backend cualquiera funciona, y Gin el tema del contexto propio en mi experiencia no es un problema en el día a día.

  • Las diferencias que he visto son la facilidad para hacer copy paste de cosas típicas

  • Echo esta mas cargado, Chi es mas ligero.

  • Chi me gusta que tiene un "autodoc", como comente taras, el tener una doc es un puntazo. Porque un middleware de logging me la pela, son cuatro lineas de código hacerlo tu a mano, pero el autodoc... No es tan simple.

En el curro tenemos microservicios con todos... gin, mux, echo y me suena que otro... asi que ya veis que no importa demasiado.

En la documentacion de echo encontrareis un monton de cosas tipicas que hay que ponerle, https, http2, autotls, auth o oauth, sesiones, el "/" final... al final son las cosas basicas de siempre que mola que te lo hagan. PERO, no veo la doc, y la doc (openapi) tiene prioridad por encima de estas cosas.

Manana os comparto un hello world con "chi".

Mi objetivo es el siguiente: el otro día comente las cosas que la gente hace mal, pues bueno, lo vamos a hacer bien. Esta vez oblidandonos un momento de la infraestuctura de AWS. Centrándonos primero en local. Y en el futuro lo podemos componer todo.

desu

El problema que veo es que la gente que se ha dedicado a crear las librerias de swagger/openapi para el ecosistema Go no son programadores de Go,C,Rust... Todos parece que vienen del mundo Java,PHP,PYthon y demas... porque la forma en que lo han hecho tanto en parsear como el codigo que generan esta claro que no saben lo que hacen. Son muy malos programadores, asi de simple.

Esto tambien te lo encuentras con las librerias de testeo, en golang hay algun framework para mockear que son una porqueria... gente de Java que en lugar de aprender Go han traido las malas practicas de Java al ecosistema... parece que con swagger es lo mismo.

Y en tema de ORMs para bases de datos tambien recuerdo ver muchas malas practicas. Comparado con SDKs de proveedores Cloud como AWS. Se nota que la comunidad open source de Golang esta infestada de gente de Java que no sabe programar y no deberia mantener librerias open source.

Fijaros:

// @Summary Show Account
// @Description get string by ID
// @ID get-string-by-int
// @Accept  json
// @Produce  json
// @Param id path int true "Account ID"
// @Success 200 {object} Account
// @Header 200 {string} Token "qwerty"
// @Router /accounts/{id} [get]
func getAccount(c echo.Context) error {
    id := c.Param("id")
    return c.JSON(http.StatusOK, "requested id : "+id)
}

Un ejemplo cualquiera, si tengo que anotar todo eso a mano, que diferencia hay en hacerlo con openapi siguiendo directamente su especificacion? Obviamente al principio sera un poco de curro, igual que es hacerlo en el codigo, a la larga . Y puedes usar un editor: https://editor.swagger.io/

En Java con spring, como spring ya requiere anotaciones para funcionar e inyectar cosas, esto ya lo usas. pero si no vas a usar anotaciones, ni quieres taggear todo a mano que hacemos? en go yo creo que siempre propondria mantenerlo a mano. y si tuivese que arreglar estas librerias de documentacion usando structs y un analisis estatico seguramente podria generar una gran cantidad de docu automatica para un router especifico, (gin, echo, chi)... sin tratar de ser super completo.

1
desu
rust, cli
backend para la cli, go, echo

Que estamos haciendo? Una porcelana para https://letterboxd.com/. Esta pagina tiene una versión pro que te saca datos y estadísticas a cambio de 12 euros al año. Existen herramientas gratuitas que te generan un excel que muchísima (miles de personas) usan. Vamos a hacerlo un poquito mejor. Esto ya lo hice hace un tiempo y usaban unas 20-30 personas.

  • scrap de letterboxd para los usuarios del producto
  • para cada usuarios revisar sus pelis, actores, directores, paises de las pelis... descargar todo lo necesario y almacenar en crudo en una blob comprimido
  • despues parsear y analizar estos datos y alamcenarlos en una dynamodb
  • ofrecer funcionalidades de data analysis sobre estos datos:
    • que similitud en tus gustos tienes con otro usuario?
    • top directores, pelis por pais etc Sort/GroupBy/Filters

La porcelana requiere:

Cuales son los costes?

  • Dependiendo del numero de usuarios. Cada usuario tendra su token y podrá acceder a todas las funcionalidades. El mayor coste seria el dominio/ip publica de la API
  • De nuevo, nuestro frontend podría ser estático como hicimos aquí: https://github.com/uglyorganization/frontend
    • Que cada usuario tenga su pagina personal. Nos ahorraríamos el backend entero moviéndolo al producer de datos. Como ya hicimos satisfactoriamente en el primer ejemplo de parsear /dev y sacar un top.
  • Dicho esto el mayor coste seria el de almacenamiento de los datos de letterboxd. Crece linealmente con el numero de usuarios. Por tanto no problema desde el punto de vista de planificación financiero.
JuAn4k4

Nosotros usamos spec first, y se genera el código directamente del controller.

1 respuesta
desu

#53 que pasa entonces cuando tienes que añadir cosas mas avanzadas o customizaciones a bajo nivel? te chafa el código? solo te cambia las firmas? yo entiendo que te chafa el código por eso no lo miro. Todo el tema de autocert, loggers, middlewares funciona bien?

1 respuesta
JuAn4k4

#54 El código que genera usa plantillas nuestras, tienes el control absoluto de todo, si necesitas algo más específico lo haces en otro sitio y no en el controlador. Si necesitas una API distinta no lo haces por el autogen e ya.

1
desu

Resumen Lunes 25/Marzo

  • he estado trabajando en otro proyecto que no puedo postear
  • un tema a comentar es el versionado de la API. Versionar en el path "v1"/"v2"?, headers? media type versioning?
  • aunque mucha gente se empeña en decir que esto es un debate abierto y no hay forma buena, lo mejor es usar el path
    • explicito, facilita las caches, funciona
  • si usar v1 o usar un timestamp da igual
  • un principio que hay que seguir es romper rápido y siempre que sea posible, la manera mas fácil de romper la API es tener múltiples versiones en el path.
  • el problema tradicionalmente no es la API en si, es que la gente, en su afán de abstracción y generalizar codigo, crea una variable de entorno o una global donde pone API_VERSION=v1 que usan en todos los endpoints... y no entienden que un endpoint puede evolucionar independiente de otros...
  • pero desu esto implica que mi mobile y mi binario lo tengo que recompilar y nseque... 1) es tu puto problema y 2) la solución no es tan difícil ni compleja como joder el diseño de la api

En código se vería algo así:

	g := e.Group("/v1")
	g.Use(middleware.KeyAuth(func(key string, c echo.Context) (bool, error) {
		return key == "valid-key", nil
	}))
	g.GET("/protected", func(c echo.Context) error {
		return c.NoContent(http.StatusOK)
	})

Donde puedes usar algún grupo o prefijo, y si algo tienes que bumpearlo independientemente, que es la buena practica, no bumpear toda la API porque 1 endpoint cambia. Pues lo haces:

	g.GET("/v2/protected", func(c echo.Context) error {
		return c.NoContent(http.StatusOK)
	})

Ahora imaginemos que estamos trabjanado en la CLI, y tengo que cambiar este endpoint... tengo que bumpear el versioning cierto? Si estaba en la 1.0.1 tengo que pasar a la 1.1.0 o 2.0.0 según tu versionado...

Como resolveríamos este inconveniente de la misma manera que hemos desacoplado las releases de la API?

Imagina que tenemos estos dos comandos:

cargo run -- --token API_TOKEN favorite view
cargo run -- --token API_TOKEN favorite create FILM_NAME

El primer comando hace una peticion curl a:

 GET /v1/favorites

Y el segundo comando:

 POST /v1/favorites film_name=FILM_NAME

Si ahora mi POST tiene una /v2/ donde le tengo que poner el FILM_ID en lugar del FILM_NAME, porque me he equivocado. Como realizamos el versioning en la CLI?

 POST /v2/favorites film_id=FILM_ID

Magia negra verdad? Imposible verdad? Diría que todas las CLI del mundo cada vez que hay un breaking en la API o un backend te obligan a bumpear la versión y adaptar tu código, no te dejan elegir. Y esto a veces es un cambio que cuesta implementarlo y puede pasar que haya otras releases de seguridad a posteriori que debes implementar... etc etc etc.

El problema de este modelo tradicional, mala practica, es que no se puede hacer "cherry-pick" de los cambios y tener tu propia CLI con todo lo que quieres como quieres. Podemos solucionarlo? Que pasa si un usuario quiere usar la "v1" pero otro usuario quiere usar la "v2"? Y queremos que ambos tengan todos los cambios requeridos por seguridad o funcionalidades futuras.

Wei-Yu

justo me encontré hace poco este artículo sobre el versioning en stripe que aunque es algo overkill para la mayoría de casos da una perspectiva interesante

https://stripe.com/blog/api-versioning

1 respuesta
desu

#57 lo encontraste aquí

#42desu:

- versioning con changes declarativos: https://stripe.com/blog/api-versioning

1 1 respuesta
Wei-Yu

#58 creo que fue lobsters pero para el caso

desu

Voy a solucionar el problema, la idea es similar, tratar el versionado como algo que va a cambiar, porque lo va a hacer...

spoiler

Y ya podemos:

cargo run -- --token MY_TOKEN v2 command2
cargo run -- --token MY_TOKEN v1 command2

Donde cada subcommand tendrá los parámetros que requiera.

cargo run -- --token MY_TOKEN v2 command2 create FILM_ID FILM_NAME
cargo run -- --token MY_TOKEN v1 command2 create FILM_NAME

Por ejemplo, no lo he implementado, pero se entiende. Flexibilidad y usablidad maxima para los usuarios de la CLI. UX driven design.

Y podemos aplicar la misma idea para tener distintos "base_path" o "entornos" en desarrollo. Yo recomiendo solucionar esto de la manera de nuevo mas simple, nuestra build de desarrollo tiene un parámetro extra que el usuario no tiene... Fácil y para toda la familia.

Notese que lo he puesto todo en el main para el lector, obviamente podemos simplificar el codigo.

Es sorprendente como la solución mas intuitiva y fácil no se aplique nunca y la gente termine haciendo monstruosidades tanto en las CLI, frontends, mobiles, balanceadores, caches... como en los backends para mantener 2 versiones o 3 de un endpoint...

pero... hay que duplicar código!

  • si tu API tiene ideado no soportar v1 y v2 concurrentes, al final la v1 la vas a borrar
  • dependiendo de tu lenguaje, la implementación compartida la podrás poner en el mismo modulo... asi que solo repites "definiciones" en enums o similares que deben seguir la docu...
  • ?

pero... obliga al usuario a pasar un parámetro extra!

  • tu usuario va a llamar la CLI con un script o a mano
  • a mano va a hacer copy&paste de la docu
  • a script va a poner un parametro/alias ...
  • ?

sin entrar a nivel de backend, una API gigante como la de Stripe que ha mutado de mil maneras, el 99.999% de los proyectos porque no pueden hacer esto?

porque el problema que tiene stripe es que tienen microservicios, que devuelven distintas versiones, y luego al usuario tienen que devolver otra version... es un problema distinto a la relacion 1 a 1 que es un CLIENTE (frontend, mobile) a API.

La manera de solucionar el problema de Stripe seria que el usuario tendría que pasar VARIOS parámetros y conocer TODAS las implementaciones posibles de los recursos para aplanar el mappeado como yo he hecho... Esto puede ser posible... Tan solo hay que leer la docu... Lo que el problema entonces para entenderlo seria para el usuario... Quien sabe, quizás es lo mejor. Quizas estas abstracciones a la larga solo hacen monstruos en backend e ignorantes que no piensan en el frontend.

No se, estoy cansado de bumpear la CLI porque he cambiado el nombre de un parámetro a un endpoint. Y que luego mis usuarios no puedan recibir los patches de seguridad si no estan en la ultima versión... La informática no es tan difícil eh.