Servidor GraphQL code-first
El esquema de GraphQL define los contratos de un servicio GraphQL, exponiendo el conjunto de tipos, campos y mutaciones que pueden ejecutarse contra el servicio. Al crear un servicio GraphQL, podemos decidir entre:
- que el esquema sea la fuente única de la verdad y que todo nuestro código de implementación se ajuste a sus definiciones
- que nuestro código sea la fuente única de la verdad y que el esquema sea un artefacto generado a partir del código
En cualquiera de los dos casos tendremos un servicio GraphQL plenamente funcional, pero, según el enfoque que utilicemos, podremos lograr más o menos funcionalidades, con más o menos facilidad, a lo largo del tiempo. Estos dos enfoques se denominan, respectivamente, "schema-first" (mejor llamado "SDL-first") y "code-first".
Gato GraphQL utiliza el enfoque code-first. Veamos por qué.
Por qué Gato GraphQL utiliza code-first
En el enfoque code-first, comenzamos programando los resolvers y, a partir del código como fuente única de la verdad, generamos el esquema como un artefacto. Por lo tanto, el esquema se crea ejecutando un script, en lugar de crearse manualmente como en SDL-first. Dado que code-first también dispone de un esquema, no le falta nada significativo de lo que ofrece SDL-first.
Sin embargo, code-first sí ofrece una característica importante frente a SDL-first: la posibilidad de proporcionar esquemas dinámicos, que pueden cambiar su forma y atributos en función del contexto y regularse mediante código en tiempo de ejecución. De hecho, todas las grandes funcionalidades que ofrece Gato GraphQL son una consecuencia directa de su adopción de code-first.
Ventajas de code-first
Un esquema dinámico aporta, entre otras, todas las ventajas que se enumeran a continuación:
La fuente de la verdad del esquema es un superconjunto del exigido por GraphQL. Las propiedades adicionales (como los campos globales, las conexiones globales, las directivas globales y los fragmentos persistidos) ya pueden utilizarse en nuestra API sin tener que esperar a que se añadan a la especificación de GraphQL, si es que algún día se añaden.
Como la fuente de la verdad no está atada al esquema, también podemos generar cualquier esquema para cualquier otro sistema: GraphQL es solo uno de los destinos posibles. Por ejemplo, puede generar un JSON-schema para un servicio REST a partir de la misma fuente de la verdad.
La API puede ser pública/privada al mismo tiempo, dependiendo de si el usuario ha iniciado sesión o no y de los roles del usuario autenticado, u ofrecer más o menos campos según alguna otra propiedad, como si el usuario ha pagado por la membresía PRO.
Los tipos no saben de antemano qué campos resolverán. En su lugar, los resolvers de campo se asocian a los resolvers de tipo mediante el patrón publish-subscribe, y los resolvers de campo pueden sobrescribir otros resolvers de campo. Esta característica hace que la API sea muy extensible, permitiéndonos disponer de un código general para nuestra API y personalizarlo a nivel de aplicación para un cliente o proyecto concreto.
Un campo puede ser procesado no solo por un resolver, sino por varios: cada resolver de campo en la cadena puede decidir, en tiempo de ejecución, si procesa el campo o no en función de alguna propiedad, o si lo pasa al siguiente eslabón de la cadena. Por ejemplo, un resolver de campo especial puede usarse solo si se pasa un argumento de campo "source: testing", lo que permite probarlo en unos pocos sitios en producción antes del lanzamiento general; la misma estrategia también permite ofrecer correcciones rápidas de errores para un cliente o entorno concreto sin correr el riesgo de provocar efectos secundarios no deseados en cualquier otro lugar.
Los tipos e interfaces pueden recibir automáticamente un espacio de nombres para evitar colisiones con terceros.