Cree una aplicación de punta a punta con LoopBack, Cloudant y React.js

En este tutorial descubrirá como crear una aplicación de punta a punta de React.js que funciona como un panel de instrumentos que muestra datos de ventas que se almacenan en una base de datos Cloudant. Vea cómo utilizar LoopBack 4 para exponer APIs de REST para conectarse a la base de datos de Cloudant de modo que el panel de instrumentos del frontend pueda llamar a las APIs.

Visión general

En este tutorial hay dos partes principales:

resumen del tutorial

  • Parte 1: Utilice LoopBack para crear las APIs que se conectan a Cloudant: Vea cómo se crea una aplicación de LoopBack lb4-sales-analytics que se conecta a una base de datos de Cloudant.
  • Parte 2: Cree la aplicación de React que hace llamadas a las APIs de REST que usted creó en la Parte 1: Descubra cómo se crea una aplicación de un panel de instrumentos, lb4-sales-react-app, con React.js.

Requisitos Previos

Para completar los pasos de este tutorial, es necesario:

Parte 1: Utilice LoopBack para crear las APIs que se conectan a Cloudant

En esta sección crearemos una aplicación de LoopBack que genera API que hablan con la base de datos de Cloudant.

visión general de la aplicación

Paso 1. Cree una aplicación de LoopBack 4

Genere una aplicación de LoopBack 4 llamada lb4-sales-analytics ejecutando el comando generador de aplicaciones: lb4 app.

$ lb4 app lb4-sales-analytics
? Project description: lb4-sales-analytics
? Project root directory: lb4-sales-analytics
? Application class name: Lb4SalesAnalyticsApplication
? Select features to enable in the project (Press <space> to select, <a> to toggle all, <i> to invert selectio
n)Enable tslint, Enable prettier, Enable mocha, Enable loopbackBuild, Enable vscode, Enable docker, Enable rep
ositories, Enable services
...
Application lb4-sales-analytics was created in lb4-sales-analytics.

Next steps:

$ cd lb4-sales-analytics
$ npm start

Consejo: Si usted va a usar todos los valores predeterminados, es posible acelerar el proceso de generación mediante la opción --yes; En este caso, quedaría así: lb4 app your-app-name --yes.

Paso 2. Cree el modelo de ventas

El modelo ´Sales´ representa cada pedido de ventas, que tendrá las siguientes propiedades:

  • id: el id del pedido de ventas
  • description: la descripción del pedido de ventas
  • date: la fecha en la que se hace el pedido de ventas
  • country: el país desde el que se hace el pedido de ventas
  • total: importe del pedido de ventas

Ejecute el comando lb4 model para generar el modelo.

$ lb4 model
? Model class name: Sales
? Please select the model base class Entity (A persisted model with an ID)
? Allow additional (free-form) properties? No
Let's add a property to Sales
Enter an empty property name when done

? Enter the property name: id
? Property type: number
? Is id the ID property? Sí
? Is it required?: No
? Default value [leave blank for none]:

Let's add another property to Sales
Enter an empty property name when done

? Enter the property name: description
? Property type: string
? Is it required?: No
? Default value [leave blank for none]:

Let's add another property to Sales
Enter an empty property name when done

? Enter the property name: date
? Property type: date
? Is it required?: Yes
? Default value [leave blank for none]:

Let's add another property to Sales
Enter an empty property name when done

? Enter the property name: country
? Property type: string
? Is it required?: Yes
? Default value [leave blank for none]:

Let's add another property to Sales
Enter an empty property name when done

? Enter the property name: total
? Property type: number
? Is it required?: Yes
? Default value [leave blank for none]:

Let's add another property to Sales
Enter an empty property name when done

? Enter the property name:
   create src/models/sales.model.ts
   update src/models/index.ts

Model Sales was created in src/models/

Paso 3. Añada un origen de datos

Ahora, vamos a crear un origen de datos que se conecta a una base de datos de Cloudant. Este ejemplo utilizar la imagen Couchdb de Docker, para que usted pueda ejecutar la base de datos localmente. El repositorio de conectores de LoopBack Cloudant contiene scripts de utilidades que sirven para descargar y ejecutar la imagen del Docker. Vea las instrucciones. También, es posible utilizar el servicio de Cloudant de IBM Cloud.

