¿Cómo funcionan las convenciones de URL en REST usando GET?
En el mundo del desarrollo backend, REST es un estándar fundamental para construir APIs efectivas y robustas. Aprender a utilizar adecuadamente las propiedades de los métodos HTTP, como GET, y seguir las convenciones de REST es esencial para estructurar correctamente nuestros APIs. Esto permite que nuestros sistemas interactúen de manera eficiente y clara, tanto internamente como con otros sistemas. Aquí exploraremos cómo implementar estas convenciones para obtener datos precisos y bien organizados a través de REST y GET.
¿Por qué es importante usar el plural en los endpoints?
El uso de nombres en plural para los endpoints es una buena práctica dentro de REST, ya que cuando realizamos un GET, generalmente solicitamos una colección de entidades, no una sola entidad. Por ejemplo, en lugar de /product, deberíamos usar /products para reflejar que esperamos recibir una lista. Esto mejora la legibilidad y la comprensión de nuestra API.
¿Cómo recibir un parámetro en un endpoint?
Cuando trabajamos con REST, los parámetros son clave para permitir que nuestros endpoints sean dinámicos. Un método común es agregar un identificador único después del recurso en la URL. Por ejemplo:
app.get('/products/:id',(req, res)=>{const{ id }= req.params;// Lógica para devolver un producto específico según su ID res.json({ id,nombre:"Producto de ejemplo"});});
Aquí, el :id en la URL actúa como un parámetro capturable. Al realizar una petición a /products/12, podemos recuperar el 12 como req.params.id. De este modo, podemos procesar y devolver la información específica de un producto.
¿Cómo manejar endpoints con múltiples parámetros?
REST también permite más de un nivel de especificidad utilizando varios parámetros. Esto se logra anidando recursos dentro de la URL, algo común cuando se trata de relaciones en entidades. Por ejemplo, para obtener los productos de una categoría específica:
De esta forma, en una petición a /categories/555/products/111, estamos obteniendo 555 como categoryId y 111 como productId. Permite estructurar jerárquicamente la API para reflejar relaciones reales entre entidades.
Consejos prácticos al implementar endpoints GET
Reflexiona sobre las relaciones de tus entidades: En una tienda en línea, piensa en las posibles relaciones, como categorías que contienen productos, usuarios que tienen órdenes, etc. Organiza tus endpoints para reflejar estos vínculos.
Usa nombres descriptivos: Esto facilita que otros desarrolladores entiendan la funcionalidad de tu API sin esfuerzo extra.
Prueba tus endpoints frecuentemente: Asegúrate de que los parámetros se capturan correctamente y retornan los resultados esperados.
La implementación ordenada y eficiente de REST y GET no solo optimiza tu API, sino que también maximiza su usabilidad y claridad. Recuerda que seguir convenciones claras hará que tu API sea más accesible tanto para ti como para otros desarrolladores. ¿Estás listo para poner en práctica estas estrategias y perfeccionar tus habilidades en REST? ¡No dudes en intentarlo y continuar explorando las posibilidades!
Para los que como yo, no sabíamos que es endpoints la palabra que tanto utiliza el profe:
Los endpoints son las URLs de un API o un backend que responden a una petición. Los mismos entrypoints tienen que calzar con un endpoint para existir. Algo debe responder para que se renderice un sitio con sentido para el visitante.
Por favor arreglen esto! En la descripción aparece GET: recibir parámetros, y Nicolás esta hablando es de pooling con postgresSQL. por los visto se cruzaron los videos.
Ver esta clase, me hizo entender cómo funciona los parametro y cómo lo hace Platzi con https://platzi.com/clases/2485-backend-nodejs/42215-get-recibir-parametros/
Es algo fascinante e increible :star2:.
Ya no veré las URL de la misma manera :joy:.
No sé si soy el unico con el problema pero se me reproduce un video del 'Curso de Backend con Node.js: Base de Datos con PostgreSQL' en vez del video de este curso.
Si tienen algunas dudas sobre algunos temas sobre el Desarrollo Backend, les recomiendo que pasen por este curso del profesor Facundo, Curso de Introducción al Desarrollo Backend Explica conceptos como Endpoints, servidor, flujo de desarrollo, tipos de hosting (IaaS, PaaS, SaaS) y otros temas interesantes :). Lo mejor? Dura solo una hora.
Hola compañeros, el profesor llega a mencionar endpoints, pero no le da una explicación. Para ello recomiendo checarlo en el siguiente link
. Después de leerlo más de una vez por fin logré entenderlo.
Preciso ayuda: añadí el get al array categories pero el id de todos es el mismo. No sé si no comprendí bien la clase ¿Debo hacer un endpoint por cada categoría? Gracias
cuando haces /categories, si debes enviar el arreglo con todas las categorias, pero si haces /categories/:id deberias solo devolver un objeto con el id especifico
Para añadir parametros a las rutas lo hacemos con la sintaxis:
app.get('/foo/:bar')
Donde "bar" seria el nombre del parametro de el endpoint "foo"
Para recuperar el parametro dentro de el callback de la ruta, lo podemos encontrar dentro del objeto req.params, siguiendo el mismo ejemplo de arriba seria:
app.get('/foo/:bar',(req, res)=>{const{ bar }= req.params;});
Como se supone que para este curso ya deben saber Javascript no vien al caso explicar la deestructuracion
Fialmente, se pueden agregar mas parametros a la ruta.
const express =require("express");const app =express();constPORT=3000;app.get('/',(req, res)=>{ res.send('Hello crayola');});app.get('/route-new',(req, res)=>{ res.send('Hola soy una nueva ruta o endpoint');});app.get('/products',(req, res)=>{ res.json([{name:'Laptop Gamer',price:23000,},{name:'iPhone X3',price:32000,}]);});app.get('/products/:id',(req, res)=>{const{ id }= req.params; res.json({ id,name:'iPhone X3',price:32000,});});app.get('/categories/:categoryId/products/:productId',(req, res)=>{const{ categoryId, productId }= req.params; res.json({ categoryId, productId
});});app.get('/categories/:categoryId',(req, res)=>{const{ categoryId }= req.params; res.json({ categoryId,category:'Computers & Accesories'});});app.get('/people',(req, res)=>{ res.json([{name:'Arturo',type:'employee'},{name:'Jimena',type:'customer'}]);});app.get('/people/:id',(req, res)=>{const{ id }= req.params; res.json({ id,name:'Arturo',type:'employee'});});app.listen(PORT,()=>{console.log('Mi puerto es: '+PORT);})
Yo imaginé el caso de consultas por diferentes criterios y asumo que la validación de los criterios es tarea del frontend. Por ejemplo, en una búsqueda de personas que pueden tener diferentes roles en un colegio, podríamos hacer búsquedas por nombre, apellido, rol(es) e identificador. Validamos en el frontend el criterio de búsqueda y hacemos al backend la petición que corresponda. Así, en el backend mis endpoints serían:
// ENDPOINTS DE BÚSQUEDA DE PERSONAS//PARA PERSONAS (todas)// todas, apellido, nombre, cedula, rolapp.get('/personas',(req, res)=>{ res.json([{id:"11.111.111",lastnames:'Lombardi González',Names:'Pedro Augusto',roles:["estudiante"],foto:"File",},{id:"11.111.112",lastnames:'Lombardi Egurrola',Names:'Pedro Jesús',roles:["representante","docente","administrativo"],foto:"File",},{id:"11.111.113",lastnames:'González de Lombardi',Names:'Eunice Margarita',roles:["representante","administrativo"],foto:"File",},{id:"11.111.114",lastnames:'Duarte Arambule',Names:'Alfonsina Rosario',roles:["administrativo"],foto:"File",},{id:"11.111.115",lastnames:'Pachuca Duarte',Names:'María Rosa',roles:["representante"],foto:"File",},{id:"11.111.116",lastnames:'Reyes de Molina',Names:'Elisa Margarita',roles:["docente"],foto:"File",},{id:"11.111.117",lastnames:'García Padrón',Names:'Oswaldo José',roles:["apoyo"],foto:"File",},{id:"11.111.118",lastnames:'Buitriado Paz',Names:'Gilberto Alejandro',roles:["estudiante"],foto:"File",},{id:"11.111.119",lastnames:'Cancino Ferrer',Names:'Gonzalo José',roles:["estudiante"],foto:"File",},{id:"11.111.120",lastnames:'Medina Lombardi',Names:'Augusto Alejandro',roles:["estudiante"],foto:"File",},{id:"11.111.121",lastnames:'Medina Lombardi',Names:'Isabel Josefina',roles:["estudiante"],foto:"File",},{id:"11.111.122",lastnames:'Perdomo Lombardi',Names:'Mario Ramón',roles:["representante"],foto:"File",}]);})//PARA PERSONAS (todas por Apellido)app.get('/personas/apellido/:lastname',(req, res)=>{const{lastname}= req.params; res.json([{id:"11.111.111",lastnames:'Lombardi González',Names:'Pedro Augusto',roles:["estudiante"],foto:"File",},{id:"11.111.112",lastnames:'Lombardi Egurrola',Names:'Pedro Jesús',roles:["representante","docente","administrativo"],foto:"File",},{id:"11.111.113",lastnames:'González de Lombardi',Names:'Eunice Margarita',roles:["representante","administrativo"],foto:"File",},{id:"11.111.120",lastnames:'Medina Lombardi',Names:'Augusto Alejandro',roles:["estudiante"],foto:"File",},{id:"11.111.121",lastnames:'Medina Lombardi',Names:'Isabel Josefina',roles:["estudiante"],foto:"File",},{id:"11.111.122",lastnames:'Perdomo Lombardi',Names:'Mario Ramón',roles:["representante"],foto:"File",}]);})//PARA PERSONAS (por nombre)app.get('/personas/nombre/:name',(req, res)=>{const{name}= req.params; res.json([{id:"11.111.111",lastnames:'Lombardi González',Names:'Pedro Augusto',roles:["estudiante"],foto:"File",},{id:"11.111.112",lastnames:'Lombardi Egurrola',Names:'Pedro Jesús',roles:["representante","docente","administrativo"],foto:"File",},]);})//PARA PERSONAS (por cedula)app.get('/personas/:id',(req, res)=>{const{id}= req.params; res.json({ id,lastnames:'Lombardi González',Names:'Pedro Augusto',roles:["estudiante"],foto:"File",});})//PARA PERSONAS (todas por rol o roles, en este caso representantes y administrativos)app.get('/personas/roles/:roles',(req, res)=>{const{roles}= req.params; res.json(["resultados para: "+ roles,{id:"11.111.112",lastnames:'Lombardi Egurrola',Names:'Pedro Jesús',roles:["representante","docente","administrativo"],foto:"File",},{id:"11.111.113",lastnames:'González de Lombardi',Names:'Eunice Margarita',roles:["representante","administrativo"],foto:"File",},{id:"11.111.115",lastnames:'Pachuca Duarte',Names:'María Rosa',roles:["representante"],foto:"File",},{id:"11.111.122",lastnames:'Perdomo García',Names:'Mario Ramón',roles:["representante"],foto:"File",}]);})
·
Debido a que estoy tomando este curso luego de haber realizado "los cursos de frontend de consumo de api", tengo una pequeña idea de cómo deberían estar hechas (a un nivel muy superficial y básico 😅) las respuestas de los endpoints desde el lado del Bakend.
·
Dejaré por aquí mi aporte de cómo lo he ido haciendo, je je~
·
++Lo primero son los datos++: La información que nuestra api va a enviar cómo respuesta. Y para ello simplemente hice un archivo data.js en el cual creé algunos usuarios, productos y categorías de ejemplo.
classUser{constructor(id, name, age){this.id= id,this.name= name,this.age= age
}}classProduct{constructor(id, name, price, category){this.id= id,this.name= name,this.price= price,this.category= category
}}classCategory{constructor(id, name){this.id= id,this.name= name
}}// Usersconst users =[newUser(0,"Miguel",22),newUser(1,"Luis",25),newUser(2,"Gabriela",32),newUser(3,"Alondra",19),newUser(4,"Mike",18),newUser(5,"Rafael",40),newUser(6,"Oriana",20),newUser(7,"Ania",31)];// Categoriesconst clothing =newCategory(0,"Clothing");const sports =newCategory(1,"Sports");const cleaning =newCategory(2,"Cleaning");const appliances =newCategory(3,"Appliances");const furniture =newCategory(4,"Furniture");const random =newCategory(5,"Random");const categories =[ clothing, sports, cleaning, appliances, furniture, random ];// Productsconst products =[newProduct(0,"T-Shirt",205, clothing),newProduct(1,"Jeans",210, clothing),newProduct(2,"Cool Shoes",800, clothing),newProduct(3,"Hat",70, clothing),newProduct(4,"Soccer Ball",510, sports),newProduct(5,"Tennis Racquet",130, sports),newProduct(6,"Boxing Gloves",650, sports),newProduct(7,"Bicycle",1800, sports),newProduct(8,"Disinfectant",150, cleaning),newProduct(9,"Chlorine",120, cleaning),newProduct(10,"Soap",15, cleaning),newProduct(11,"Sponge",8, cleaning),newProduct(12,"Microwave",1000, appliances),newProduct(13,"Refrigerator",2990, appliances),newProduct(14,"Toaster",770, appliances),newProduct(15,"Washing Machine",2500, appliances),newProduct(16,"Sofa",890, furniture),newProduct(17,"Bed",900, furniture),newProduct(18,"Table",500, furniture),newProduct(19,"Chair",130, furniture),newProduct(20,"Pensaste que era un producto cualquiera de la API, pero era yo: ¡DIO!",710, random)];// ALL DATAconstDATA={users:[...users],products:[...products],categories:[...categories]}module.exports=DATA;
Al final toda esa información la almaceno dentro de un objeto llamado DATA el cual simplemente exporto mediante el module.exports para poder usarla en el archivo index.js; el archivo principal de nuestra api y desde el cual enviamos las respuestas.
·
Una vez tenemos los datos, ++establecemos los endpoints++:
/* Initial & Global Values */constDATA=require("./data.js");const express =require("express");const app =express();const port =3000;/* HTTP Requests */// GET Requestsapp.get("/", getMainPage);app.get("/example-route", getExampleRoutePage);app.listen(port,()=>{console.log(`El servidor está corriendo en el puerto ${port}`);});app.get("/users", getUsers); app.get("/users/:userId", getUserById);app.get("/products", getProducts); app.get("/products/:productId", getProductById);app.get("/categories", getCategories); app.get("/categories/:categoryId", getCategoryById); app.get("/categories/:categoryId/products", getProductsByCategory); app.get("/categories/:categoryId/products/:productId", getProductByIdFromCategory);
++En el código hay 10 rutas (de las cuales 8 son endpoints):++
"/", La Página Principal.
"/example-route", Una Ruta de Ejemplo.
"/users", El Endpoint de todos los usuarios.
"/users/:userId", El Endpoint de un usuario específico (por id).
"/produtcs", El Endpoint de todos los productos.
"/produtcs/:productId", El Endpoint de un producto en específico (por id).
"/categories", El Endpoint de todas las categorías.
"/categories/:categoryId", El Endpoint de una categoría en específico (por id).
"/categories/:categoryId/products", El Endpoint de todos los productos de una categoría en específico (por id).
"/categories/:categoryId/products/:productId", El Endpoint de un producto en específico (por id) de una categoría en específico (también por id).
·
Además, como se puede apreciar, no definí las funciones directamente dentro del app.get, sino que les dí nombres y las definí más abajo en mi código. Esto es más que nada para tener todo más ordenadito, je je, 👉👈.
·
Con los endpoints listos, ++redactamos la lógica de las respuestas++:
Dado que en DATA es un objeto en el cual tenemos toda la información de nuestra api, simplemente regresamos como respuesta la propiedad que corresponda, ya sea users, products o categories.
·
Sin embargo, si nos piden un usuario, producto o categoría en concreto, primero tenemos que verificar que el id que nos proporcionen sea correcto. Para ello, simplemente revisamos dentro de nuestra DATA si hay algún usuario, producto o categoría que tenga dicho id, y en caso de que sí, enviar dicho usuario, producto o categoría como respuesta.
// ./Users/{id}functiongetUserById(request, response){const{ userId }= request.params;let userFound =searchInDataById(userId,DATA.users);if(!userFound){ response.send("No se encontró la información solicitada");}else{ response.json(userFound);}}// ./Products/{productId}functiongetProductById(request, response){const{ productId }= request.params;let productFound =searchInDataById(productId,DATA.products);if(!productFound){ response.send("No se encontró la información solicitada");}else{ response.json(productFound);}}// ./Categories/{categoryId}functiongetCategoryById(request, response){const{ categoryId }= request.params;let categoryFound =searchInDataById(categoryId,DATA.categories);if(!categoryFound){ response.send("No se encontró la información solicitada");}else{ response.json(categoryFound);}}
Debido a que la búsqueda es muy similar en cualquiera de los tres casos, tengo una pequeña función searchInDataById la cual busca dentro de DATA.users, DATA.products o DATA.categories (según corresponda) si hay algún usuario, producto o categoría que tenga el id pasado como parámetro. Si lo encuentra, directamente lo retorna, y si no, devuelve null.
Lo hice de One piece, me gusta como proyecto inicial
const express =require("express");const app =express();const port =3000;app.get("/",(req, res)=>{ res.send("Hello! I'm your new e-commerce :D");});app.get("/new-rute",(req,res)=>{ res.send("Hello, I'm a new rute");});app.get("/characters",(req,res)=>{ res.json([{categorie:"character",name:"Monkey D. Luffy",phrase:"I'll become pirate king"},{categorie:"character",name:"Nami",phrase:"I'll make the world map"},{categorie:"character",name:"Vizmoke Sanji",phrase:"I'll find the All Blue"}]);});const characters_phrases ="/characters/:id/phrase/:phraseId";app.get(characters_phrases,(req,res)=>{const{ id, phraseId }= req.params res.json({ id, phraseId
});});const family ="/characters/:id/phrase/:phraseId";app.get(family,(req,res)=>{const{ id, phraseId }= req.params res.json({ id, phraseId
});});app.get("/categories/:categoryId/characters/:id",(req,res)=>{const{categoryId, id}= req.params; res.json({ categoryId, id
})})app.listen(port,()=>{console.log("My port"+ port);});// Install JSON Viewer as navigator extention
app.get('/products',(req, res)=>{ res.json([{name:'Product One',price:1000},{name:'Product Two',price:1000},])})app.get('/products/:id',(req, res)=>{const{ id }= req.params; res.json({ id,name:'Product Id One',price:1000,})})app.get('/category/:id',(req, res)=>{const{ id }= req.params; res.json({ id,categoryName:'ProdOrganic Products',})})app.get('/categories/:categoryId/products/:productsId',(req, res)=>{const{ categoryId, productsId }= req.params; res.json({ categoryId, productsId,name:'Organic Products',collection:[{name:'Organic Coffe',price:35,},{name:'fresh Lettuce',price:35,}]})})app.get('/users/:id',(req, res)=>{const{ id }= req.params; res.json({ id,userName:'Leon Licona',town:'Ciudad de México'})})
const express =require("express");const app =express();const port =3000;const objBooks =[{bookId:1,ISBN:'sadasd',name:'Don quijote',autor:'Juan Bosh'},{bookId:2,ISBN:'asdasd',name:'Wawa',autor:'RochyRD'},{bookId:4,ISBN:'asdadacxz',name:'LeBron James',autor:'MJ'}]app.get("/books",(req, res)=>{ res.send(objBooks);});app.get("/books/:bookId",(req, res)=>{ res.send(objBooks.find((e)=>String(e.bookId)===String(req.params.bookId)));});app.listen(port,()=>{console.log("Estoy corriendo en el puerto "+ port);});
Lo hice de esta forma creo que es mas combeniente en estos casos utilizar las funciones que nos ofrece JS con relación a los arrays