GraphQL es un lenguaje de consulta para API, que brinda a los clientes el poder de preguntar exactamente qué datos necesitan y recibir exactamente, nada más o menos. De esta manera, una sola consulta ya puede hacerse cargo de todos los datos necesarios para reproducir un componente. (En comparación, una API REST debe desencadenar más ducha para tomar datos de más recursos de diferentes puntos finales, lo que puede volverse muy lento, especialmente en dispositivos móviles). Incluso si GraphQL (que significa “lenguaje la consulta del gráfico”) utiliza un gráfico Modelo de datos Para representar datos, el servidor GraphQL no necesariamente tiene que usar una estructura de datos para resolver la consulta, pero puede usar cualquier estructura de datos deseada. El gráfico es solo un modelo mental, no una implementación real.
Esto es compatible con el proyecto GraphQL declarando en su sitio web Graphql.org (mi énfasis): los gráficos son herramientas fuertes para modelar muchos fenómenos en el mundo real, porque se asemejan a nuestros modelos mentales naturales y las descripciones verbales del proceso básico. Con GraphQL, modela su negocio como un gráfico que define un esquema; Dentro de su esquema, defina diferentes tipos de nudos y la forma en que se conectan / se relacionan entre sí. En el cliente, esto crea un modelo similar a la programación orientada a objetos: tipos que se refieren a otros tipos. En el servidor, debido a que GraphQL solo define la interfaz, tiene la libertad de usarla con cualquier fondo (¡nuevo o antiguo!).
Esta es una buena noticia, porque tratar con gráficos o árboles (que son subconjuntos gráficos) no es trivial y puede conducir a una complejidad exponencial o logarítmica para resolver el interrogatorio (es decir, el tiempo para resolver un interrogación puede aumentar más. Muchos órdenes de tamaño para cada nueva entrada en la consulta). En este artículo, describiré el diseño arquitectónico del servidor GraphQL en PHP GraphQL por POP, que utiliza componentes como estructura de datos en lugar de gráficos. Este servidor debe su nombre POP, la biblioteca para construir componentes en el PHP. (Soy el autor de ambos proyectos). Este artículo se divide en 5 secciones, explicando:
¿Qué es un componente?
Cómo funciona el pop
¿Cómo son los componentes en POP?
Cómo los componentes son naturalmente adecuados para GraphQL
El rendimiento del uso de componentes para resolver una consulta GraphQL
Vamos a empezar. 1. ¿Cuál es un componente? La apariencia de cada página web se puede representar utilizando componentes. Un componente es simplemente un conjunto de piezas de código (como HTML, JavaScript y CSS) reunidas para crear una entidad autónoma, que puede envolver otros componentes para crear estructuras más complejas y se puede envolverse y otros componentes. Cada componente tiene un propósito, que puede variar desde algo muy básico, como un enlace o un botón, algo muy elaborado, como un carrusel o una carga de imagen.
La construcción de un sitio a través de componentes es similar al juego LEGO. Por ejemplo, en la página web de la imagen a continuación, los componentes simples (enlaces, botones, avatares) están compuestos para crear estructuras más complejas (widgets, secciones, barras laterales, menús) en la parte superior, hasta que cuando obtengamos la página web : La página es un componente que empaca componentes que empacan los componentes, como se muestra en los cuadrados, los componentes se pueden implementar tanto para el cliente (como las bibliotecas JS Vue y React, o las bibliotecas CSS Bootstrap y los componentes de material), así como para el servidor lado, en cualquier idioma.
2. Cómo Works POP describe una arquitectura basada en un modelo de componente en el lado del servidor y la implementa en el PHP a través de la biblioteca del modelo de componentes. En las secciones a continuación, los términos “componentes” y “módulo” se usan indistintamente. La jerarquía de los componentes La relación entre todos los módulos que se envuelven entre sí, desde el módulo anterior hasta el último nivel, se llama jerarquía de componentes. Esta relación puede expresarse mediante una matriz asociativa (una matriz clave => propy) en el lado del servidor, en el que cada módulo afirma su nombre como un atributo clave y sus módulos interiores bajo la propiedad “Módulos”.

