Presentamos la API basada en componentes

 

 

 

  • Register!
  • Designing For Complex UI Masterclass, with Vitaly Friedman

  • Índice
    1. Construyendo un sitio a través de componentes
    2. La especificación API basada en componentes
    3. Diferencias en la obtención de datos de API basadas en recursos, basadas en esquemas y basadas en componentes
    4. Propiedades particulares de una API basada en componentes
      1. Los datos que se recuperarán de la base de datos se pueden inferir de la jerarquía de componentes

    En el mundo de las API, GraphQL últimamente ha eclipsado a REST debido a su capacidad para consultar y recuperar todos los datos necesarios en una sola solicitud. En este artículo, describiré un tipo diferente de API, basado en componentes, que va un paso más allá en la cantidad de datos que puede recuperar de una sola solicitud.

     

    Este artículo se actualizó el 31 de enero de 2019 para responder a los comentarios de los lectores. El autor ha agregado capacidades de consulta personalizadas a la API basada en componentes y describe cómo funciona .

    Una API es el canal de comunicación para que una aplicación cargue datos desde el servidor. En el mundo de las API, REST ha sido la metodología más establecida, pero últimamente ha sido eclipsada por GraphQL , que ofrece importantes ventajas sobre REST . Mientras que REST requiere múltiples solicitudes HTTP para obtener un conjunto de datos para representar un componente, GraphQL puede consultar y recuperar dichos datos en una sola solicitud, y la respuesta será exactamente la que se requiere, sin obtener datos excesivos o insuficientes como suele ocurrir en DESCANSAR.

    En este artículo, describiré otra forma de recuperar datos que he diseñado y llamado "PoP" (y de código abierto aquí ), que amplía la idea de recuperar datos para varias entidades en una sola solicitud introducida por GraphQL y la lleva a un vaya más allá, es decir, mientras REST recupera los datos de un recurso y GraphQL recupera los datos de todos los recursos en un componente, la API basada en componentes puede recuperar los datos de todos los recursos de todos los componentes en una página.

    El uso de una API basada en componentes tiene más sentido cuando el sitio web se construye utilizando componentes, es decir, cuando la página web se compone iterativamente de componentes que envuelven otros componentes hasta que, en la parte superior, obtenemos un único componente que representa la página. Por ejemplo, la página web que se muestra en la imagen siguiente está construida con componentes delineados con cuadrados:

     

    La página es un componente que envuelve componentes que envuelve componentes, como lo muestran los cuadrados. ( Vista previa grande )

    Una API basada en componentes puede realizar una única solicitud al servidor solicitando los datos de todos los recursos de cada componente (así como de todos los componentes de la página), lo que se logra manteniendo las relaciones entre los componentes en la propia estructura de la API.

    Entre otros, esta estructura ofrece los siguientes beneficios:

    • Una página con muchos componentes activará sólo una solicitud en lugar de muchas;
    • Los datos compartidos entre componentes pueden recuperarse solo una vez de la base de datos e imprimirse solo una vez en la respuesta;
    • Puede reducir en gran medida (incluso eliminar por completo) la necesidad de un almacén de datos.

    Los exploraremos en detalle a lo largo del artículo, pero primero, exploremos qué son realmente los componentes y cómo podemos crear un sitio basado en dichos componentes y, finalmente, exploremos cómo funciona una API basada en componentes.

    Lectura recomendada : Introducción a GraphQL: por qué necesitamos un nuevo tipo de API

    Construyendo un sitio a través de componentes

    Un componente es simplemente un conjunto de piezas de código HTML, JavaScript y CSS juntas para crear una entidad autónoma. Esto luego puede envolver otros componentes para crear estructuras más complejas y también ser envuelto por otros componentes. Un componente tiene un propósito, que puede variar desde algo muy básico (como un enlace o un botón) hasta algo muy elaborado (como un carrusel o un cargador de imágenes de arrastrar y soltar). Los componentes son más útiles cuando son genéricos y permiten la personalización mediante propiedades inyectadas (o "accesorios"), de modo que puedan servir para una amplia gama de casos de uso. En el mejor de los casos, el propio sitio se convierte en un componente.

    El término "componente" se utiliza a menudo para referirse tanto a la funcionalidad como al diseño. Por ejemplo, en lo que respecta a la funcionalidad, los marcos de JavaScript como React o Vue permiten crear componentes del lado del cliente, que pueden autorenderizarse (por ejemplo, después de que la API recupera los datos requeridos) y usar accesorios para establecer valores de configuración en sus componentes empaquetados, lo que permite la reutilización del código. En cuanto al diseño, Bootstrap ha estandarizado cómo se ven y se sienten los sitios web a través de su biblioteca de componentes front-end, y se ha convertido en una tendencia saludable para los equipos crear sistemas de diseño para mantener sus sitios web, lo que permite a los diferentes miembros del equipo (diseñadores y desarrolladores, pero también (comercialistas y vendedores) hablen un lenguaje unificado y expresen una identidad consistente.

     

    Por lo tanto, crear componentes para un sitio es una forma muy sensata de hacer que el sitio web sea más fácil de mantener. Los sitios que utilizan marcos de JavaScript como React y Vue ya están basados ​​en componentes (al menos en el lado del cliente). El uso de una biblioteca de componentes como Bootstrap no necesariamente hace que el sitio esté basado en componentes (podría ser una gran masa de HTML), sin embargo, incorpora el concepto de elementos reutilizables para la interfaz de usuario.

    Si el sitio es una gran masa de HTML, para que podamos componerlo debemos dividir el diseño en una serie de patrones recurrentes, para lo cual debemos identificar y catalogar las secciones de la página en función de su similitud de funcionalidad y estilos, y dividirlas. secciones en capas, lo más granulares posible, intentando que cada capa se centre en un solo objetivo o acción, y también tratando de unir capas comunes en diferentes secciones.

    Nota : El “ Diseño atómico ” de Brad Frost es una excelente metodología para identificar estos patrones comunes y construir un sistema de diseño reutilizable.

    Brad Frost identifica cinco niveles distintos en el diseño atómico para la creación de sistemas de diseño. ( Vista previa grande )

    Por lo tanto, construir un sitio a través de componentes es similar a jugar con LEGO. Cada componente es una funcionalidad atómica, una composición de otros componentes o una combinación de ambos.

    Como se muestra a continuación, un componente básico (un avatar) se compone iterativamente de otros componentes hasta obtener la página web en la parte superior:

    La especificación API basada en componentes

    Para la API basada en componentes que he diseñado, un componente se llama "módulo", por lo que de ahora en adelante los términos "componente" y "módulo" se usan indistintamente.

    La relación de todos los módulos que se envuelven entre sí, desde el módulo superior hasta el último nivel, se denomina "jerarquía de componentes". Esta relación se puede expresar a través de una matriz asociativa (una matriz de clave = propiedad) en el lado del servidor, en la que cada módulo indica su nombre como atributo clave y sus módulos internos bajo la propiedad modules. Luego, la API simplemente codifica esta matriz como un objeto JSON para su consumo:

    // Component hierarchy on server-side, e.g. through PHP:[ "top-module" = [ "modules" = [ "module-level1" = [ "modules" = [ "module-level11" = [ "modules" = [...] ], "module-level12" = [ "modules" = [ "module-level121" = [ "modules" = [...] ] ] ] ] ], "module-level2" = [ "modules" = [ "module-level21" = [ "modules" = [...] ] ] ] ] ]]// Component hierarchy encoded as JSON:{ "top-module": { modules: { "module-level1": { modules: { "module-level11": { ... }, "module-level12": { modules: { "module-level121": { ... } } } } }, "module-level2": { modules: { "module-level21": { ... } } } } }}

    La relación entre módulos se define estrictamente de arriba hacia abajo: un módulo envuelve a otros módulos y sabe quiénes son, pero no sabe (y no le importa) qué módulos lo envuelven a él.

     

    Por ejemplo, en el código JSON anterior, el módulo module-level1sabe que envuelve módulos module-level11y module-level12y, transitivamente, también sabe que envuelve module-level121; pero al módulo module-level11no le importa quién lo está envolviendo y, en consecuencia, no lo sabe module-level1.

    Al tener la estructura basada en componentes, ahora podemos agregar la información real requerida por cada módulo, que se clasifica en configuraciones (como valores de configuración y otras propiedades) y datos (como los ID de los objetos de la base de datos consultados y otras propiedades). , y colocado en consecuencia bajo entradas modulesettingsy moduledata:

    { modulesettings: { "top-module": { configuration: {...}, ..., modules: { "module-level1": { configuration: {...}, ..., modules: { "module-level11": { repeat... }, "module-level12": { configuration: {...}, ..., modules: { "module-level121": { repeat... } } } } }, "module-level2": { configuration: {...}, ..., modules: { "module-level21": { repeat... } } } } } }, moduledata: { "top-module": { dbobjectids: [...], ..., modules: { "module-level1": { dbobjectids: [...], ..., modules: { "module-level11": { repeat... }, "module-level12": { dbobjectids: [...], ..., modules: { "module-level121": { repeat... } } } } }, "module-level2": { dbobjectids: [...], ..., modules: { "module-level21": { repeat... } } } } } }}

    A continuación, la API agregará los datos del objeto de la base de datos. Esta información no se coloca debajo de cada módulo, sino en una sección compartida llamada databases, para evitar duplicar información cuando dos o más módulos diferentes obtienen los mismos objetos de la base de datos.

    Además, la API representa los datos del objeto de la base de datos de manera relacional, para evitar duplicar información cuando dos o más objetos de la base de datos diferentes están relacionados con un objeto común (como dos publicaciones que tienen el mismo autor). En otras palabras, los datos del objeto de la base de datos están normalizados.

    Lectura recomendada : Creación de un formulario de contacto sin servidor para su sitio estático

    La estructura es un diccionario, organizado primero por cada tipo de objeto y luego por ID de objeto, del cual podemos obtener las propiedades del objeto:

     

    { databases: { primary: { dbobject_type: { dbobject_id: { property: ..., ... }, ... }, ... } }}

    Este objeto JSON ya es la respuesta de la API basada en componentes. Su formato es una especificación en sí mismo: siempre que el servidor devuelva la respuesta JSON en el formato requerido, el cliente puede consumir la API independientemente de cómo esté implementada. Por lo tanto, la API se puede implementar en cualquier idioma (lo cual es una de las ventajas de GraphQL: ser una especificación y no una implementación real le ha permitido estar disponible en una gran variedad de idiomas).

    Nota : En un próximo artículo, describiré mi implementación de la API basada en componentes en PHP (que es la que está disponible en el repositorio ).

    Ejemplo de respuesta API

    Por ejemplo, la respuesta API a continuación contiene una jerarquía de componentes con dos módulos, page= post-feed, donde el módulo post-feedrecupera publicaciones de blog. Tenga en cuenta lo siguiente:

    • Cada módulo sabe cuáles son sus objetos consultados desde la propiedad dbobjectids(ID 4y 9para las publicaciones del blog)
    • Cada módulo conoce el tipo de objeto para sus objetos consultados desde la propiedad dbkeys(los datos de cada publicación se encuentran en postsy los datos del autor de la publicación, correspondientes al autor con el ID proporcionado en la propiedad de la publicación author, se encuentran en users)
    • Debido a que los datos del objeto de la base de datos son relacionales, la propiedad authorcontiene el ID del objeto del autor en lugar de imprimir los datos del autor directamente.
    { moduledata: { "page": { modules: { "post-feed": { dbobjectids: [4, 9] } } } }, modulesettings: { "page": { modules: { "post-feed": { dbkeys: { id: "posts", author: "users" } } } } }, databases: { primary: { posts: { 4: { title: "Hello World!", author: 7 }, 9: { title: "Everything fine?", author: 7 } }, users: { 7: { name: "Leo" } } } }}

    Diferencias en la obtención de datos de API basadas en recursos, basadas en esquemas y basadas en componentes

    Veamos cómo se compara una API basada en componentes como PoP, al recuperar datos, con una API basada en recursos como REST y con una API basada en esquemas como GraphQL. Aprender a programar con ejemplos

    Digamos que IMDB tiene una página con dos componentes que necesitan obtener datos: "Director destacado" (que muestra una descripción de George Lucas y una lista de sus películas) y "Películas recomendadas para usted" (que muestra películas como Star Wars: Episodio I — La amenaza fantasma y Terminator ). Podría verse así:

    Componentes 'Director destacado' y 'Películas recomendadas para ti' para el sitio IMDB de próxima generación. ( Vista previa grande )

    Veamos cuántas solicitudes se necesitan para recuperar los datos a través de cada método API. Para este ejemplo, el componente "Director destacado" genera un resultado ("George Lucas"), del cual recupera dos películas ( Star Wars: Episodio I - La amenaza fantasma y Star Wars: Episodio II - El ataque de los clones ), y para cada película dos actores (“Ewan McGregor” y “Natalie Portman” para la primera película, y “Natalie Portman” y “Hayden Christensen” para la segunda película). El componente “Películas recomendadas para ti” trae dos resultados ( Star Wars: Episodio I — La amenaza fantasma y Terminator ) y luego busca a sus directores (“George Lucas” y “James Cameron” respectivamente).

     

    Al usar REST para representar el componente featured-director, es posible que necesitemos las siguientes 7 solicitudes (este número puede variar según la cantidad de datos proporcionados por cada punto final, es decir, cuánto exceso de recuperación se ha implementado):

    GET - /featured-directorGET - /directors/george-lucasGET - /films/the-phantom-menaceGET - /films/attack-of-the-clonesGET - /actors/ewan-mcgregorGET - /actors/natalie-portmanGET - /actors/hayden-christensen

    GraphQL permite, a través de esquemas fuertemente tipados, recuperar todos los datos requeridos en una sola solicitud por componente. La consulta para obtener datos a través de GraphQL para el componente featuredDirectorse ve así (después de haber implementado el esquema correspondiente ):

    query { featuredDirector { name country avatar films { title thumbnail actors { name avatar } } }}

    Y produce la siguiente respuesta:

    { data: { featuredDirector: { name: "George Lucas", country: "USA", avatar: "...", films: [ { title: "Star Wars: Episode I - The Phantom Menace", thumbnail: "...", actors: [ { name: "Ewan McGregor", avatar: "...", }, { name: "Natalie Portman", avatar: "...", } ] }, { title: "Star Wars: Episode II - Attack of the Clones", thumbnail: "...", actors: [ { name: "Natalie Portman", avatar: "...", }, { name: "Hayden Christensen", avatar: "...", } ] } ] } }}

    Y al consultar el componente "Películas recomendadas para usted" se produce la siguiente respuesta:

    { data: { films: [ { title: "Star Wars: Episode I - The Phantom Menace", thumbnail: "...", director: { name: "George Lucas", avatar: "...", } }, { title: "The Terminator", thumbnail: "...", director: { name: "James Cameron", avatar: "...", } } ] }}

    PoP emitirá solo una solicitud para recuperar todos los datos de todos los componentes de la página y normalizar los resultados. El punto final a llamar es simplemente el mismo que la URL para la cual necesitamos obtener los datos, solo agregando un parámetro adicional output=jsonpara indicar traer los datos en formato JSON en lugar de imprimirlos como HTML:

    GET - /url-of-the-page/?output=json

    Suponiendo que la estructura del módulo tiene un módulo superior llamado pageque contiene módulos featured-directory films-recommended-for-you, y estos también tienen submódulos, como este:

     

    "page" modules "featured-director" modules "director-films" modules "film-actors" "films-recommended-for-you" modules "film-director"

    La única respuesta JSON devuelta tendrá este aspecto:

    { modulesettings: { "page": { modules: { "featured-director": { dbkeys: { id: "people", }, modules: { "director-films": { dbkeys: { films: "films" }, modules: { "film-actors": { dbkeys: { actors: "people" }, } } } } }, "films-recommended-for-you": { dbkeys: { id: "films", }, modules: { "film-director": { dbkeys: { director: "people" }, } } } } } }, moduledata: { "page": { modules: { "featured-director": { dbobjectids: [1] }, "films-recommended-for-you": { dbobjectids: [1, 3] } } } }, databases: { primary: { people { 1: { name: "George Lucas", country: "USA", avatar: "..." films: [1, 2] }, 2: { name: "Ewan McGregor", avatar: "..." }, 3: { name: "Natalie Portman", avatar: "..." }, 4: { name: "Hayden Christensen", avatar: "..." }, 5: { name: "James Cameron", avatar: "..." }, }, films: { 1: { title: "Star Wars: Episode I - The Phantom Menace", actors: [2, 3], director: 1, thumbnail: "..." }, 2: { title: "Star Wars: Episode II - Attack of the Clones", actors: [3, 4], thumbnail: "..." }, 3: { title: "The Terminator", director: 5, thumbnail: "..." }, } } }}

    Analicemos cómo se comparan estos tres métodos entre sí, en términos de velocidad y cantidad de datos recuperados.

    Velocidad

    A través de REST, tener que recuperar 7 solicitudes solo para representar un componente puede ser muy lento, principalmente en conexiones de datos móviles y inestables. Por lo tanto, el salto de REST a GraphQL representa una gran cantidad de velocidad, porque podemos renderizar un componente con una sola solicitud.

    PoP, debido a que puede recuperar todos los datos de muchos componentes en una sola solicitud, será más rápido para procesar muchos componentes a la vez; sin embargo, lo más probable es que no sea necesario. Hacer que los componentes se representen en orden (como aparecen en la página) ya es una buena práctica, y para aquellos componentes que aparecen debajo de la página, ciertamente no hay prisa por renderizarlos. Por lo tanto, tanto las API basadas en esquemas como las basadas en componentes ya son bastante buenas y claramente superiores a una API basada en recursos.

    La cantidad de datos

    En cada solicitud, los datos de la respuesta GraphQL pueden duplicarse: la actriz "Natalie Portman" se busca dos veces en la respuesta del primer componente, y al considerar el resultado conjunto de los dos componentes, también podemos encontrar datos compartidos, como la película. Star Wars: Episodio I - La amenaza fantasma .

     

    PoP, por otro lado, normaliza los datos de la base de datos y los imprime solo una vez; sin embargo, conlleva la sobrecarga de imprimir la estructura del módulo. Por lo tanto, dependiendo de que la solicitud particular tenga datos duplicados o no, la API basada en esquema o la API basada en componentes tendrán un tamaño más pequeño.

    En conclusión, una API basada en esquemas como GraphQL y una API basada en componentes como PoP son igualmente buenas en cuanto a rendimiento y superiores a una API basada en recursos como REST.

    Lectura recomendada : Comprensión y uso de las API REST

    Propiedades particulares de una API basada en componentes

    Si una API basada en componentes no es necesariamente mejor en términos de rendimiento que una API basada en esquemas, quizás se pregunte: ¿qué intento lograr con este artículo?

    En esta sección, intentaré convencerlo de que una API de este tipo tiene un potencial increíble y proporciona varias características que son muy deseables, lo que la convierte en un serio competidor en el mundo de las API. A continuación describo y demuestro cada una de sus excelentes características únicas.

    Los datos que se recuperarán de la base de datos se pueden inferir de la jerarquía de componentes

    Cuando un módulo muestra una propiedad de un objeto de base de datos, es posible que el módulo no sepa, o no le importe, qué objeto es; lo único que le importa es 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 descendientes mostrarán ciertas propiedades del objeto, como titley content:

    Mientras que algunos módulos cargan el objeto de la base de datos, otros cargan propiedades. ( Vista previa grande )

    Por lo tanto, a lo largo de la jerarquía de componentes, los módulos de “carga de datos” estarán a cargo de cargar los objetos consultados (el módulo que carga la publicación única, en este caso), y sus módulos descendientes definirán qué propiedades del objeto de base de datos se requieren ( titley content, en este caso).

    Fetching all the required properties for the DB object can be done automatically by traversing the component hierarchy: starting from the dataloading module, we iterate all its descendant modules all the way down until reaching a new dataloading module, or until the end of the tree; at each level we obtain all required properties, and then merge all properties together and query them from the database, all of them only once.

    In the structure below, module single-post fetches the results from the DB (the post with ID 37), and submodules post-title and post-content define properties to be loaded for the queried DB object (title and content respectively); submodules post-layout and fetch-next-post-button do not require any data fields.

     

    "single-post" = Load objects with object type "post" and ID 37 modules "post-layout" modules "post-title" = Load property "title" "post-content" = Load property "content" "fetch-next-post-button"

    The query to be executed is calculated automatically from the component hierarchy and their required data fields, containing all the properties needed by all the modules and their submodules:

    SELECT title, content FROM posts WHERE id = 37

    By fetching the properties to retrieve directly from the modules, the query will be automatically updated whenever the component hierarchy changes. If, for instance, we then add submodule post-thumbnail, which requires data field thumbnail:

    "single-post" = Load objects with object type "post" and ID 37 modules "post-layout" modules "post-title" = Load property "title" "post-content" = Load property "content" "post-thumbnail" = Load property "thumbnail" "fetch-next-post-button"

    Then the query is automatically updated to fetch the additional property:

    SELECT title, content, thumbnail FROM posts WHERE id = 37

    Because we have established the database object data to be retrieved in a relational manner, we can also apply this strategy among the relationships between database objects themselves.

    Consider the image below: Starting from the object type post and moving down the component hierarchy, we will need to shift the DB object type to user and comment, corresponding to the post’s author and each of the post’s comments respectively, and then, for each comment, it must change the object type once again to user corresponding to the comment’s author.

    Moving from a database object to a relational object (possibly changing the object type, as in post = author going from post to user, or not, as in author = followers going from user to user) is what I call “switching domains”.

    Changing the DB object from one domain to another. (Large preview)

    After switching to a new domain, from that level at the component hierarchy downwards, all required properties will be subjected to the new domain:

    • name is fetched from the user object (representing the post’s author),
    • content is fetched from the comment object (representing each of the post’s comments),
    • name is fetched from the user object (representing the author of each comment).

    Traversing the component hierarchy, the API knows when it is switching to a new domain and, appropriately, update the query to fetch the relational object.

    For example, if we need to show data from the post’s author, stacking submodule post-author will change the domain at that level from post to the corresponding user, and from this level downwards the DB object loaded into the context passed to the module is the user. Then, submodules user-name and user-avatar under post-author will load properties name and avatar under the user object:

    "single-post" = Load objects with object type "post" and ID 37 modules "post-layout" modules "post-title" = Load property "title" "post-content" = Load property "content" "post-author" = Switch domain from "post" to "user", based on property "author" modules "user-layout" modules "user-name" = Load property "name" "user-avatar" = Load property "avatar" "fetch-next-post-button"

    Resulting in the following query:

    SELECT p.title, p.content, p.author, u.name, u.avatar FROM posts p INNER JOIN users u WHERE p.id = 37 AND p.author = 




    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Presentamos la API basada en componentes

    Presentamos la API basada en componentes

    Register! Designing For Complex UI Masterclass, with Vitaly Friedman Índice Construyendo un sitio a trav�

    programar

    es

    https://aprendeprogramando.es/static/images/programar-presentamos-la-api-basada-en-componentes-963-0.jpg

    2024-05-20

     

    Presentamos la API basada en componentes
    Presentamos la API basada en componentes

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20