- Resumen
- Abbreviations
- Contexto
- Research Questions
- Research Framework
- Research Methodology
- Objetivos
- Marco Teórico
- Desarrollo: Metodología
- Desarrollo: Requerimientos
- Desarrollo: Alcance
- Desarrollo: Pruebas
- Desarrollo: RAD
- Results: Type System
- Results: Operational Equivalence
- Results: Compatibility Validation
- Conclusions
Esta tesis presenta el desarrollo de una implementación del lenguaje de consulta GraphQL en el lenguaje de programación Go, así como la validación de su compatibilidad con implementaciones de referencia.
GraphQL es un protocolo de comunicación entre clientes y servidores, en el cual los servidores definen sus capacidades mediante esquemas. Este lenguaje permite realizar operaciones como consultas, mutaciones y suscripciones, y fue diseñado para facilitar la interacción entre interfaces de usuario y servidores.
La implementación se fundamentó en dos fuentes principales:
- La Especificación oficial de GraphQL.
- La implementación de GraphQL en el lenguaje de programación JavaScript.
El objetivo principal fue desarrollar una implementación compatible con la versión v0.6.0 de graphql-js, la biblioteca de referencia en JavaScript.
Como resultado, se creó el proyecto de código abierto graphql-go/graphql, utilizando GitHub como sistema de control de versiones y plataforma para el ciclo de vida del desarrollo del software.
Se eligió el lenguaje Go debido a su naturaleza moderna, su creciente adopción en nuevos proyectos y su enfoque en la computación en la nube, lo cual se alinea con los beneficios ofrecidos por GraphQL.
El correcto funcionamiento del diseño de la API se confirmó mediante la comparación de aplicaciones de ejemplo desarrolladas en ambos lenguajes. Asimismo, la compatibilidad fue verificada a través de una biblioteca de código abierto denominada graphql-go/compatibility-standard-definitions, que representa una contribución novedosa dentro del contexto de esta investigación.
| Term | Description |
|---|---|
| GraphQL | A Query Language |
graphql-js |
GraphQL JavaScript reference implementation |
graphql-go |
GraphQL Go implementation |
La estrategia tradicional para desarrollar software se basa en herramientas que permiten la comunicación entre clientes y servidores utilizando protocolos tradicionales como: RPC1, SOAP2, REST3.
Estas herramientas centralizan el funcionamiento en el lado del servidor, donde se define la información con la que se puede interactuar. Estas estrategias de comunicación generan diversos problemas que se resuelven bajo demanda con distintas soluciones.
Se crean múltiples endpoints para cubrir diversos casos de uso, lo que genera complejidad en su gestión debido a que en el lado del cliente se agregan soluciones ad-hoc.
Estos diferentes endpoints provocan problemas de sobrecarga o insuficiencia de datos. Como consecuencia, se requieren múltiples solicitudes para consolidar la información, ya que el servidor decide qué datos enviar, generando cargas útiles mayores o menores a las esperadas.
Una de las principales consecuencias de tener múltiples endpoints es la generación de solicitudes anidadas, lo cual conlleva una complejidad conocida como el problema n + 1.
Se produce ineficiencia en el mantenimiento porque cuando se hacen cambios en el servidor, estos impactan en los distintos clientes que dependen de él, volviendo a los clientes más propensos a errores.
Los costos aumentan porque los datos enviados desde los servidores requieren mayor capacidad para atender la demanda, por lo tanto se necesitan más recursos y aprovisionamiento.
La experiencia de desarrollo se ve limitada porque se requieren múltiples herramientas para interactuar con cada uno de los protocolos utilizados por los servidores, lo que impacta negativamente al momento de integrar nuevos miembros al equipo y también afecta la curva de aprendizaje.
Existe complejidad en el lado del cliente de la aplicación porque se requieren múltiples capas de abstracción para coordinar y re-consolidar la información, lo que vuelve al código difícil de mantener debido a la necesidad de múltiples soluciones para abordar los problemas.
Los protocolos tradicionales generan múltiples estrategias para gestionar el versionado de la API, lo que desencadena complejidad en el lado del servidor y provoca una extensibilidad limitada.
RQ1. Is graphql-go implemented according to graphql-js?
This question investigates how the
graphql-goimplementation aligns with the structure and behavior ofgraphql-js, including type system definitions, resolver handling, and API design.
RQ2. Is graphql-go compatible with graphql-js?
This question focuses on runtime behavior, internal API consistency, and validation through introspection and execution results.
-
Justification Framework The structured approach divides justification into three categories—Introduction, Applied, and Social—aligning with the layered reasoning recommended by Hernández‑Sampieri & Mendoza (2018).
-
Research Strategy Alignment This study follows a mixed-method approach as outlined by Hernández‑Sampieri & Mendoza (2018):
- Qualitative: Applied to RQ1, focusing on the implementation. This includes analyzing code structures and comparing API design and runtime outputs between
graphql-jsandgraphql-go. - Quantitative: Applied to RQ2, focusing on compatibility validation. Using introspection, the internal type systems are programmatically compared, ensuring output equivalence across implementations.
- Qualitative: Applied to RQ1, focusing on the implementation. This includes analyzing code structures and comparing API design and runtime outputs between
-
Problem Definition & Validation Mechanisms Their methodology encourages clear research problem statements, guided questions (Covered by RQ1 and RQ2), empirical evidence gathering, and comparative analysis (Reflected by the
graphql-goimplementation, cross-language validation, and compatibility tool).
- Implementar GraphQL en el lenguaje de programación Go.
- Validar la compatibilidad de la implementación de GraphQL Go con
graphql-js.
- Investigar el contexto y las motivaciones del diseño de GraphQL y su relevancia en los sistemas modernos.
- Estudiar el estado actual de las implementaciones de GraphQL en Go.
- Analizar la arquitectura y el proceso de desarrollo del proyecto de código abierto
graphql-go/graphql. - Documentar las prácticas de ingeniería de software utilizadas en el desarrollo de la biblioteca de GraphQL en Go.
- Diseñar y desarrollar una biblioteca de validación:
graphql-go/compatibility-standard-definitions. - Evaluar la compatibilidad con
graphql-jsmediante introspección y comparaciones de tiempo de ejecución.
99designs/gqlgen (GitHub)
Esta biblioteca implementa GraphQL a partir de un esquema definido en un archivo .graphql, generando automáticamente todos los componentes necesarios del lado del servidor en tiempo de compilación. Entre los elementos generados se incluyen: un servidor HTTPS, punto de acceso GraphQL, pruebas unitarias, y herramientas de desarrollo como GraphQL Playground. Su ventaja principal radica en la centralización de la definición del sistema de tipos y la automatización de su desarrollo.
Limitaciones: La extensibilidad se ve restringida debido a la generación automática de código Go, dificultando las personalizaciones avanzadas sin modificar dependencias internas del proyecto.
graph-gophers/graphql-go (GitHub)
Implementa la especificación de GraphQL iniciando desde un archivo de esquema en texto plano, mientras que los resolutores se definen manualmente en código Go. Su ventaja principal radica en la adopción generalizada por parte de la comunidad de Go y su núcleo compartido, que favorece el mantenimiento colaborativo.
Limitaciones: Al definirse el esquema a nivel de texto, se requiere infraestructura adicional para mantener la fuente de verdad del sistema de tipos.
dosco/graphjin (GitHub) Propone una solución declarativa de extremo a extremo que traduce un esquema GraphQL directamente a consultas SQL. Esta biblioteca genera código Go que permite consultas, mutaciones y suscripciones sin necesidad de lógica personalizada.
Limitaciones: Al ser una solución integrada, introduce dependencia en su núcleo, dificultando su extensión sin intervención directa sobre el proyecto principal.
Karla Cecilia Reyes Burgos (2023): En su estudio titulado Servicios web con GraphQL, se realiza una revisión sistemática de literatura sobre el uso de GraphQL. Se enfocó en responder las siguientes preguntas:
-
¿Qué áreas científicas muestran mayor interés en el desarrollo de servicios web con GraphQL?
La industria médica lidera el interés en la implementación de GraphQL. -
¿Qué países presentan mayor interés en el desarrollo de servicios web con GraphQL?
Estados Unidos encabeza el uso e implementación de GraphQL. -
¿Cuál fue el año con mayor número de investigaciones relacionadas al desarrollo de servicios con GraphQL?
El año 2019 reportó el mayor número de soluciones informáticas basadas en GraphQL.
-
Implementación de GraphQL en Go
- Paridad de Implementación
- Corrección de Implementación
-
Validación de Compatibilidad de GraphQL en Go
- Equivalencia de Validación de Compatibilidad vía Introspección
-
graphql-js (Implementación de Referencia en JavaScript)
- Actualizaciones de la API
- Cambios en Componentes Centrales
- Cambios en el Sistema de Tipos
- Capacidades de Introspección
-
Especificación de GraphQL
- Cambios en la Documentación de la Especificación
Enfatiza iteraciones rápidas para desarrollar software.
- Prototipado: Validar ideas mediante versiones tempranas.
- Retroalimentación del usuario: Incorporar mejoras basadas en uso real.
- Desarrollo veloz: Ideal para entornos de desarrollo ágil.
Se enfoca en colaboración abierta y descentralizada.
- Revisión por pares: Verificación constante para minimizar errores.
- Contribución descentralizada: Apoyo global con herramientas compartidas.
- Código público: Transparencia total que facilita auditoría y colaboración.
- Prototipado rápido: Permite innovación acelerada por el acceso directo al código fuente.
- Colaboración: Participación diversa que enriquece el aprendizaje colectivo.
El desarrollo de la biblioteca graphql-go/graphql siguió la metodología de Desarrollo Rápido de Aplicaciones (RAD) para facilitar una implementación ágil e iterativa alineada con el modelo de referencia graphql-js.
La implementación comenzó con componentes funcionales mínimos y se expandió de manera incremental. Los esfuerzos iniciales se centraron en módulos fundamentales, incluidos el procesamiento del texto fuente, el análisis léxico (lexer), la construcción del árbol sintáctico (AST), el análisis del esquema y los mecanismos de resolución de campos.
A medida que el proyecto evolucionaba, la retroalimentación de los usuarios jugó un papel clave. En lugar de seguir un plan de desarrollo rígido, se priorizó la integración continua de sugerencias recopiladas a través de GitHub mediante Issues y Pull Requests. Esto permitió una respuesta ágil a las necesidades emergentes, manteniendo al mismo tiempo la alineación con el código base de graphql-js, la Especificación de GraphQL y las mejores prácticas del lenguaje Go.
El proyecto se benefició de ciclos de desarrollo cortos, lo que permitió lanzamientos frecuentes. Esta entrega acelerada fue impulsada por la demanda real de empresas que requerían capacidades funcionales de GraphQL en Go, lo que exigía un ritmo de desarrollo eficiente y adaptable.
El paradigma de desarrollo de código abierto sustentó el ciclo de vida del proyecto, promoviendo la transparencia, la colaboración y la innovación impulsada por la comunidad. Alojado en GitHub, el proyecto se mantuvo accesible públicamente desde sus primeras etapas y fomentó la participación global.
La revisión por pares impulsada por la comunidad fue esencial para garantizar la calidad del software. Los colaboradores reportaron problemas, sugirieron mejoras, corrigieron errores y aplicaron parches de seguridad críticos, fortaleciendo la confiabilidad de la implementación.
El desarrollo no estuvo vinculado a una única entidad u organización. Por el contrario, colaboradores de diversas regiones y perfiles profesionales contribuyeron de forma asincrónica utilizando GitHub como plataforma central de coordinación.
Desde sus primeras versiones, el repositorio fue publicado bajo la licencia permisiva MIT, fomentando el uso libre y la colaboración abierta. Esta decisión se alineó con el modelo de licencia adoptado por la implementación de referencia en JavaScript, graphql-js, que en su versión v0.6.0 utilizaba una licencia BSD de tres cláusulas1. Esta compatibilidad de licencias facilitó tanto el aprendizaje académico como el uso comercial, permitiendo la creación de proyectos derivados mediante forks, integraciones y adaptaciones particulares.
La plataforma GitHub respaldó la naturaleza ágil del proyecto al proporcionar herramientas esenciales como seguimiento de incidencias, pull requests, etiquetado, ramificación y lanzamientos versionados. Estas capacidades permitieron a los colaboradores iterar rápidamente y gestionar eficazmente los hitos del desarrollo.
La colaboración entre equipos multidisciplinarios fue una piedra angular del proyecto. Las funciones colaborativas de GitHub fomentaron el intercambio de documentación, el seguimiento de decisiones y discusiones transparentes sobre compensaciones de diseño. Esto apoyó la mantenibilidad a largo plazo y redujo la curva de aprendizaje para nuevos colaboradores y usuarios.
- La implementación debe estar escrita en el lenguaje de programación Go.
- Debe implementar GraphQL siguiendo la versión 0.6.0 de
graphql-js. - La Especificación GraphQL servirá como guía alternativa en caso de ambigüedad o ausencia de detalles en
graphql-js.
- Compatible con sistemas operativos cruzados.
- Ejecutable en el entorno de ejecución estándar de Go, evitando dependencias de C (cgo).
- Debe seguir las mejores prácticas de seguridad recomendadas por la comunidad de Go.
- Aplicar buenas prácticas de diseño de API y estructuras internas según las convenciones de Go.
- Incluir comentarios explicativos en el código fuente.
- Integrar herramientas de cobertura de pruebas.
- Proveer ejemplos de código para casos de uso comunes.
- El proyecto debe ser de código abierto.
- Debe seguir flujos de trabajo colaborativos que incluyan revisión de código.
- La aceptación por parte de la comunidad de código abierto servirá como indicador de su capacidad de adopción y escalamiento.
- El rendimiento debe ser validado a través de pruebas unitarias que incluyan evaluaciones de desempeño fundamentales.
- La solución debe poder integrarse en otros proyectos de Go mediante interfaz de línea de comandos (CLI).
- Debe mantener una mínima desviación respecto a
graphql-jspara conservar la paridad de diseño de API.
- La herramienta de validación de compatibilidad debe comparar el sistema de tipos de
graphql-jsygraphql-gousando introspección. - Debe ser ejecutable via la interface de linea de commandos (CLI).
- La herramienta debe ser escrita en Go.
- De ser necesario usar otras bibliotecas de Go open-source.
- Compatible con sistemas operativos cruzados.
- Ejecutable en el entorno de ejecución estándar de Go, sin necesidad de cgo.
- Debe aplicar las mejores prácticas de seguridad reconocidas en la comunidad de desarrollo en Go.
- Aplicar buenas prácticas de diseño de API y estructuras internas en Go.
- Incluir comentarios explicativos en el código fuente.
- Integrar herramientas de cobertura de pruebas.
- Incluir scripts ejecutables para facilitar la interacción mediante CLI.
- Debe tratarse de un proyecto de código abierto.
- Requiere procesos colaborativos de revisión de código para garantizar calidad.
- La aceptación y uso por parte de la comunidad será un indicador clave.
- La validación de rendimiento debe estar basada en la actividad del repositorio y la eficiencia del procesamiento con caché.
- El sistema debe ser integrable en otros proyectos de Go utilizando la interfaz de línea de comandos (CLI).
- Debe permitir la integración de nuevas funcionalidades dentro del CLI.
Esta investigación tiene como objetivo explorar la integración de GraphQL en el ecosistema de programación Go, centrándose tanto en la implementación de la especificación de GraphQL como en su validación de compatibilidad. El estudio establece una base técnica y metodológica para la evolución continua de bibliotecas open-source de GraphQL mediante herramientas automatizadas y entornos colaborativos de contribución.
El alcance de la implementación se encuentra anclado a la implementación de referencia en JavaScript (graphql-js) en su versión 0.6.0. Aunque esta versión constituye la base del desarrollo, el proyecto promueve futuras mejoras mediante contribuciones de la comunidad, alineadas con principios de extensibilidad y compatibilidad retroactiva.
Las mejoras no deben alterar la funcionalidad existente, a menos que sean impulsadas explícitamente por cambios en la implementación de referencia. La estabilidad es un objetivo clave, y la implementación es validada mediante aplicaciones reales en entornos de producción de múltiples organizaciones.
La biblioteca reproduce el modelo imperativo de construcción de esquemas utilizado por graphql-js, lo que permite una interfaz completamente programable para interactuar con el sistema de tipos interno. La solidez del sistema se garantiza al replicar el conjunto original de pruebas unitarias, adaptado idiomáticamente para Go, asegurando paridad de características y coherencia de comportamiento.
La herramienta de validación de compatibilidad está diseñada como un componente externo, intencionalmente desacoplado de la implementación principal. Su arquitectura modular permite integrar futuras implementaciones de GraphQL más allá de las evaluadas en este estudio.
La herramienta verifica la equivalencia en tiempo de ejecución mediante comparaciones basadas en introspección, enfocándose en la compatibilidad estructural entre sistemas de tipos. Además, sienta las bases para la integración con CI/CD, permitiendo que futuros mantenedores automaticen las verificaciones de compatibilidad durante los flujos de trabajo de desarrollo.
La implementación toma como referencia principal el diseño de graphql-js. Sin embargo, se realizan adaptaciones para ajustarse a las prácticas idiomáticas de Go, evitando patrones específicos del lenguaje JavaScript. Este proceso enfatiza la fidelidad conceptual sobre la replicación sintáctica.
Asimismo, la herramienta de validación de compatibilidad se limita inicialmente a la versión 0.6.0 de graphql-js. Aunque esta restricción reduce su alcance inmediato, su diseño modular facilita su ampliación para futuras versiones u otras implementaciones de referencia.
Esta investigación se limita explícitamente a evaluar y replicar el comportamiento de graphql-js en su versión 0.6.0. Si bien se considera la extensibilidad, los esfuerzos de validación y las conclusiones están limitados a dicha versión histórica.
Las siguientes iniciativas fueron consideradas conceptualmente para enriquecer la validación de compatibilidad, pero quedaron fuera del alcance de este estudio debido a limitaciones de tiempo y recursos. Se proponen como trabajos futuros:
- Pruebas de Compatibilidad Unitarias (GitHub): Framework para validar nombres de pruebas unitarias entre
graphql-jsygraphql-go. - Aceptación de Usuario en Compatibilidad (GitHub): Análisis centrado en el usuario para comparar métricas de adopción, patrones de retroalimentación y características de uso entre
graphql-jsygraphql-go.
La estrategia para la implementación de graphql-go fue crear pruebas unitarias siguiendo la convención de nombres de las pruebas unitarias de la implementación de referencia graphql-js, pero debido a la creación natural de convenciones propias del implementador, la estrategia de mapeo 1 a 1 en los nombres de las pruebas unitarias no se siguió estrictamente. Algunas pruebas unitarias aún mantienen nombres similares a sus equivalentes en graphql-js, verificando componentes análogos.
Por ello, inicialmente se tuvo la intención de crear graphql-go/compatibility-unit-tests, lo cual requería refactorizaciones de código con la intención de hacer coincidir los nombres de pruebas unitarias entre graphql-go y graphql-js, pero este proyecto quedó fuera del alcance y se agregó como trabajo futuro.
Aunque la convención de coincidencia en los nombres de pruebas no se mantuvo como estrategia establecida, la implementación contiene una suite de pruebas robusta con herramientas que aseguran la reducción de riesgos de errores mediante regresiones.
El entorno de pruebas incluye, por ejemplo, herramientas de cobertura de código que aseguran que el proyecto no descienda por debajo del estado de calidad deseado. Actualmente, la base de cobertura de código es: 92%.
La herramienta de validación de compatibilidad es una biblioteca basada en CLI que contiene pruebas unitarias para sus componentes principales.
Actualmente no contiene herramientas de integración continua (CI) como la biblioteca de implementación.
Se agregó como trabajo futuro mejorar el entorno de pruebas para soportar los siguientes aspectos:
- Cobertura de código.
- Integración continua (CI).
- Aumento del número de pruebas y cobertura.
La implementación de la biblioteca graphql-go/graphql adoptó un modelo de Desarrollo Rápido de Aplicaciones (RAD), caracterizado por contribuciones iterativas a través de pull requests en GitHub. En lugar de seguir una hoja de ruta estrictamente predefinida, el desarrollo surgió de manera orgánica mediante interacciones comunitarias, discusiones en issues y necesidades prácticas derivadas del portado de características desde la implementación de referencia, graphql-js.
Cada tarea, representada como un pull request individual, abordó componentes específicos como el ejecutor, resolutor, impresor, analizador sintáctico e introspección. Este enfoque hizo énfasis en la modularidad, mantenibilidad y conformidad con la especificación de GraphQL versión 0.6.0, incorporando frecuentemente mejoras paralelas encontradas en graphql-js.
Este enfoque ascendente, basado en pull requests, permitió una rápida creación de prototipos y pruebas de funcionalidades, donde muchas decisiones de diseño se discutieron y resolvieron abiertamente dentro de los hilos de las pull requests. En consecuencia, el historial de desarrollo constituye una línea de tiempo de soluciones prácticas moldeadas tanto por el conocimiento colectivo como por los requisitos en evolución para garantizar la compatibilidad de GraphQL en Go.
Para facilitar la adopción y uso por parte de proyectos externos, se utilizaron etiquetas de GitHub (Tags) para publicar versiones. Estas etiquetas no siguen necesariamente una relación 1:1 con las versiones correspondientes de graphql-js, sino que representan hitos estables con sus respectivas notas de lanzamiento.
La siguiente sección presenta una lista detallada de las solicitudes de extracción que documentan la evolución de la implementación.
La herramienta de validación de compatibilidad siguió un enfoque de desarrollo estrechamente alineado con la metodología de Desarrollo Rápido de Aplicaciones (RAD), caracterizada por ciclos cortos e incrementales, impulsados principalmente mediante pull requests. A diferencia de metodologías tradicionales basadas en planificación, el desarrollo no comenzó con una hoja de ruta completamente definida. En su lugar, la evolución del proyecto fue guiada por la integración continua de funcionalidades abordadas iterativamente.
A diferencia de la implementación original de graphql-go, este proyecto puso un mayor énfasis en el seguimiento de tareas mediante GitHub Issues. Se mantuvo, en la mayoría de los casos, una relación uno a uno entre issues y sus pull requests asociados, lo que proporcionó trazabilidad y un mecanismo de planificación ligera.
Además, el proyecto experimentó con el uso de herramientas inteligentes, como un agente de inteligencia artificial denominado mentatbot, al cual se le asignaron issues que luego fueron abordados mediante pull requests automatizadas o asistidas. Este enfoque refleja la creciente integración de herramientas inteligentes en los flujos modernos de desarrollo de software.
Todos los pull requests fueron desarrollados en ramas aisladas antes de integrarse a la rama main, que funcionó como la versión estable por defecto del proyecto, dado que no se utilizaron etiquetas de versiones formales. Este flujo de trabajo basado en ramas permitió agilidad y menor sobrecarga, en línea con los principios del RAD.
A continuación, se presenta un listado detallado de los pull requests que documentan la evolución de la herramienta de validación de compatibilidad.
To validate the implementation of the core GraphQL type system, we created equivalent fields and types in both the JavaScript and Go example applications using graphql-js and graphql-go, respectively. Both libraries follow an imperative schema definition pattern and maintain a near-identical API surface, faithfully reproducing the GraphQL Specification’s flexibility in schema construction styles while emphasizing programmatic control.
This section presents the implementation details of various GraphQL type system elements. Each type is documented with side-by-side code snippets and concise descriptions to aid in comparative understanding.
Note: In all
graphql-goexamples, we adhere to Go coding style conventions. For instance, allResolvefunctions return two values—data and anerror—which is a fundamental idiom in Go for error handling.
Scalars are the basic leaf values in GraphQL.
graphql-js:
int: {
type: GraphQLInt,
resolve() {
return 20;
},
},graphql-go
"int": &graphql.Field{
Type: graphql.Int,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return 20, nil
},
},graphql-js
float: {
type: GraphQLFloat,
resolve() {
return 20.01;
},
},graphql-go
"float": &graphql.Field{
Type: graphql.Float,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return 20.01, nil
},
},graphql-js
string: {
type: GraphQLString,
resolve() {
return "str";
},
},graphql-go
"string": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return "str", nil
},
},graphql-js
boolean: {
type: GraphQLBoolean,
resolve() {
return true;
},
},graphql-go
"boolean": &graphql.Field{
Type: graphql.Boolean,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return true, nil
},
},graphql-js
ID: {
type: GraphQLID,
resolve() {
return "d983b9d9-681c-4059-b5a3-5329d1c6f82d";
},
},graphql-go
"ID": &graphql.Field{
Type: graphql.ID,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return "d983b9d9-681c-4059-b5a3-5329d1c6f82d", nil
},
},Defines structured data types with fields.
graphql-js
const objectTypeWithArguments = new GraphQLObjectType({
name: "objectTypeWithArguments",
description: "An object with arguments.",
fields: () => {
return {
name: {
description: "The name of the object.",
type: GraphQLString,
},
};
},
});graphql-go
objectTypeWithArguments := graphql.NewObject(graphql.ObjectConfig{
Name: "objectTypeWithArguments",
Description: "An object with arguments.",
Fields: graphql.Fields{
"name": &graphql.Field{
Description: "The name of the object.",
Type: graphql.String,
},
},
})Used to abstract fields shared by multiple types.
graphql-js
const nodeInterface = new GraphQLInterfaceType({
name: "Node",
description: "An object with an ID.",
fields: {
id: {
type: GraphQLID,
description: "The ID of the object."
}
},
resolveType(obj) {
switch (obj.type) {
case "user":
return userType;
case "product":
return productType;
}
return null;
},
});graphql-go
nodeInterface = graphql.NewInterface(graphql.InterfaceConfig{
Name: "Node",
Description: "An object with an ID.",
Fields: graphql.Fields{
"id": &graphql.Field{
Type: graphql.ID,
Description: "The ID of the object.",
},
},
ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object {
if obj, ok := p.Value.(map[string]interface{}); ok {
switch obj["type"] {
case "user":
return userType
case "product":
return productType
}
}
return nil
},
})Allows fields to return one of multiple object types.
graphql-js
const searchResultUnion = new GraphQLUnionType({
name: "SearchResult",
description: "A union of User and Product types.",
types: [userType, productType],
resolveType: (obj) => {
switch (obj.type) {
case "user":
return userType;
case "product":
return productType;
}
return null;
},
});graphql-go
searchResultUnion = graphql.NewUnion(graphql.UnionConfig{
Name: "SearchResult",
Description: "A union of User and Product types.",
Types: []*graphql.Object{userType, productType},
ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object {
if obj, ok := p.Value.(map[string]interface{}); ok {
switch obj["type"] {
case "user":
return userType
case "product":
return productType
}
}
return nil
},
})Defines a fixed set of possible values.
graphql-js
const enumType = new GraphQLEnumType({
name: "Enum",
description: "A enum.",
values: {
FIRST_ENUM: {
value: 1,
description: "First enum value.",
},
SECOND_ENUM: {
value: 2,
description: "Second enum value.",
},
},
});graphql-go
enumType := graphql.NewEnum(graphql.EnumConfig{
Name: "Enum",
Description: "A enum.",
Values: graphql.EnumValueConfigMap{
"FIRST_ENUM": &graphql.EnumValueConfig{
Value: 1,
Description: "First enum value.",
},
"SECOND_ENUM": &graphql.EnumValueConfig{
Value: 2,
Description: "Second enum value.",
},
},
})Used for passing structured input to queries or mutations.
graphql-js
const userInputType = new GraphQLInputObjectType({
name: "UserInput",
description: "Input type for user data.",
fields: () => {
return {
name: {
type: GraphQLString,
description: "The name of the user.",
},
email: {
type: GraphQLString,
description: "The email of the user.",
},
age: {
type: GraphQLInt,
description: "The age of the user.",
},
};
},
});graphql-go
userInputType := graphql.NewInputObject(graphql.InputObjectConfig{
Name: "UserInput",
Description: "Input type for user data.",
Fields: graphql.InputObjectConfigFieldMap{
"name": &graphql.InputObjectFieldConfig{
Type: graphql.String,
Description: "The name of the user.",
},
"email": &graphql.InputObjectFieldConfig{
Type: graphql.String,
Description: "The email of the user.",
},
"age": &graphql.InputObjectFieldConfig{
Type: graphql.Int,
Description: "The age of the user.",
},
},
})Represents arrays of values or objects.
graphql-js
stringList: {
type: new GraphQLList(GraphQLString),
resolve() {
return ["first string", "second string", "third string"];
},
},
objectList: {
type: new GraphQLList(objectType),
resolve() {
return [
{ name: "First object in list" },
{ name: "Second object in list" },
{ name: "Third object in list" },
];
},
},graphql-go
"stringList": &graphql.Field{
Type: graphql.NewList(graphql.String),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return []string{"first string", "second string", "third string"}, nil
},
},
"objectList": &graphql.Field{
Type: graphql.NewList(objectType),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return []interface{}{
map[string]interface{}{ "name": "First object in list" },
map[string]interface{}{ "name": "Second object in list" },
map[string]interface{}{ "name": "Third object in list" },
}, nil
},
},Represents a declaration that a type disallows null.
graphql-js
const userTypeNonNull = new GraphQLObjectType({
name: "UserNonNull",
description: "A user with non-null fields.",
fields: () => {
return {
id: {
type: new GraphQLNonNull(GraphQLID),
description: "The non-null ID of the user.",
},
name: {
type: new GraphQLNonNull(GraphQLString),
description: "The non-null name of the user.",
},
};
},
});userNonNull: {
type: userTypeNonNull,
resolve() {
return {
id: "user-non-null-1",
name: "John Doe Non-Null",
};
},
},graphql-go
userTypeNonNull := graphql.NewObject(graphql.ObjectConfig{
Name: "UserNonNull",
Description: "A user with non-null fields.",
Fields: graphql.Fields{
"id": &graphql.Field{
Type: graphql.NewNonNull(graphql.ID),
Description: "The non-null ID of the user.",
},
"name": &graphql.Field{
Type: graphql.NewNonNull(graphql.String),
Description: "The non-null name of the user.",
},
},
})"userNonNull": &graphql.Field{
Type: userTypeNonNull,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return map[string]interface{}{
"id": "user-non-null-1",
"name": "John Doe Non-Null",
}, nil
},
},Allows for conditional exclusion during execution.
graphql-js
query ExampleQuery($skipUserName: Boolean!, $skipProductPrice: Boolean!, ...) {
// ...
}graphql-go
query ExampleQuery($skipUserName: Boolean!, $skipProductPrice: Boolean!, ...) {
// ...
}Allows for conditional inclusion during execution.
graphql-js
query ExampleQuery(... , $includeUserName: Boolean!, $includeProductPrice: Boolean!) {
// ...
}graphql-go
query ExampleQuery(... , $includeUserName: Boolean!, $includeProductPrice: Boolean!) {
// ...
}Represents an operation to mutate data.
graphql-js
mutation: new GraphQLObjectType({
name: "RootMutationType",
fields: {
createUser: {
type: userType,
args: {
input: {
description: "input for creating a user",
type: userInputType,
},
},
resolve(root, { input }) {
return {
type: "user",
id: `user-${Date.now()}`,
name: input.name,
};
},
},
},
}),graphql-go
mutationType := graphql.NewObject(graphql.ObjectConfig{
Name: "Mutation",
Fields: graphql.Fields{
"createUser": &graphql.Field{
Type: userType,
Args: graphql.FieldConfigArgument{
"input": &graphql.ArgumentConfig{
Description: "input for creating a user",
Type: userInputType,
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
input := p.Args["input"].(map[string]interface{})
return map[string]interface{}{
"type": "user",
"id": fmt.Sprintf("user-%d", time.Now().Unix()),
"name": input["name"],
}, nil
},
},
},
})Represents an operation for subscribing to data.
graphql-js
subscription: new GraphQLObjectType({
name: "RootSubscriptionType",
fields: {
userAdded: {
type: userType,
resolve() {
return {
type: "user",
id: `user-${Date.now()}`,
name: "New User Added",
};
},
},
},
}),graphql-go
subscriptionType := graphql.NewObject(graphql.ObjectConfig{
Name: "Subscription",
Fields: graphql.Fields{
"userAdded": &graphql.Field{
Type: userType,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return map[string]interface{}{
"type": "user",
"id": fmt.Sprintf("user-%d", time.Now().Unix()),
"name": "New User Added",
}, nil
},
},
},
})This detailed breakdown forms the foundation for the Conclusions section, where we compare design patterns and resolver behaviors across implementations.
This comparison demonstrates that the Go implementation faithfully reproduces the API design of the JavaScript reference implementation. The imperative construction of the type system remains consistent, aligning with the GraphQL Specification’s flexibility in schema definition styles while emphasizing programmatic control.
To assess whether both graphql-js and graphql-go yield the same runtime behavior, we executed equivalent GraphQL operations—Query, Mutation, and Subscription—against each implementation.
Below are the outputs returned by each library. Identical structures and values across both implementations demonstrate operational equivalence, reinforcing that the Go implementation faithfully replicates the behavior of the JavaScript reference.
graphql-js |
graphql-go |
|---|---|
| Identical query, mutation, and subscription outputs | Identical query, mutation, and subscription outputs |
Identical outputs were observed across both implementations.
{
"data": {
"ID": "d983b9d9-681c-4059-b5a3-5329d1c6f82d",
"boolean": true,
"enum": "SECOND_ENUM",
"float": 20.01,
"int": 20,
"node": {
"id": "user-1",
"name": "John Doe"
},
"object": {
"name": "Name of the object instance."
},
"objectList": [
{ "name": "First object in list" },
{ "name": "Second object in list" },
{ "name": "Third object in list" }
],
"objectWithArguments": {
"name": "Name of the object with arguments instance, id: 1"
},
"product": {
"id": "product-1",
"name": "GraphQL Book"
},
"productNonNull": {
"id": "product-non-null-1",
"name": "GraphQL Book Non-Null"
},
"searchResult": {
"id": "user-1",
"name": "John Doe"
},
"string": "str",
"stringList": [
"first string",
"second string",
"third string"
],
"user": {
"id": "user-1",
"name": "John Doe"
},
"userNonNull": {
"id": "user-non-null-1",
"name": "John Doe Non-Null"
}
}
}Identical outputs were observed across both implementations.
{
"data": {
"createProduct": {
"id": "product-1",
"name": "GraphQL Guide",
"price": 49.99
},
"createUser": {
"id": "user-1",
"name": "Alice"
},
"deleteProduct": "Product with id: product-2 deleted successfully",
"deleteUser": "User with id: user-2 deleted successfully",
"updateProduct": {
"id": "product-1",
"name": "GraphQL Guide Updated",
"price": 59.99
},
"updateUser": {
"id": "user-1",
"name": "Alice Updated"
}
}
}Both implementations emit the same payloads for real-time events.
{
"data": {
"productAdded": {
"id": "product-1",
"name": "New Product Added",
"price": 0
},
"userAdded": {
"id": "user-1",
"name": "New User Added"
}
}
}The exact match in structure and values for all GraphQL operations confirms the operational equivalence between the JavaScript and Go implementations. This not only validates the correctness of the graphql-go implementation but also supports its use as a reliable alternative to the reference library when building production-grade GraphQL APIs in Go.
To further validate the compatibility between graphql-js and graphql-go, we developed an open-source utility: graphql-go/compatibility-standard-definitions.
This library leverages the GraphQL specification’s built-in introspection system to programmatically extract and compare the internal type systems of both implementations. By querying each server's schema metadata (via __schema and __type fields), we can confirm that the registered type definitions—such as objects, interfaces, enums, unions, inputs, and scalars—match precisely between the two.
This approach allows us to automatically assert structural and semantic alignment between the JavaScript reference implementation and the Go alternative, even in deeply nested or polymorphic types.
This compatibility validation framework serves as conclusive evidence that graphql-go conforms to the same type system semantics as graphql-js. It answers one of the central research questions of this thesis:
“Is
graphql-gocompatible with the GraphQL type system as defined and implemented bygraphql-js?”
The answer, supported by introspection-based comparisons, is yes.
The research affirms that graphql-go implements and exposes a programmatic API that closely reproduces the structure, naming conventions, and behaviors of graphql-js. While not all internal names match, due to typical open-source divergence and idiomatic Go conventions, the key observable features do align.
In operational testing, identical outputs for execution and introspection validate the compatibility claim. The introspection-powered validation tool contributes novel proof of runtime schema fidelity, strengthening confidence in using graphql-go as a GraphQL implementation.
Footnotes
-
graphql-jsv0.6.0 BSD License: https://github.com/graphql/graphql-js/blob/v0.6.0/LICENSE ↩