Los datos en la matriz PHP se pueden usar directamente y en el cliente, codificados como un objeto JSON. La jerarquía de componentes se ve así:
$ componectierachy = [
‘módulo-nivel0’ => [
“módulos” => [
‘módulo-nivel1’ => [
“módulos” => [
‘módulo-nivel11’ => [
“Módulos” => […]
] ,,
‘módulo-nivel12’ => [
“módulos” => [
‘módulo-nivel121’ => [
“módulos” => […]]
]
]
]
] ,,
‘módulo-nivel2’ => [
“módulos” => [
‘módulo-nivel21’ => [
“Módulos” => […]
]
]
]
]
]
]
La relación entre los módulos se define de una manera estrictamente ascendente: un módulo envuelve otros módulos y sabe quiénes son, pero no sabe y no le importa, qué módulos lo cubren.
Por ejemplo, en la jerarquía de los componentes anteriores, el módulo ‘módulo-nivel1’ sabe que los módulos ‘módulo-nivel1’ y ‘módulo-nivel2’ y, transitivo, saben que envolver ‘módulo-nivel21’; Pero el módulo ‘módulo-nivel1’ no le importa quién lo empaca, por lo que no sabe ‘módulo-nivel1’. Con la estructura basada en componentes, agregamos la información real solicitada por cada módulo, que se clasifican en la configuración (como los valores de configuración y otras propiedades) y en los datos (como IDS de la base de datos de consultas y otras propiedades) y correctamente colocado en Modulesetts y entradas moduladas:
$ componecterarchyData = [
“Módulos” => [
‘módulo-nivel0’ => [
“Configuración” => […],
…
“módulos” => [
‘módulo-nivel1’ => [
“Configuración” => […],
…
“módulos” => [
‘módulo-nivel11’ => [
… Niños …
] ,,
‘módulo-nivel12’ => [
“Configuración” => […],
…
“módulos” => [
‘módulo-nivel121’ => [
… Niños …
]
]
]
]
] ,,
‘módulo-nivel2’ => [
“Configuración” => […],
…
“módulos” => [
‘módulo-nivel21’ => [
… Niños …
]
]
]
]
]
] ,,
“modulado” => [
‘módulo-nivel0’ => [
“Dbobjectids” => […], …,
“módulos” => [
‘módulo-nivel1’ => [
“Dbobjectids” => […],
…
“módulos” => [
‘módulo-nivel11’ => [
… Niños …
] ,,
‘módulo-nivel12’ => [
“Dbobjectids” => […],
…
“módulos” => [
‘módulo-nivel121’ => [
… Niños …
]
]
]
]
] ,,
‘módulo-nivel2’ => [
“Dbobjectids” => […],
…
“módulos” => [
‘módulo-nivel21’ => [
… Niños …
]
]
]
]
]
]
]
Luego, los datos del objeto de la base de datos se agregan a la jerarquía de componentes. Esta información no se coloca en cada módulo, sino en una sección compartida llamada bases de datos, para evitar duplicar la información cuando 2 o más módulos diferentes traen los mismos objetos de la base de datos.
Además, la biblioteca representa los datos del objeto de la base de datos de manera relacional, para evitar duplicar la información cuando 2 o más objetos diferentes de la base de datos están relacionados con un objeto común (como 2 publicaciones con el mismo autor). En otras palabras, los datos del objeto de la base de datos se normalizan. La estructura es un diccionario, organizado bajo cada tipo de objeto primero y la ID del segundo objeto, desde el cual podemos obtener las propiedades del objeto:
$ componecterarchyData = [
…
“Bases de datos” => [
“Dbobject_type” => [
“Dbobject_id” => [
“Propiedad” => …,
…
] ,,
…
] ,,
…
]
]
Por ejemplo, el siguiente objeto contiene una jerarquía de dos módulos, “Página” => “Post-Feed”, donde el módulo “Post-Feed” toma publicaciones de blog. Tenga en cuenta lo siguiente:
Cada módulo sabe cuáles son sus objetos interrogados en la propiedad de DBObjectids (IDS 4 y 9 para publicaciones de blog) Cada módulo conoce el tipo de objeto para sus objetos interrogados en la propiedad DBKEYS (los datos de cada publicación se pueden encontrar en “publicaciones”, y los datos El autor de la publicación, que corresponde al autor con la identificación dada bajo la propiedad de la publicación “Autor”, están a continuación “Usuarios”):
Debido a que los datos del objeto de la base de datos son relacionales, la propiedad “autor” contiene la identificación del autor en lugar de imprimir directamente los datos del autor
$ componecterarchyData = [
“modulado” => [
‘Página’ => [
“módulos” => [
‘post-feed’ => [
“Dbobjectids”: [4, 9]
]
]
]
] ,,
“Módulos” => [
‘Página’ => [
“módulos” => [
‘post-feed’ => [
“DBKEYS” => [
‘id’ => ‘publicaciones’,
‘Autor’ => ‘Usuarios’
]
]
]
]
] ,,
“Bases de datos” => [
‘Postes’ => [
4 => [
‘Título’ => “¡Hola mundo!”,
‘Autor’ => 7
] ,,
9 => [
‘Título’ => “¿Todo bien?”,
‘Autor’ => 7
]
] ,,
‘usuarios’ => [
7 => [
‘Nombre’ => ‘Leo’
]
]
]
]
Cargando datos Cuando un módulo muestra una propiedad desde un objeto de base de datos, el módulo puede no saber o preocuparse por qué es el objeto;Solo se preocupa por definir qué propiedades del objeto cargado son necesarias.Por ejemplo, considere la imagen a continuación: un módulo carga un objeto de la base de datos (en este caso, una sola publicación), y luego sus módulos descendentes mostrarán ciertas propiedades en el objeto, como “Título” y “Contenido”:
Mientras que algunos módulos cargan el objeto de la base de datos, otros cargan propiedades, por lo tanto, a lo largo de la jerarquía de componentes, los módulos de “DataLading” se cargarán con la carga de los objetos solicitados (el módulo que carga la publicación única, en este caso) y la baja Módulos Definirá qué propiedades del objeto DB son necesarias (“títulos” y “contenido”, en este caso). Se puede hacer cargo de todas las propiedades necesarias para el objeto DB se puede hacer atravesando la jerarquía de componentes: comenzando desde el módulo de carga de datos, explique todos sus módulos descendentes hasta que un nuevo módulo de carga de datos, o hasta el final del eje; En cada nivel, obtiene todas las propiedades necesarias, luego combina todas las propiedades y las interroga de la base de datos, todo una vez. Debido a que los datos del objeto de la base de datos se recuperan de manera relacional, podemos aplicar esta estrategia en las relaciones entre los objetos de la base de datos. Considere la imagen a continuación: a partir del tipo de objeto “Post” y transmitiendo la jerarquía de componentes, tendremos que mover el tipo de base de datos a “Usuario” y “Comentario”, correspondiente al perpetrador y cada uno de los comentarios los respectivos Publicar, luego, para cada comentario, tener que cambiar el tipo de objeto nuevamente al “usuario”
correspondiente al autor del comentario. La transición de una base de datos a un objeto relacional es lo que yo llamo “cambios en los dominios”. Después de cambiar a un nuevo dominio, desde ese nivel hasta la jerarquía de componentes hacia abajo, todas las propiedades necesarias estarán sujetas al nuevo dominio: la propiedad “Nombre” se toma del objeto “Usuario” que representa al autor de la publicación “, Contenido “del objeto” Comentario “que representa cada uno de los comentarios de la publicación, luego” Nombre “del objeto” Usuario “que representa al autor de cada comentario: Cambiar el objeto DB de un dominio a otro que pasa la jerarquía de los componentes , Pop sabe cuándo cambia el dominio y, adecuadamente, toma los datos del objeto relacional. 3. Cómo definir los componentes en POP Las propiedades del módulo (valores de configuración, qué datos básicos de tomarse, etc.) y los módulos descendentes se definen por objetos del proceso, en función del módulo, y el POP crea el Jerarquía de los componentes de todo el procesador que administra todos los módulos involucrados. Similar a una aplicación React (donde debemos indicar qué componente se representa en
), el modelo de componente POP debe tener un módulo de entrada. A partir de esto, POP pasará por todos los módulos en la jerarquía de componentes, se hará cargo de las propiedades para cada uno de los procesadores correspondientes y creará la matriz asociativa vestida con todas las propiedades para todos los módulos. Cuando un componente define un componente hacia abajo, se refiere a una matriz de 2 partes:
Clase PHP
El nombre del componente
Esto sucede porque los componentes generalmente comparten propiedades. Por ejemplo, los componentes post_thumbnail_large y post_thumbnail_small compartirán la mayoría de las propiedades, excepto el tamaño de miniatura. Luego, es lógico agrupar todos los componentes similares en la misma clase PHP y usar instrucciones de conmutación para identificar el módulo solicitado y devolver la propiedad apropiada. Un módulo de procesador para los componentes del widget posterior que deben colocarse en diferentes páginas se muestran de la siguiente manera: Class PostwidgetModulesor extiende AbstractModuleProcessor {

Const post_widget_homepage = ‘post-widget-homepage’;
Const post_widget_autothorPage = ‘post-widget-authorpage’;

Function getSubModulEtoProcess () {
devolver [
self :: post_widget_homepage,
Self :: post_widget_autothorPage,
];
}
Función getSubModules ($ módulos): matriz
{
$ ret = [];
Switch ($ módulo [1]) {
Case self :: post_widget_homepage:
Case self :: post_widget_autthOrpage:
$ ret [] = [
UserLayoutModuleProcessor :: Clase,
UserLayoutModuleProcessor :: Post_thumb
];
$ ret [] = [
UserLayoutModuleProcessor :: Clase,
UserLayoutModuleProcessor :: post_title
];
descanso;
}
Switch ($ módulo [1]) {
Case self :: post_widget_homepage:
$ ret [] = [
UserLayoutModuleProcessor :: Clase,
UserLayoutModuleProcessor :: post_date
];
descanso;
}
devolver $ ret;
}
Función getMmutableConfiguration ($ módulo y $ accesorios)
{
$ ret = [];
Switch ($ módulo [1]) {
Case self :: post_widget_homepage:
$ Ret [‘Descripción’] = __ (‘Última publicación’, ‘My-Domain’);
$ Ret [‘Showmore’] = $ this-> getProp ($ módulo, $ props, ‘showmore’);
$ ret [‘class’] = $ this-> getProp ($ módulo, $ props, ‘class’);
descanso;
Case self :: post_widget_autthOrpage:
$ Ret [‘Descripción’] = __ (‘Últimas publicaciones por el autor’, ‘My-Domain’); $ Ret [‘Showmore’] = False;
$ ret [‘class’] = ‘Text-Center’;
descanso;
}
devolver $ ret;
}
Función initModelProps ($ módulo y $ accesorios)
{
Switch ($ módulo [1]) {
Case self :: post_widget_homepage:
$ this-> setProp ($ módulo, $ props, ‘showmore’, falso);
$ this-> appendprop ($ módulo, $ props, ‘class’, ‘text-center’);
descanso;
}
Parent :: initModelProps ($ módulo, $ accesorios);
}
// …
}
La creación de los componentes reutilizables se logra mediante la elaboración de las clases del módulo del modulador abstracto que definen las funciones sustituyentes que deben implementarse por una cierta clase de la corte:
Clase abstracta PostwidgetLayAbstractectModulessor extiende AbstractModuleProcessor
{
Función getSubModules ($ módulos): matriz
{
$ ret = [
$ this-> getContentModule ($ módulo),
];
if ($ thumbnail_module = $ this-> getThumbnailModule ($ módulo))

{
$ ret [] = $ thumbnail_module;
}
If ($ AfterContant_Modules = $ this-> getaFterContentModules ($ módulos)))
{
$ ret = array_merge (
$ retin,
$ AphterContant_Modules
);
}
devolver $ ret;
}
Función abstracta de la función getContentModule ($ módulos): matriz;
Función protegida getThumbnailModule ($ módulos) 😕 matriz
{
// Valor predeterminado (Overidable)
return [self :: class, self :: thumbnail_layout];
}
Función protegida getaFterContentModules ($ módulos): matriz
{
devolver [];
}
Función getMmutableConfiguration ($ módulos y $ accesorios): matriz
{
devolver [
‘Descripción’ => $ this-> getDecription (),
];
}
Función protegida getDecription ($ módulo): cadena
{
devolver ”;
}
}
ModuleProcessor Custom ModuleProcessor puede extender la clase abstracta y definir sus propias propiedades:
Clase PostLayoutModulessor extiende AbstractLayoutModuuleProcessor {const post_content = ‘post-Contentnt’
consistir post_excerpt = ‘post-except’
Const post_thumbnail_large = ‘post-thumbnail-large’
Const post_thumbnail_medium = ‘post-pulgada-medio’
consistir post_share = ‘post-cuidado’
Function getSubModulEtoProcess () {
devolver [
Self :: post_content,
Self :: post_excerpt,
self :: post_thumbnail_large,
self :: post_thumbnail_medium,
Self :: post_share,
];
}
}
Clase PostwidgetLayoutModulesor extiende AbstractWidgetLayoutModulArsor
{
Función protegida getContentModule ($ módulos) 😕 Array
{
Switch ($ módulos [1])
{
Case self :: post_widget_homepage_large:
devolver [
PostLayoutModuleProcessor :: Clase,
PostLayoutModuleProcessor :: post_content
];
Case self :: post_widget_homepage_medium:
Case self :: post_widget_homepage_small:
devolver [
PostLayoutModuleProcessor :: Clase,
PostLayoutModuleProcessor :: post_excerpt
];
}
Return parent :: getContentModule ($ módulos);
}
Función protegida getThumbnailModule ($ módulos) 😕 matriz
{
Switch ($ módulos [1])
{
Case self :: post_widget_homepage_large:
devolver [
PostLayoutModuleProcessor :: Clase,
PostLayoutModuleProcessor :: Post_Thumbnail_Large
];
Case self :: post_widget_homepage_medium:
devolver [
PostLayoutModuleProcessor :: Clase,
PostLayoutModuleProcessor :: Post_Thumbnail_Medium
];
}
Return parent :: getThumbnailModule ($ módulos);
}
Función protegida getaFterContentModules ($ módulos): matriz
{
$ ret = [];
Switch ($ módulos [1])
{
Case self :: post_widget_homepage_large:
$ ret [] = [
PostLayoutModuleProcessor :: Clase,
PostLayoutModuleProcessor :: Post_share
];
Romper
}
devolver $ ret;
}
Función protegida getDecription ($ módulo): cadena
{
Return __ (‘estas tienen mis publicaciones de blog’, ‘mi dominio’);}
}
4. Como los componentes son naturalmente adecuados para GraphQL, el modelo de componentes puede asignar naturalmente un interrogatorio en forma de árbol, lo que lo convierte en una arquitectura ideal para implementar un servidor GraphQL. GraphQL by POP ha implementado las clases de modulación necesarias para convertir una consulta GraphQL en la jerarquía de componentes correspondientes y resolverla utilizando el motor POP Datalading. Es por eso y cómo funciona esta solución. La asignación de los componentes del cliente en GraphQL Consuly consultas se puede representar utilizando la jerarquía de componentes POP, en el que cada tipo de objeto representa un componente y cada campo de relación de un tipo a otro tipo de objeto representa un componente que envuelve otro componente. Veamos cuál es el caso usando un ejemplo. Supongamos que queremos construir el próximo widget “Director destacado”:
Widget of Director presentado con Vue o React (o cualquier otra biblioteca basada en componentes), primero identificamos los componentes. En este caso, tendríamos un componente externo (en rojo), que envuelve un componente (en azul), que en sí mismo envuelve un (en verde):
Identificar los componentes en el código de pseudo de widget se ve así:
<!-Componente: ->
País: {país}
{Foreach Films como película}
{/para cada}
<!-componente: ->