Ejecute el comando generador de orígenes de datos lb4 datasource para crear el origen de datos.

$ lb4 datasource
? Datasource name: cloudant
? Select the connector for cloudant: IBM Cloudant DB (supported by StrongLoop)
? Connection String url to override other settings (eg: https://username:password@host): http://admin:pass@localhost:8080/lb4-sales
? database:
? username:
? password: [hidden]
? Specify the model name to document mapping, defaults to `loopback__model__name`:
   create src/datasources/cloudant.datasource.json
   create src/datasources/cloudant.datasource.ts
...
Datasource cloudant was created in src/datasources/

Este origen de datos configura el conector LoopBack Cloudant. Si usted tiene el URL de la conexión, es posible ignorar el resto de los ajustes, como los de la base de datos, el nombre de usuario y la contraseña.

De forma predeterminada, las APIs de REST solo pueden devolver un máximo de 25 instancias. Para modificar eso, es posible añadir la propiedad globalLimit al cloudant.datasource.json de la siguiente manera:

{
  "name": "cloudant",
  "connector": "cloudant",
  "url": "http://admin:pass@localhost:8080",
  "database": "lb4-sales",
  "username": "",
  "password": "",
  "modelIndex": "",
  "globalLimit": 1000
}

Si tienes planes para desplegar la aplicación de LoopBack en IBM Cloud y para utilizar el servicio de Cloudant, vaya a la página Desplegar en documentos de IBM Cloud para vincular la aplicación al servicio, para que las credenciales del servicio de Cloudant no se expongan en la aplicación de LoopBack.

Paso 4. Cree un repositorio

El comando generador de repositorios lb4 repository crea una clase Repository que vincula el origen de datos y el modelo:

$ lb4 repository
? Please select the datasource CloudantDatasource
? Select the model(s) you want to generate a repository Sales
? Please select the repository base class DefaultCrudRepository (Legacy juggler bridge)
   create src/repositories/sales.repository.ts
   update src/repositories/index.ts

Repository SalesRepository was created in src/repositories/

Paso 5. Cree un controlador

Finalmente, cree el controlador que se encarga del ciclo de vida solicitud-respuesta de su API.

$ lb4 controller
? Controller class name: Sales
? What kind of controller would you like to generate? REST Controller with CRUD functions
? What is the name of the model to use with this CRUD repository? Ventas
? What is the name of your CRUD repository? SalesRepository
? What is the name of ID property? id
? What is the type of your ID? número
? What is the base HTTP path name of the CRUD operations? /sales
   create src/controllers/sales.controller.ts
   update src/controllers/index.ts

Controller Sales was created in src/controllers/

Además de las operaciones CRUD que se generaron, usted tiene que añadir dos puntos finales más:

  • GET /sales/analytics/{country}/{year}/{month}: Obtiene el número de ventas por país para el rango de fechas AAAA/MM
  • GET /sales/analytics/{country}/{year}: Número de ventas por país de un año

En src/controllers/sales.controller.ts, añada los siguientes dos métodos que corresponden a los puntos finales nuevos:

@get('/sales/analytics/{country}/{year}/{month}', {
    responses: {
      '200': {
        description: 'Number of sales by country in a date YYYY/MM range.',
        content: {'application/json': {schema: CountSchema}},
      },
    },
  })
  async analyticsMonthAndYear(
    @param.path.string('country') country: string,
    @param.path.number('year') year: number,
    @param.path.number('month') month: number,
  ): Promise<number> {
    const filter = {
      where: {
        country,
        date: {
          between: [
            new Date(year, month - 1).toISOString(),
            new Date(year, month).toISOString(),
          ] as [string, string],
        },
      },
    };

    const res = await this.salesRepository.find(filter);

    return res.length;
  }

  @get('/sales/analytics/{country}/{year}', {
    responses: {
      '200': {
        description: 'Number of sales by country for a year.',
        content: {'application/json': {schema: CountSchema}},
      },
    },
  })
  async analyticsYear(
    @param.path.string('country') country: string,
    @param.path.number('year') year: number,
  ): Promise<number> {
    const filter = {
      where: {
        country,
        date: {
          between: [
            new Date(year, 0).toISOString(),
            new Date(year + 1, 0).toISOString(),
          ] as [string, string],
        },
      },
    };

    const res = await this.salesRepository.find(filter);

    return res.length;
  }

Paso 6. Cambie el puerto al 3001

El puerto que se utiliza de forma predeterminada en la aplicación LoopBack es el 3000. Como la aplicación de React que usted va a crear utilizará el mismo puerto, es necesario modificar la aplicación LoopBack para que utilice el puerto 3001.

Vaya a index.js. En config cambie el número de puerto del 3000 al 3001, de esta manera:

const config = {
  rest: {
    port: +(process.env.PORT || 3001),
    host: process.env.HOST,
    openApiSpec: {
      // useful when used with OpenAPI-to-GraphQL to locate your application
      setServersFromRequest: true,
    },
  },
};

Pruebe su API

Ahora, su aplicación está lista para ejecutarse. Utilice npm start para lanzarla.

$ npm start

Server is running at http://[::1]:3001
Try http://[::1]:3001/ping

Abra un navegador y vaya al URL: http://localhost:3001

Página de destino de la aplicación LoopBack

La especificación de OpenAPI para las APIs de REST está en http://localhost:3001/openapi.json. Pruebe sus APIs en API Explorer: http://localhost:3001/explorer.

Es posible probarlo yendo a GET /sales/count o a cualquier punto final, y haciendo clic en el botón Try it out.

Pruebe el punto final

Opcional: Inicialice la base de datos

Para inicializar una base de datos, vamos a insertar algunos datos aleatorios cuando se inicia la aplicación. Podemos usar el soporte del ciclo de vida de LoopBack.

Ejecute el comando generador del observador el ciclo de vida: lb4 observer.

$ lb4 observer
? Observer name: AddData
? Observer group: AddDataGroup
   create src/observers/add-data.observer.ts
   update src/observers/index.ts
Observer AddData was created in src/observers/

En AddDataObserver, hay dos métodos generados: start() y stop(). Para añadir algunos datos durante el inicio de la aplicación, llame a Repository.create().

Primero, obtendremos el SalesRepository que creamos anteriormente.

Añada el constructor de la siguiente manera:

constructor(
  @repository('SalesRepository') private salesRepo: SalesRepository,
) {}

Asegúrese de que añade las siguientes importaciones:

//import the repository decorator
import {repository} from '@loopback/repository';

//import the Sales and SalesRepository in my LB app
import {SalesRepository} from '../repositories';
import {Sales} from '../models';

En el método start(), cree una instancia de Sales y añádala a la base de datos por medio del método Repository.create().

async start(): Promise<void> {
  let count: number = (await this.salesRepo.count()).count;
  if (count !== 0) return;

  //create an instance of Sales to be inserted into the database
  let salesData = new Sales({
    description: 'this is a sample data',
    date: '2019-01-01',
    country: 'Canada',
    total: 100,
  });
  this.salesRepo.create(salesData);
}

Lea esta publicación de blog para obtener más información acerca de la generación de instancias aleatorias de Sales.

Nota: El código para generar varias instancias se puede encontrar en src/observers/add-data.observer.ts.

Ahora que ha visto cómo se crean las APIs que extraen datos de Cloudant por medio de LoopBack, veamos cómo se crea en el panel de instrumentos donde se puede ver esta información.

Parte 2. Cree el panel de instrumentos con React.js

En esta sección, le mostramos los pasos para crear con React un panel de instrumentos que llama a las APIs de REST creadas por la aplicación LoopBack que usted creó en la Parte 1 para obtener los datos. Si usted es principiante en React, le convendría seguir este tutorial que cubre la forma en que usamos esta tecnología.

Después de construir todo, la aplicación se parecerá a esto:

Panel de instrumentos

En este panel de instrumentos hay tres componentes:

  1. Una barra de herramientas en la parte superior de la página
  2. Una sección de visión general que contiene cuadrículas con algunos puntos de datos
  3. Una sección de un gráfico de ventas que muestra el número de ventas realizadas durante los últimos meses para varios países

Paso 1: Cree una aplicación de React.js

Ejecute este comando:

$ npx create-react-app lb4-sales-react-app

Paso 2: Cree el panel de instrumentos

En la carpeta src, cree un archivo llamado Dashboard.js. Vea el código en src/Dashboard.jsen nuestra aplicación previamente creada.

Como es posible ver en el método render(), hay tres componentes principales:

  • Una barra de herramientas con el texto «LoopBack Dashboard»
  • Una sección de visión general con el componente CenteredGrid que crearemos
  • Una sección de ventas con el componente SimpleLineChart que crearemos

Paso 3: Cree CenteredGrid para la sección de visión general

Cree un archivo llamado CenteredGrid.js y vea su código en src/CenteredGrid.js, en nuestra aplicación previamente creada. Vamos a crear dos cuadrículas, una para el número total de ventas y otra para los ingresos totales por ventas. Se conectan a los dos puntos finales /sales/count y /sales que usted creó antes con LoopBack 4.

Como existen algunos valores que se usan de forma habitual en los tres componentes que estamos creando, cree un archivo llamado config.js con el siguiente contenido:

const baseUrl = 'http://localhost:3001';
const availableCountries = ['US', 'Canada', 'Germany', 'France', 'Mexico'];

export {baseUrl, availableCountries};

En CenteredGrid.js, inicialice el estado del componente en el constructor de la siguiente manera:

this.state = {
  totalNumberOfSales: 0,
  totalRevenueOfSales: 0,
};

Añada el método componentDidMount() del ciclo de vida, para que se realice una llamada a las APIs de REST cuando se represente el componente, y luego actualice su estado con los datos:

Compruebe los métodos del ciclo de vida de React.

async componentDidMount() {
  const [ totalNumberOfSales, totalRevenueOfSales ] = await Promise.all([
    fetch(`${baseUrl}/sales/count`).then(res => res.json()).catch(err => err),
    fetch(`${baseUrl}/sales`).then(res => res.json()).catch(err => err)
  ]);

  this.setState({
    totalNumberOfSales: totalNumberOfSales.count || 0,
    totalRevenueOfSales: Array.isArray(totalRevenueOfSales) ?
      totalRevenueOfSales.reduce((sum, curr) => sum + curr.total, 0) : 0,
  });
}

Finalmente, modificaremos la función render() de la siguiente manera:

render() {
  const { classes } = this.props;
  return (
    <div className={classes.root}>
    <Grid container spacing={24}>
      <Grid item xs={6}>
          <Paper className={classes.paper}>
          <h3>Total Number Of Sales</h3>
          { this.state.totalNumberOfSales }
          </Paper>
      </Grid>
      <Grid item xs={6}>
          <Paper className={classes.paper}>
          <h3>Total Revenue From Sales</h3>
          ${ this.state.totalRevenueOfSales }
          </Paper>
      </Grid>
    </Grid>
    </div>
  );
}

Paso 4: Cree SimpleLineChart para la sección ´Sales´

En esta sección nos hacen falta dos valores para construir el gráfico:

  1. Eje-x: dates (año, mes y la etiqueta del gráfico)
  2. Eje-y: el graphData de las ventas

Vamos a crear un archivo llamado SimpleLineChart.js, y vamos a inicializar el estado del componente en el constructor con las dos variables:

Observe que el periodo temporal del gráfico está determinado por la variable CALC_PERIOD_IN_MONTHS

constructor() {
  super();

  this.state = {
    graphData: [],
    dates: []
  };

  const MONTHS_IN_TEXT = ['JAN', 'FEB', 'MAR','APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'];
  const currentYear = new Date().getUTCFullYear();
  const currentMonth = new Date().getUTCMonth();

  for (let i = 0; i < CALC_PERIOD_IN_MONTHS; i++) {
    const date = new Date(currentYear, currentMonth - 12 + i, 1);

    this.state.dates[i] = {
      label: MONTHS_IN_TEXT[date.getUTCMonth()],
      year: date.getUTCFullYear(),
      month: date.getUTCMonth(),
    };
  }
}

Eche un vistazo a la función componentDidMount() para saber cómo se obtienen los datos de ventas por país.

Resumen

Este tutorial muestra el escenario de principio a fin para tener una aplicación frontend que habla con una base de datos por medio de una aplicación de LoopBack. En la Parte 1, creamos una aplicación de LoopBack que se conecta a una bases de datos de Cloudant para obtener los datos de las ventas. La aplicación de React que creamos en la Parte 2 para mostrar los datos en un panel de instrumentos utiliza las APIs de REST que se ¬¬exponen en esta aplicación de LoopBack.

Aviso

El contenido aquí presentado fue traducido de la página IBM Developer US. Puede revisar el contenido original en este link.