Best GitHub parte 4
Erik Giovani
Posted on May 15, 2023
Hola 馃憢, en este post terminaremos la parte del backend con Next JS.
Para empezar, dentro de nuestra carpeta api que se encuentra dentro de la carpeta pages, vamos a crear un archivo llamado search-place.ts.
Dentro de este archivo agregaremos el siguiente c贸digo:
import type { NextApiRequest, NextApiResponse } from "next";
import messages from "@/utils/messages";
export default async function handler(req: NextApiRequest,res: NextApiResponse) {
if (req.method !== "POST") {
return res.status(404).json(messages.notFound);
}
}
Como te habr谩s dado cuenta, la estructura es muy parecida a lo que hab铆amos hecho en el post anterior, pero esta vez vamos de usar el m茅todo GET usaremos el m茅todo POST.
Antes de continuar, vamos a instalar una dependencia llamada Zod para validar el usuario de GitHub que vamos a resibir.
Esto lo haremos con el siguiente comando:
yarn add zod
Si est谩s usando NPM:
npm install zod
Ya instalado, crearemos un archivo llamado validations.ts, dentro de nuestra carpeta utils, ah铆 procederemos a escribir el siguiente c贸digo:
import { z } from "zod";
export const userZodSchema = z.object({
username: z.string().trim().min(1),
});
Lo que estoy haciendo es importar z desde zod para poder acceder a su propiedad object, que nos sirve para poder validar varios datos, pas谩ndole un solo objeto, en lugar de validar dato por dato, tambi茅n estoy validando un dato como un objeto en caso de que quiera despu茅s agregar m谩s datos para validar que vengan del frontend.
La key username va a tener la validaci贸n del username, en este caso le estoy diciendo con z.string que quiero que el dato sea de tipo string, con el trim le estoy diciendo que si el string recibido tiene espacios se los quite, y con min(1) le estoy diciendo que el username no puede estar vac铆o y debe tener minimo un car谩cter.
Y ese esquema de validaci贸n lo estoy guardando en una constante llamada userZodSchema.
Ahora en nuestro archivo search-place.ts, procederemos a importar nuestro esquema y agregar el siguiente c贸digo despu茅s del if:
const result = userZodSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json(messages.error);
}
const { username } = result.data;
Lo que hace ese c贸digo, es que estamos accediendo a la propiedad safeParse que nos crea zod en nuestro esquema de validaci贸n, que sirve para que si el dato recibido no cumple con las validaciones que le agregamos no nos mande un error, depu茅s va a recibir todo lo que venga del req.body de la petici贸n que nos manden a la ruta /api/search-place con el m茅todo POST y guardaremos el resultado en una constante llamada result, si el objeto recibido tiene m谩s propiedades aparte del username, nuestro esquema de validaci贸n directamente las ignorar谩.
En el if lo que estoy haciendo es revisar que la constante result no tenga una propiedad llamada success en true, que significa que el dato recibido no cumple con las validaciones que agregamos,y responda con el mensaje de error de nuestras utilidades que hab铆amos creado en el post anterior, y si existe la propiedad success, entonces de data desestructuramos el username ya validado.
Ahora en nuestra carpeta util vamos a crear un archivo llamado githubCall.ts y dentro agregaremos el siguiente c贸digo:
const githubCall = async(username: string) => {
const response = await fetch(`https://api.github.com/users/${username}`);
const user = await response.json();
return user;
}
export default githubCall;
Como podr谩s ver, es solo una funci贸n que recibe el username y hace una llamada al api p煤blica de GitHub y nos retorna los datos p煤blicos de su perfil de GitHub.
Tambi茅n crearemos un archivo llamado changeUser.ts dentro de nuestra carpeta utils, y agregaremos el siguiente c贸digo:
import { PrismaClient } from "@prisma/client";
import type { NewUser } from "./types";
const prisma = new PrismaClient();
const changeUser = async (userID: string, newUser: NewUser) => {
const updatedUser = await prisma.user.update({
where: { id: userID },
data: newUser,
});
if (updatedUser) {
console.log("User Updated");
} else {
console.error("Error Updating User");
}
};
export default changeUser;
Esta utilidad nos va a servir para actualizar a los lugares ganadores, por eso la funci贸n esta recibiendo el userID y el newUser, dentro de la funci贸n estamos accediendo a la propiedad user de nuestro user en prisma para actualizar los del usuario por los del nuevo usuario identific谩ndolo por su ID.
Tambi茅n crearemos un archivo newUser.ts dentro de nuestra carpeta utils con el siguiente c贸digo:
import type { NextApiResponse } from "next";
import changeUser from "./changeUser";
import type { GitHubUser, NewUser } from "./types";
import type { User } from "@prisma/client";
const newUser = async (
res: NextApiResponse,
user: GitHubUser,
users: User[]
) => {
const newUser: NewUser = {
username: user.login,
name: user.name,
url: user.html_url,
avatar: user.avatar_url,
total: user.public_repos + user.followers,
};
if (newUser.total >= users[0].total) {
await changeUser(users[0].id, newUser);
return res.status(200).json({
message: "Congratulations, you are in the first place",
});
} else if (
newUser.total < users[0].total &&
newUser.total >= users[1].total
) {
await changeUser(users[1].id, newUser);
return res.status(200).json({
message: "Congratulations, you are in the second place",
});
} else if (
newUser.total < users[1].total &&
newUser.total >= users[2].total
) {
await changeUser(users[2].id, newUser);
return res.status(200).json({
message: "Congratulations, you are in the third place",
});
} else {
return res.status(200).json({
message: "Sorry, you are not in any of the first places",
});
}
};
export default newUser;
Lo que est谩 haciendo ese c贸digo es ver si el nuevo usuario tiene m谩s puntos o menos que cualquiera de los tres usuarios en nuestra base de datos, y si tiene m谩s o igual de puntos lo va a sustituir.
Para finalizar, nuestro archivo search-place.ts se tendr铆a que ver de esta forma:
import type { NextApiRequest, NextApiResponse } from "next";
import messages from "@/utils/messages";
import { userZodSchema } from "@/utils/validations";
import githubCall from "@/utils/githubCall";
import usersCall from "@/utils/usersCall";
import newUser from "@/utils/newUser";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== "POST") {
return res.status(404).json(messages.notFound);
}
const result = userZodSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json(messages.error);
}
const { username } = result.data;
try {
const user = await githubCall(username);
if (user.message) {
return res.status(400).json({ message: "The username not exist" });
}
const users = await usersCall();
return await newUser(res, user, users);
} catch (error) {
return res.status(400).json(messages.error);
}
}
Posted on May 15, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.