Título: {Título}
Pic: {Miniatura}
{Actores de Foreach como actor}
{/para cada}
<!-componente: ->
Nombre nombre}
Foto: {Avatar}
Luego identificamos qué datos se necesitan para cada componente.Para Necesitamos nombre, avatar y país.Para necesitamos miniatura y título.Y para necesitamos nombre y avatar:
Identifique las propiedades de datos para cada componente y creamos nuestra consulta GraphQL para tomar los datos necesarios:
consulta {
Director destacado {
Nombre
País
Avatares
Película (s {
Título
Miniatura
actores {
Nombre

Avatares
}
}
}
}
Como se puede apreciar, existe una relación directa entre la forma de una jerarquía de componentes y una consulta GraphQL. De hecho, una consulta GraphQL puede incluso considerarse la representación de una jerarquía de componentes. Resolver la consulta GraphQL utilizando los componentes del servidor porque una consulta GraphQL tiene la misma forma que una jerarquía de componentes, transforma la interrogación en la jerarquía de componentes equivalentes, lo resuelve utilizando su enfoque para tomar datos para los componentes y, en última instancia, recrea la forma de consulta para enviar la consulta para enviar la consulta. Datos en respuesta. Veamos cómo funciona esto. Para procesar los datos, POP convierte los tipos de GraphQL en componentes: => Director, , => actor y, utilizando el orden en que aparecen en la consulta, POP crea una jerarquía virtual de componentes con Los mismos elementos: director de componentes raíz, que envuelve el componente de la película, que envuelve el componente del actor. De ahora en adelante, hablar sobre tipos GraphQL o componentes POP no hace ninguna diferencia. Para cargar sus datos, POP los trata en las “iteraciones”, tomando los datos del objeto para cada tipo en su propia iteración, de la siguiente manera: tratar los tipos de iteración El motor de carga de datos POP implementa el siguiente pseudoalgoritmo Para cargar los datos: Preparación:
Tiene una cola vacía para almacenar la lista de ID de los objetos que se tomarán de la base de datos, organizada por tipo (cada entrada será: [type => lista de IDS])
Recupere la ID del objeto Director presentado y colóquelo en la cola bajo el tipo de directorio
Bucles hasta que no haya entradas en la cola:
Obtenga la primera entrada de la cola: el tipo y la lista de IDS (por ejemplo: Director y [2]) y elimine esta entrada de la cola una consulta única contra la base de datos para tomar todos los objetos para ese tipo con esos IDS
Si el tipo tiene campos relacionales (por ejemplo: el director tiene campos de campo de tipo cinematográfico), luego recopile todas las ID en estos campos en todos los objetos recuperados en la iteración actual (por ejemplo: todas las ID en el campo de los archivos de todos los tipos de director de objetos) y coloque estas ID en la cola bajo el tipo apropiado (por ejemplo: IDS [3, 8] bajo el tipo de película).
Al final de las iteraciones cargaremos todos los datos de objetos para todos los tipos, como:
Tratando los tipos en las iteraciones, consulte cómo se recopilan todas las ID para un chico, hasta que el tipo se procese en la cola. Si, por ejemplo, agregamos una preferencia de campo relacional al tipo de directorio, estas ID se agregarían a la cola bajo el tipo de actor y se procesarían con los ID de tipo de campo de actores:
Sin embargo, tratar los tipos de iteraciones, si un tipo ha sido procesado y luego tenemos que cargar más datos de ese tipo, entonces es una nueva iteración en ese tipo. Por ejemplo, agregar un campo relacional de preferencia al tipo de autor, hará que el tipo se agregue nuevamente a la cola:
Al organizar un tipo repetido, preste atención, también que aquí podemos usar un mecanismo de caché: en la segunda iteración para el tipo de directorio, el objeto con ID 2 no se recupera nuevamente, porque ya se ha recuperado en la primera iteración, para que lo hará se puede tomar del caché. Ahora que hemos asumido todos los datos del objeto, debemos modelarlos en la respuesta esperada, reflejando el interrogatorio de GraphQL. Como lo es hoy, los datos se organizan como en una base de datos relacional: tabla para el tipo de director: Id Nombre de país Avatar películas
Table para el tipo de película:
tabla para el tipo de actor:
| 4 | ewan mcgregor | McGregor.jpg | 6 | Nathalie Portman | portman.jpg |
| 7 | Hayden Christensen | Christensen.jpg |
En esta etapa, Pop tiene todos los datos organizados en forma de tablas y muestra la forma Cada tipo se relaciona entre sí (por ejemplo, referencias de director de cine a través de películas de tierra, me refiero Película de actores a través de Actors Land). Luego, al hablar la jerarquía de los componentes en la raíz, navegar en las relaciones y recuperar los objetos apropiados en las tablas relacionales, POP producirá la forma del eje de la consulta GraphQL:
Respuesta en forma de árbol Finalmente, la impresión de datos en la salida produce la respuesta con la misma forma de pregunta GraphQL: {
Fecha: {

SenseDirector: {
Nombre: “George Lucas”,
País: “Puerta”,
Avatar: “George-Lucas.jpg”,
Película (s: [
{
Título: “Star Wars: Episodio I”,
Miniatura: “Episodio-1.jpg”,

Actores: [

{

Nombre: “Ewan McGregor”,

Avatar: “McGregor.jpg”,
},
{
Nombre: “Natalie Portman”,
Avatar: “Portman.jpg”,
}
]
},
{
Título: “Star Wars: Episodio II”,
Miniatura: “Episodio-2.jpg”,
Actores: [
{
Nombre: “Natalie Portman”,
Avatar: “Portman.jpg”,
},
{
Nombre: “Hayden Christensen”,
Avatar: “Christensen.jpg”,
}
]
}
]
}
}
}
Tags Implementación de un servidor GraphQL con componentes PHP
homefinance blog