A mi papá le gusta recordarme que, como ingeniero informático en la década de 1970, " era programador antes de que la programación estuviera de moda ". Incluso mostró viejos guiones de Fortran y COBOL un par de veces. Después de leer este código, puedo decir con seguridad que la programación es definitivamente mejor hoy .
Un sello distintivo de los lenguajes de programación y entornos de desarrollo modernos es cuánto menos código tiene que escribir un desarrollador. Mediante el uso de lenguajes de alto nivel junto con las muchas API disponibles, paquetes de código abierto y servicios de pago, las aplicaciones, incluso aquellas con requisitos complejos, se pueden construir con bastante rapidez.
Una comparación para demostrar la evolución del desarrollo de software es la construcción. Érase una vez, la construcción de cualquier casa comenzó con la tala de árboles en su sitio. Sin embargo, los materiales, herramientas y métodos aparecieron rápidamente para que la construcción se completara más rápido, los objetos se volvieran más fuertes y los trabajadores se liberaran de algunas tareas elementales.
¿Cuántos rascacielos se construirían si los constructores extraen su propio acero?
Los desarrolladores de software, que continúan trabajando hasta el día de hoy, en los albores de sus carreras "cortan sus propios árboles". Al mismo tiempo, las innovaciones sin precedentes de la última década han llevado al hecho de que la industria del software comenzó a desarrollarse de manera muy similar a la construcción.
En pocas palabras, los desarrolladores modernos ahora tienen las herramientas, técnicas y mejores prácticas para completar proyectos más rápido, obtener aplicaciones estables y ahorrar a los desarrolladores tareas de bajo nivel.
Cómo hacer una aplicación de chat
Creemos rápidamente algo que solía llevar días o semanas. Crearemos una aplicación de sala de chat pública que utiliza WebSockets para mensajería en tiempo real.
WebSockets es compatible de forma nativa con todos los navegadores modernos. Sin embargo, nuestro objetivo es descubrir qué herramientas podemos utilizar en el trabajo, no reinventarlas . Teniendo esto en cuenta, utilizaremos las siguientes tecnologías:
El proyecto de inicio y el archivo README completo se pueden encontrar en este repositorio de GitHub . Si solo desea ver la aplicación terminada, eche un vistazo a la rama de la sala de chat pública.
Además, el video a continuación (en inglés) explica cada paso con más detalle.
Empecemos.
Siete pasos para crear una aplicación de chat:
1. Configuración del proyecto
Clona el proyecto de inicio y ve al directorio de chat grupal. Puedes decidir por ti mismo si usar yarn o npm para instalar las dependencias del proyecto. En cualquier caso, necesitamos todos los paquetes NPM especificados en el archivo package.json.
#
git clone https://github.com/8base/Chat-application-using-GraphQL-Subscriptions-and-Vue.git group-chat
#
cd group-chat
#
yarn
Para interactuar con la API GraphQL, necesitamos configurar tres variables de entorno. Cree un archivo .env.local en el directorio raíz con el siguiente comando, y la aplicación Vue, después de la inicialización, establecerá automáticamente las variables de entorno que agregamos a este archivo. Ambos valores y no deben cambiarse. Solo necesita establecer el valor . Si tiene un espacio de trabajo de 8base que desea usar para crear una aplicación de chat usando nuestro tutorial, actualice el archivo .env.local con su ID de espacio de trabajo. De lo contrario, obtenga el ID del espacio de trabajo siguiendo los pasos 1 y 2 de la guía de inicio rápido de 8base .
echo 'VUE_APP_8BASE_WORKSPACE_ID=<YOUR_8BASE_WORKSPACE_ID>
VUE_APP_8BASE_API_ENDPOINT=https://api.8base.com
VUE_APP_8BASE_WS_ENDPOINT=wss://ws.8base.com' \
> .env.local
VUE_APP_8BASE_API_ENDPOINT
VUE_APP_8BASE_WS_ENDPOINT
VUE_APP_8BASE_WORKSPACE_ID
2. Importar esquema
Ahora tenemos que preparar el lado del servidor. En la raíz de este repositorio, debería encontrar el archivo
chat-schema.json
. Para importarlo al espacio de trabajo, solo necesita instalar la línea de comando 8base e iniciar sesión, y luego importar el archivo de esquema.
# 8base CLI
yarn global add 8base-cli
# CLI
8base login
#
8base import -f chat-schema.json -w <YOUR_8BASE_WORKSPACE_ID>
3. Acceso a API
La última tarea del backend es permitir el acceso público a la API GraphQL.
En la consola 8base, vaya a
App Services > Roles > Guest
. Actualice los permisos establecidos para publicaciones y usuarios para que estén marcados o configurados como Todos los registros (como se muestra en la captura de pantalla a continuación).
La función Invitado determina qué puede hacer el usuario que realiza una solicitud de API no autenticada.
Editor de roles en la consola 8base.
4. Escribir consultas GraphQL
En este paso, vamos a definir y escribir todas las consultas GraphQL que necesitaremos para nuestro componente de chat. Esto nos ayudará a comprender qué datos leeremos, crearemos y escucharemos (a través de WebSockets) utilizando la API.
El siguiente código debe colocarse en un archivo
src / utils / graphql.js
. Lea los comentarios sobre cada constante exportada para comprender qué hace cada consulta.
/* gql graphQL */
import gql from "graphql-tag";
/* 1. - 10 */
export const InitialChatData = gql`
{
usersList {
items {
id
email
}
}
messagesList(last: 10) {
items {
content
createdAt
author {
id
email
}
}
}
}
`;
/* 2. */
export const CreateUser = gql`
mutation($email: String!) {
userCreate(data: { email: $email, roles: { connect: { name: "Guest" } } }) {
id
}
}
`;
/* 3. */
export const DeleteUser = gql`
mutation($id: ID!) {
userDelete(data: { id: $id, force: true }) {
success
}
}
`;
/* 4. */
export const UsersSubscription = gql`
subscription {
Users(filter: { mutation_in: [create, delete] }) {
mutation
node {
id
email
}
}
}
`;
/* 5. */
export const CreateMessage = gql`
mutation($id: ID!, $content: String!) {
messageCreate(
data: { content: $content, author: { connect: { id: $id } } }
) {
id
}
}
`;
/* 6. . */
export const MessagesSubscription = gql`
subscription {
Messages(filter: { mutation_in: create }) {
node {
content
createdAt
author {
id
email
}
}
}
}
`;
5. Configuración del cliente Apollo para suscripciones
Con nuestras consultas GraphQL escritas, es hora de configurar nuestros módulos API.
Primero, abordemos el cliente API
ApolloClient
con sus valores predeterminados requeridos. Para createHttpLink
nosotros, proporcionamos nuestro punto final de espacio de trabajo completamente formado. Este código está en src/utils/api.js
.
import { ApolloClient } from "apollo-boost";
import { createHttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";
const { VUE_APP_8BASE_API_ENDPOINT, VUE_APP_8BASE_WORKSPACE_ID } = process.env;
export default new ApolloClient({
link: createHttpLink({
uri: `${VUE_APP_8BASE_API_ENDPOINT}/${VUE_APP_8BASE_WORKSPACE_ID}`,
}),
cache: new InMemoryCache(),
});
// Note: , // ApolloClient, .
Luego trataremos con el cliente de suscripción usando
subscriptions-transport-ws
y isomorphic-ws
. Este código es un poco más largo que el anterior, por lo que vale la pena tomarse el tiempo para leer los comentarios en el código.
Inicializamos
SubscriptionClient
usando nuestro punto final de WebSockets y workspaceId
en parámetros connectionParams
. Luego usamos este subscriptionClient
en dos métodos definidos en la exportación predeterminada: subscribe()
y close()
.
subscribe
nos permite crear nuevas suscripciones con datos y devoluciones de llamada de error. El método de cierre es el que podemos usar para cerrar la conexión cuando salimos del chat.
import WebSocket from "isomorphic-ws";
import { SubscriptionClient } from "subscriptions-transport-ws";
const { VUE_APP_8BASE_WS_ENDPOINT, VUE_APP_8BASE_WORKSPACE_ID } = process.env;
/**
* ,
* .
*/
const subscriptionClient = new SubscriptionClient(
VUE_APP_8BASE_WS_ENDPOINT,
{
reconnect: true,
connectionParams: {
/**
* Workspace ID ,
* Websocket
*
*/
workspaceId: VUE_APP_8BASE_WORKSPACE_ID,
},
},
/**
* WebSocket, W3C. * , *WebSocket (, NodeJS)
*/
WebSocket
);
export default {
/**
* , *'data’ 'error’
*/
subscribe: (query, options) => {
const { variables, data, error } = options;
/**
* .
*/
const result = subscriptionClient.request({
query,
variables,
});
/**
* * , ,
* subscriptionClient
*/
const { unsubscribe } = result.subscribe({
/**
*
* , .
*/
next(result) {
if (typeof data === "function") {
data(result);
}
},
/**
* , .
*/
error(e) {
if (typeof error === "function") {
error(e);
}
},
});
return unsubscribe;
},
/**
* subscriptionClient .
*/
close: () => {
subscriptionClient.close();
},
};
// . SubscriptionClient ,
// , .
6. Escribir un componente de Vue
Ahora tenemos todo lo que necesitamos para crear un chat público. Solo queda un componente por escribir
GroupChat.vue
.
Cargue el componente usando hilo servido y continuemos.
Nota importante: todos tienen su propia idea de la belleza, por lo que solo hice los estilos mínimos necesarios para que el componente sea funcional.
Script de componente
Primero, necesitamos importar nuestros módulos, estilos simples y consultas GraphQL. Todo esto está en el nuestro
src / utils
.
Declare las siguientes importaciones en formato
GroupChat.vue
.
/* API */
import Api from "./utils/api";
import Wss from "./utils/wss";
/* graphQL */
import {
InitialChatData,
CreateUser,
DeleteUser,
UsersSubscription,
CreateMessage,
MessagesSubscription,
} from "./utils/graphql";
/* */
import "../assets/styles.css";
Datos de componentes
Podemos definir qué propiedades de datos queremos usar en la función de datos de nuestro componente. Todo lo que necesitamos es una forma de almacenar usuarios de chat, mensajes, el nombre del usuario "actual" y cualquier mensaje que aún no se haya enviado. Estas propiedades se pueden agregar de la siguiente manera:
/* imports ... */
export default {
name: "GroupChat",
data: () => ({
messages: [],
newMessage: "",
me: { email: "" },
users: [],
}),
};
Ganchos de ciclo de vida
Nuestros enlaces de ciclo de vida se ejecutan en diferentes puntos de la vida de un componente de Vue. Por ejemplo, cuando se monta o actualiza. En este caso, solo nos interesa la creación y el
beforeDestroy
componente. En tales casos, queremos abrir las suscripciones de chat o cerrarlas.
/* ... */
export default {
/* ... */
/**
* , .
*/
created() {
/**
* ,
*/
Wss.subscribe(UsersSubscription, {
data: this.handleUser,
});
/**
* ,
*/
Wss.subscribe(MessagesSubscription, {
data: this.addMessage,
});
/**
* ( 10 )
*/
Api.query({
query: InitialChatData,
}).then(({ data }) => {
this.users = data.usersList.items;
this.messages = data.messagesList.items;
});
/**
* ,
*/
window.onbeforeunload = this.closeChat;
},
/**
* , .
*/
beforeDestroy() {
this.closeChat();
},
};
Métodos de componentes
Tenemos que añadir algunos métodos para procesar cada respuesta de llamada / API (
createMessage
, addMessage
, closeChat
, etc.). Todos ellos se almacenarán en el objeto método de nuestro componente.
Es necesario
señalar una cosa: la mayoría de las mutaciones no esperan y no manejan las respuestas. Esto se debe a que tenemos suscripciones que rastrean estas mutaciones. Después de un lanzamiento exitoso, la suscripción procesa los datos del evento.
La mayoría
de estos métodos hablan por sí mismos. De todos modos, lea los comentarios en el siguiente código.
/* ... */
export default {
/* ... */
methods: {
/**
* , .
*/
createUser() {
Api.mutate({
mutation: CreateUser,
variables: {
email: this.me.email,
},
});
},
/**
* ID.
*/
deleteUser() {
Api.mutate({
mutation: DeleteUser,
variables: { id: this.me.id },
});
},
/**
* ,
*
* .
*
* , ,
* , .
*/
handleUser({
data: {
Users: { mutation, node },
},
}) {
({
create: this.addUser,
delete: this.removeUser,
}[mutation](node));
},
/**
* users, , * .
*/
addUser(user) {
if (this.me.email === user.email) {
this.me = user;
}
this.users.push(user);
},
/**
* users ID.
*/
removeUser(user) {
this.users = this.users.filter(
(p) => p.id != user.id
);
},
/* */
createMessage() {
Api.mutate({
mutation: CreateMessage,
variables: {
id: this.me.id,
content: this.newMessage,
},
}).then(() => (this.newMessage = ""));
},
/**
* . * , , *.
*/
addMessage({
data: {
Messages: { node },
},
}) {
this.messages.push(node);
},
/**
* . beforeDestroy .
*/
closeChat () {
/* */
Wss.close()
/* */
this.deleteUser();
/* */
this.me = { me: { email: '' } }
}
},
/* ... */
}
Plantilla de componente
Por último, pero no menos importante, tenemos un componente
GroupChat.vue
.
Hay
miles de excelentes tutoriales sobre cómo crear hermosas interfaces de usuario. Este no es uno de ellos.
El siguiente
patrón coincide con los requisitos mínimos para la aplicación de chat. Hacerlo hermoso o no depende de ti. Dicho esto, repasemos rápidamente el marcado clave que hemos implementado aquí.
Como
siempre, lea los comentarios en línea del código.
<template>
<div id="app">
<!--
, . ..
-->
<div v-if="me.id" class="chat">
<div class="header">
<!--
, , , , .
-->
{{ users.length }} Online Users
<!--
, closeChat..
-->
<button @click="closeChat">Leave Chat</button>
</div>
<!--
, , div. , , me.
-->
<div
:key="index"
v-for="(msg, index) in messages"
:class="['msg', { me: msg.participant.id === me.id }]"
>
<p>{{ msg.content }}</p>
<small
><strong>{{ msg.participant.email }}</strong> {{ msg.createdAt
}}</small
>
</div>
<!--
newMessage.
-->
<div class="input">
<input
type="text"
placeholder="Say something..."
v-model="newMessage"
/>
<!--
, createMessage.
-->
<button @click="createMessage">Send</button>
</div>
</div>
<!--
. , createUser.
-->
<div v-else class="signup">
<label for="email">Sign up to chat!</label>
<br />
<input
type="text"
v-model="me.email"
placeholder="What's your email?"
@blur="createUser"
required
/>
</div>
</div>
</template>
Y ahora el chat público está construido. Si lo abre en su red local, puede comenzar a enviar y recibir mensajes. Sin embargo, para demostrar que se trata de un chat grupal real, abra varias ventanas y observe el progreso de la conversación.
7. Conclusión y prueba
En este tutorial, hemos explorado cómo el uso de herramientas de desarrollo modernas nos permite crear aplicaciones del mundo real en minutos.
Espero que también haya aprendido cómo inicializar
ApolloClient
y SubscriptionClient
ejecutar consultas, mutaciones y suscripciones GraphQL de manera eficiente en un espacio de trabajo de 8base, así como un poco sobre VueJS.
Ya sea que esté trabajando en un juego móvil, mensajería, aplicaciones de notificación u otros proyectos que requieren datos en tiempo real, las suscripciones son una gran herramienta. Y ahora acabamos de empezar a considerarlos.
Crea una aplicación de chat con 8base
8base es un backend sin servidor llave en mano como servicio creado por desarrolladores para desarrolladores. La plataforma 8base permite a los desarrolladores crear impresionantes aplicaciones en la nube utilizando JavaScript y GraphQL. Obtenga más información sobre la plataforma 8base aquí .