Cómo crear una aplicación de recetas con React, Prisma y GraphQL

Introducción

Índice
  1. Introducción
  • Prerrequisitos
  • Paso 1: Instalación de dependencias
  • Paso 2: Configuración de Prisma
  • Paso 3: Implementación de Prisma
  • Paso 4: configuración de la aplicación React
    1. Estructura de carpetas:
  • Paso 5: escribir el código
    1. Índice.js
    2. Obtener todas las recetas publicadas.js
    3. ObtenerRecetaSingle.js
    4. AgregarNuevaReceta.js
    5. ActualizarReceta.js
    6. Contenedor de recetas AllRecipes.js
    7. Creando una receta
    8. Editar una receta
    9. Eliminar una receta
  • Conclusión:
  • GraphQL ganó popularidad en términos de desarrollo front-end debido a las diversas ventajas que ofrece sobre las API REST. Sin embargo, configurar su propio servidor GraphQL es propenso a errores y complicado. Debido a esto, se han creado servicios administrados como Prisma para administrar su servidor GraphQL, lo que le permite concentrarse en el desarrollo de su aplicación.

    En este tutorial, crearemos una aplicación de recetas completamente funcional utilizando React y Prisma para administrar GraphQL.

    Prerrequisitos

    • Conocimientos intermedios de Javascript y React
    • Fundamentos de GraphQL
    • Fundamentos de Docker

    Paso 1: Instalación de dependencias

    Instale el cliente Prisma CLI globalmente ejecutando el siguiente comando:

    1. npm install -g prisma

    Usaremos create-react-app para iniciar nuestra aplicación React, así que ejecute el siguiente comando para instalarla globalmente:

    1. npm install -g create-react-app

    Para utilizar Prisma de forma local, debe tener Docker instalado en su máquina. Si aún no tiene Docker, puede descargar Docker Community Edition.

    Paso 2: Configuración de Prisma

    Para utilizar la CLI de Prisma, necesitará tener una cuenta de Prisma. Puede crear una cuenta en el sitio web de Prisma y luego iniciar sesión en la CLI de Prisma ejecutando el siguiente comando:

    1. prisma login

    Ahora que tenemos todas las dependencias necesarias, crea una carpeta para el proyecto y navega hacia la carpeta ejecutando los siguientes comandos:

    1. mkdir recipe-app-prisma-react
    2. cd recipe-app-prisma-react

    Luego inicialice su servidor Prisma en la carpeta:

    1. prisma init

    Aparecerá un mensaje con algunas opciones sobre el método que desea utilizar para configurar su servidor Prisma. Trabajaremos con el servidor localmente por ahora y luego lo implementaremos más tarde. Elija Create new databaseque Prisma cree una base de datos localmente con Docker.

    A continuación, se le solicitará que elija una base de datos. Para este tutorial, utilizaremos Postgres, así que elija PostgreSQL:

    A continuación, tenemos que elegir un lenguaje de programación para nuestro cliente prisma generado. Elija Prisma Javascript Client:

    Tendrás los siguientes archivos generados por Prisma en función de las opciones seleccionadas:

    Paso 3: Implementación de Prisma

    Ahora que tenemos configurado nuestro servidor Prisma, asegúrese de que Docker esté en ejecución. Luego, ejecute el siguiente comando para iniciar el servidor:

    1. docker-compose up -d

    Docker Compose se utiliza para ejecutar varios contenedores como un único servicio. El comando anterior iniciará nuestro servidor Prisma y la base de datos Postgres. Dirígete a 127.0.0.1:4466en tu navegador para ver el área de juegos de Prisma.

    Si desea detener su servidor, ejecute docker-compose stop.

    A continuación, abra su datamodel.prismaarchivo y reemplace el contenido de demostración con lo siguiente:

    type Recipe {  id: ID! @unique  createdAt: DateTime!  updatedAt: DateTime!  title: String! @unique  ingredients: String!  directions: String!  published: Boolean! @default(value: "false")}

    Luego ejecute el siguiente comando para implementar en un servidor de demostración:

    1. prisma deploy

    Recibirá una respuesta que muestra los modelos creados y su punto final Prisma de la siguiente manera:

    Para ver el servidor implementado, abra el panel de Prisma https://app.prisma.io/y navegue hasta Servicios. En el panel, verá lo siguiente:

    Para implementar en su servidor local, abra el prisma.ymlarchivo y cambie el punto final a http://localhost:4466, luego ejecuteprisma deploy

    Paso 4: configuración de la aplicación React

    Ahora que nuestro servidor Prisma está listo, podemos configurar nuestra aplicación React para consumir el punto final Prisma GraphQL.

    En la carpeta del proyecto, ejecute el siguiente comando para iniciar nuestra aplicación cliente usando create-react-app:

    1. create-react-app client

    Para trabajar con GraphQL, necesitamos algunas dependencias. Navegue hasta la carpeta del cliente y ejecute los siguientes comandos para instalarlas:

    1. cd client
    2. npm install apollo-boost react-apollo graphql-tag graphql --save

    Para la interfaz de usuario, utilizaremos Ant Design:

    1. npm install antd --save

    Estructura de carpetas:

    La estructura de carpetas de nuestra aplicación será la siguiente:

    src├── components│   ├── App.js│   ├── App.test.js│   ├── RecipeCard│   │   ├── RecipeCard.js│   │   └── index.js│   └── modals│       ├── AddRecipeModal.js│       └── ViewRecipeModal.js├── containers│   └── AllRecipesContainer│       ├── AllRecipesContainer.js│       └── index.js├── graphql│   ├── mutations│   │   ├── AddNewRecipe.js│   │   └── UpdateRecipe.js│   └── queries│       ├── GetAllPublishedRecipes.js│       └── GetSingleRecipe.js├── index.js├── serviceWorker.js└── styles    └── index.css

    Paso 5: escribir el código

    Índice.js

    Aquí realizaremos la configuración de Apollo. Este será el archivo de entrada principal para nuestra aplicación:

    import React from 'react';import ReactDOM from 'react-dom';import ApolloClient from 'apollo-boost';import { ApolloProvider } from 'react-apollo';import App from './components/App';// Pass your prisma endpoint to uriconst client = new ApolloClient({  uri: 'https://eu1.prisma.sh/XXXXXX'});ReactDOM.render(  ApolloProvider client={client}    App /  /ApolloProvider,  document.getElementById('root'));

    Obtener todas las recetas publicadas.js

    Consulta para obtener todas las recetas:

    import { gql } from 'apollo-boost';export default gql`query GetAllPublishedRecipes {    recipes(where: { published: true }) {      id      createdAt      title      ingredients      directions      published    }  }`;

    ObtenerRecetaSingle.js

    Consulta para obtener una receta por el ID de la receta:

    import { gql } from 'apollo-boost';export default gql`query GetSingleRecipe($recipeId: ID!) {    recipe(where: { id: $recipeId }) {      id      createdAt      title      directions      ingredients      published    }  }`;

    AgregarNuevaReceta.js

    La mutación para crear una nueva receta:

    import { gql } from 'apollo-boost';export default gql`mutation AddRecipe(    $directions: String!    $title: String!    $ingredients: String!    $published: Boolean  ) {    createRecipe(      data: {        directions: $directions        title: $title        ingredients: $ingredients        published: $published      }    ) {      id    }  }`;

    ActualizarReceta.js

    La mutación para actualizar una receta:

    import { gql } from 'apollo-boost';export default gql`mutation UpdateRecipe(    $id: ID!    $directions: String!    $title: String!    $ingredients: String!    $published: Boolean  ) {    updateRecipe(      where: { id: $id }      data: {        directions: $directions        title: $title        ingredients: $ingredients        published: $published      }    ) {      id    }  }`;

    Contenedor de recetas AllRecipes.js

    Aquí es donde CRUDse basa nuestra lógica para las operaciones. El archivo es bastante grande, por lo que hemos incluido solo las partes cruciales. Puedes ver el resto del código en GitHub.

    Para poder utilizar nuestras consultas y mutaciones, necesitamos importarlas y luego usar react-apollo'sgraphql que nos permite crear una higher-order componentque pueda ejecutar consultas y actualizar de forma reactiva en función de los datos que tenemos en nuestra aplicación.

    A continuación se muestra un ejemplo de cómo podemos obtener y mostrar todas las recetas publicadas:

    import React, { Component } from 'react';import { graphql } from 'react-apollo';import { Card, Col, Row, Empty, Spin } from 'antd';// queriesimport GetAllPublishedRecipes from '../../graphql/queries/GetAllPublishedRecipes';class AllRecipesContainer extends Component {  render() {    const { loading, recipes } = this.props.data;    return (      div        {loading ? (          div className="spin-container"            Spin /          /div        ) : recipes.length  0 ? (          Row gutter={16}            {recipes.map(recipe = (              Col span={6} key={recipe.id}                RecipeCard                  title={recipe.title}                  content={                    Fragment                      Card                        type="inner"                                               style={{ marginBottom: '15px' }}                                              {`${recipe.ingredients.substring(0, 50)}.....`}                      /Card                      Card type="inner"                        {`${recipe.directions.substring(0, 50)}.....`}                      /Card                    /Fragment                  }                  handleOnClick={this._handleOnClick}                  handleOnEdit={this._handleOnEdit}                  handleOnDelete={this._handleOnDelete}                  {...recipe}                /              /Col            ))}          /Row        ) : (          Empty /        )}      /div    );  }}graphql(GetAllPublishedRecipes)(AllRecipesContainer);

    La vista resultante se vería así:

    Nota: No se incluirá el estilo de los componentes debido al tamaño del archivo. El código está disponible en el repositorio de GitHub.

    Dado que necesitamos más de un potenciador en nuestro componente, usaremos compose para incorporar todos los potenciadores necesarios para el componente:

    import React, { Component } from 'react';import { graphql, compose, withApollo } from 'react-apollo';// queriesimport GetAllPublishedRecipes from '../../graphql/queries/GetAllPublishedRecipes';import GetSingleRecipe from '../../graphql/queries/GetSingleRecipe';// mutationsimport UpdateRecipe from '../../graphql/mutations/UpdateRecipe';import AddNewRecipe from '../../graphql/mutations/AddNewRecipe';// other importsclass GetAllPublishedRecipes extends Component {    // class logic}export default compose(  graphql(UpdateRecipe, { name: 'updateRecipeMutation' }),  graphql(AddNewRecipe, { name: 'addNewRecipeMutation' }),  graphql(GetAllPublishedRecipes))(withApollo(AllRecipesContainer));

    También necesitamos el withApollopotenciador, que proporciona acceso directo a su ApolloClientinstancia. Esto será útil, ya que necesitamos realizar consultas puntuales para obtener datos para una receta.

    Creando una receta

    Después de capturar los datos del siguiente formulario:

    Luego ejecutamos la siguiente handleSubmitdevolución de llamada, que ejecuta la addNewRecipeMutationmutación:

    class GetAllPublishedRecipes extends Component {  //other logic   _handleSubmit = event = {    this.props      .addNewRecipeMutation({        variables: {          directions,          title,          ingredients,          published        },        refetchQueries: [          {            query: GetAllPublishedRecipes          }        ]      })      .then(res = {        if (res.data.createRecipe.id) {          this.setState(            (prevState, nextProps) = ({              addModalOpen: false            }),            () =              this.setState(                (prevState, nextProps) = ({                  notification: {                    notificationOpen: true,                    type: 'success',                    message: `recipe ${title} added successfully`,                    title: 'Success'                  }                }),                () = this._handleResetState()              )          );        }      })      .catch(e = {        this.setState((prevState, nextProps) = ({          notification: {            ...prevState.notification,            notificationOpen: true,            type: 'error',            message: e.message,            title: 'Error Occured'          }        }));      });  };};

    Editar una receta

    Para editar una receta, reutilizamos el formulario que se utilizó para crear una nueva receta y luego pasamos los datos de la receta. Cuando un usuario hace clic en el ícono de edición, aparece el formulario con los datos precargados de la siguiente manera:

    Luego ejecutamos un handleSubmitcontrolador diferente para ejecutar la mutación de actualización de la siguiente manera:

    class GetAllPublishedRecipes extends Component {  // other logic  _updateRecipe = ({    id,    directions,    ingredients,    title,    published,    action  }) = {    this.props      .updateRecipeMutation({        variables: {          id,          directions,          title,          ingredients,          published: false        },        refetchQueries: [          {            query: GetAllPublishedRecipes          }        ]      })      .then(res = {        if (res.data.updateRecipe.id) {          this.setState(            (prevState, nextProps) = ({              isEditing: false            }),            () =              this.setState(                (prevState, nextProps) = ({                  notification: {                    notificationOpen: true,                    type: 'success',                    message: `recipe ${title} ${action} successfully`,                    title: 'Success'                  }                }),                () = this._handleResetState()              )          );        }      })      .catch(e = {        this.setState((prevState, nextProps) = ({          notification: {            ...prevState.notification,            notificationOpen: true,            type: 'error',            message: e.message,            title: 'Error Occured'          }        }));      });  };}

    Eliminar una receta

    En cuanto a la funcionalidad de eliminación, haremos lo mismo soft-deleteen la receta eliminada, lo que significa que cambiaremos el publishedatributo a falso ya que al obtener los artículos filtramos para asegurarnos de obtener solo publishedartículos.

    Utilizaremos la misma función que antes y pasaremos publicado como falso, como se muestra en el siguiente ejemplo:

    class GetAllPublishedRecipes extends Component {   // other logic    _handleOnDelete = ({ id, directions, ingredients, title }) = {    // user confirmed delete prompt     this._updateRecipe({      id,      directions,      ingredients,      title,      published: false, // soft delete the recipe      action: 'deleted'    });  };};

    Conclusión:

    En este tutorial, creaste una aplicación de recetas con React y GraphQL, usando Prisma para administrar tu servidor GraphQL. Prisma es un servicio confiable que te permite concentrarte en implementar tu lógica empresarial.

    Puedes acceder al código en GitHub.

    SUSCRÍBETE A NUESTRO BOLETÍN 
    No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

    Subir

    Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion