Despliegue GraphQL/MongoDB API usando Netlify Functions
Pawel Rybczynski
Software Engineer
Objetivos Configuración inicial Instalar dependencias Empecemos Primero, añade el tsconfig.json al directorio principal: Ahora, vamos a crear src/server.ts para las implementaciones de los servidores. Luego agrega dos funciones: una para el servidor local y la segunda para lambda. Bien, no tenemos resolvers ni definiciones de tipos así que necesitamos crear algunos. Supongamos que, al principio, queremos [...]
Objetivos
Configure tanto los servidores locales como los lambda.
Conecta ambos a MongoDB.
Implantar la autenticación básica.
Despliegue de Apollo sin servidor GraphQL API con Netlify.
Ahora, vamos a crear src/server.ts para la implementación de servidores. A continuación, agregue dos funciones: una para el servidor local y la segunda para lambda.
Bien, no tenemos resolvers ni definiciones de tipos, así que necesitamos crear algunos. Supongamos que, al principio, queremos crear usuarios y recibir información sobre ellos.
No olvide importar la definición de tipo y el resolver al servidor.
// src/server.ts
import { ApolloServer as ApolloServerLambda } from "apollo-server-lambda";
import { ApolloServer } de "apollo-server";
import { typeDefs } from "./schemas";
import { resolvers } from "./resolvers";
{...}
Conectar con MongoDB a través de mongoose
Ahora es un buen momento para crear una conexión con nuestra base de datos. En este caso particular, será MongoDB. Es gratis y fácil de mantener. Pero antes de eso, vamos a instalar dos dependencias más:
La seguridad ante todo Ahora vamos a asegurar nuestras contraseñas mediante hashing.
npm install --save bcrypt @tipos/bcrypt
Ahora, implementa la seguridad de la contraseña dentro del callback pre-middleware. Las funciones pre-middleware se ejecutan una tras otra, cuando cada middleware llama a continuación. Para hacer las contraseñas seguras, estamos usando una técnica que genera una sal y un hash en llamadas a funciones separadas.
// src/model.ts
import bcrypt from "bcrypt";
{...}
const SALT_WORK_FACTOR: número = 10;
UserSchema.pre("guardar", function (next) {
const user = this as User;
if (!this.isModified("password")) return next();
bcrypt.genSalt(SALT_WORK_FACTOR, function (err, salt) {
if (err) return next(err);
bcrypt.hash(usuario.contraseña, salt, function (err, hash) {
if (err) return next(err);
usuario.contraseña = hash;
next();
});
});
});
{...}
A continuación, añada el método comparePasswords a UserSchema:
Ahora podemos organizar una conexión entre servidores y bases de datos. MONGODB_URI es una variable de entorno que contiene una cadena de conexión necesaria para crear la conexión. Puedes obtenerla desde el panel de tu cluster después de iniciar sesión en tu cuenta de MongoDB atlas. Ponla dentro de .env
// .env
MONGODB_URI = ...;
Recuerde siempre añadir ese archivo a .gitignore. Genial. Ahora vamos a añadir una función que permite conectar con db.
El contexto es un objeto que comparten todos los resolvers. Para proporcionarlo, sólo tenemos que añadir una función de inicialización del contexto al constructor de ApolloServer. Vamos a hacerlo.
Deberías obtener esa información dentro del terminal:
Servidor ir funcionando en http://localhost:4000/
En caso afirmativo, abra el http://localhost:4000/ dentro de su navegador.
Debería aparecer la zona de juegos GraphQL. ¡Vamos a crear un nuevo usuario!
Echa un vistazo a cómo se ve en la base de datos.
¡Genial! Todo funciona bien.
Intentemos obtener información del usuario.
Y añadir el campo de contraseña...
Muy bien. Recibimos error No se puede consultar el campo "contraseña" en el tipo "Usuario".". Como puede comprobar, no hemos añadido este campo dentro de la definición del tipo de usuario. Está ahí a propósito. No debemos hacer posible la consulta de contraseñas u otros datos sensibles.
Otra cosa... Podemos obtener datos del usuario sin ninguna autenticación... no es una buena solución. Tenemos que arreglarlo.
Pero antes...
Configurar Codegen
Utilicemos el GraphQL código para obtener un tipo base compatible, basado en nuestro esquema.
Además, necesitamos una forma de crear dicho token. La mejor manera es implementar una consulta de inicio de sesión dentro de nuestro resolver.
// resolvers.ts
import { Resolvers, Token, User } from "./generated/graphql";
const userResolver: Resolvers = {
Consulta: {
user: async (_, { id }, { models: { userModel }, auth }): Promise => {
if (!auth) throw new AuthenticationError("No estás autenticado");
const user = await userModel.findById({ _id: id }).exec();
return usuario;
},
login: async (
_,
{ email, password },
{ models: { userModel } }
): Promise => {
const user = await userModel.findOne({ email }).exec();
if (!user) throw new AuthenticationError("Credenciales no válidas");
const matchPasswords = bcrypt.compareSync(password, user.password);
if (!matchPasswords) lanza un nuevo AuthenticationError("Credenciales no válidas");
const token = jwt.sign({ id: user.id }, "riddlemethis", {
expiresIn: 60,
});
return { token };
},
},
Mutación: {
createUser: async (
_,
{ email, name, password },
{ modelos: { userModel } }
): Promise => {
const user = await userModel.create({
email,
nombre
contraseña,
});
return usuario;
},
},
};
También es necesario actualizar las definiciones de tipo de usuario por tipo de token y consulta de inicio de sesión.
tipo Token {
token: String
}
type Consulta {
usuario(id: ID!): ¡Usuario!
login(email: String!, password: String!): ¡Token!
}
Intentemos ahora obtener el usuario sin token
OK, ¡funciona bien! Intenta iniciar sesión
Intentemos de nuevo obtener el usuario, pero esta vez con el token añadido a las cabeceras
¡Genial! ¿Y si nos equivocamos de credenciales?
¡Genial!
Preparar el despliegue
Último paso: ¡desplegar la api sin servidor con Netlify!
Crear carpeta lambda en el directorio principal y poner dos archivos dentro:
Primero contiene el manejador de AWS. Crea una instancia de servidor ApolloServerLambda y y luego exponer un manejador usando createHandler de esa instancia.