I have a REST API, shown below, that takes in a code param, search the database, return a result if the param exists, and redirect users to a long_url gotten from the database. How do I translate this to graphQL?
indexRoute.get("/:code", async (req, res) => {
try {
const urlCode = req.params.code
const url = await Model.findUrlCode(urlCode)
if (url) {
return res.redirect(url.long_url)
} else {
return res.status(404).json("No url found.")
}
} catch (err) {
console.log(err)
return res.status(500).json("Server error")
}
})
export default indexRoute
a very good resource with example,
https://blog.bitsrc.io/migrating-existing-rest-apis-to-graphql-2c5de3db
Related
I make a crud with products
I send an http request to the /api/deleteProduct route with the product id to retrieve it on the server side and delete the product by its id
To create a product it works only the delete does not work
pages/newProduct.js :
useEffect(() => {
async function fetchData() {
const res = await axios.get('/api/products');
setProducts(res.data);
}
fetchData();
}, []);
const handleSubmit = async (event) => {
event.preventDefault();
const formData = new FormData();
formData.append('picture', picture);
formData.append('name', name);
formData.append('price', price);
formData.append('category', category);
formData.append('description', description);
try {
const res = await axios.post('/api/createProduct', formData);
console.log(res.data);
} catch (error) {
console.log(error);
}
};
const handleDelete = async (id) => {
try {
await axios.delete(`/api/deleteProduct?id=${id}`);
setProducts(products.filter(product => product._id !== id));
} catch (error) {
console.log(error);
}
};
api/deleteProduct.js :
import Product from '../../models/Products';
import { initMongoose } from '../../lib/mongoose';
initMongoose();
export const handleDelete = async (req, res) => {
if (req.method === 'DELETE'){
try {
const { id } = req.params
const product = await Product.findByIdAndRemove(id);
if (!product) {
return res.status(404).json({ message: 'Product not found' });
}
return res.status(200).json({ message: 'Product deleted successfully' });
} catch (error) {
console.log(error);
return res.status(500).json({ message: 'Database error' });
}
}};
I have a 500 error but no error in the server side console and the console.log is not showing like the file was not read
Based on the code you've shared, it seems that the problem may be with the way that the delete request is being handled on the frontend. Specifically, in this line:
await axios.delete("/api/deleteProduct", { params: { id } });
The delete request is supposed to receive the id of the product that should be deleted as a query parameter, but it is being passed as a request body.
Instead of passing it as a parameter, you should pass it as a query parameter by changing it to
await axios.delete(`/api/deleteProduct?id=${id}`);
Also, in your api/deleteProduct.js, you should change the following line:
const { id } = req.query;
to
const { id } = req.params;
Also, you should make sure that the server is running and that the api endpoint '/api/deleteProduct' is accessible and handling the request correctly.
For the last, make sure that the product model is imported and initialized correctly and the database connection is established.
Hope that it solves your problem or, at least, helps :))
I succeeded, I put this (server side):
const { id } = req. query;
and (client side):
await axios.delete(/api/deleteProduct?id=${id});
and I exported my function like this:
export default async function handleDelete(req, res) {
I want to search for my product to display on my browser by clicking the search button.
I can search products by Postman API nicely. But, I have no idea to display data by clicking the search button.
product.js
router.get("/find/:id", async (req, res) => {
try {
const product = await Product.findById(req.params.id);
res.status(200).json(product);
} catch (err) {
res.status(500).json(err);
}
});
//GET ALL PRODUCTS
router.get("/", async (req, res) => {
const qNew = req.query.new;
const qCategory = req.query.category;
try {
let products;
if (qNew) {
products = await Product.find().sort({ createdAt: -1 }).limit(1);
} else if (qCategory) {
products = await Product.find({
categories: {
$in: [qCategory],
},
});
} else {
products = await Product.find();
}
res.status(200).json(products);
} catch (err) {
res.status(500).json(err);
}
});
Navbar.js
const Navbar = () => {
return (
<Button>Search</Button>
);
};
export default Navbar;
You're going to want to use Axios to make a request from your react application.
To do this you need to install and require Axios into your react application.
This code will allow you to make a request to your express application:
async function getProduct(productID) {
try {
const response = await axios.get(`/find/${productID}`);
console.log(response);
} catch (error) {
console.error(error);
}
}
This is going to only work when you know what the ID of the product you're searching is. If you have another endpoint on your server to search for a product via name you can change the endpoint accordingly. Here are the Axios docs.
Hope this helps. Thanks!
Any idea how we can write graphQL resolver so that I can cache API response in the redis and on the next call it takes data from the redis instead of hitting the backend API response ?
Here user name is unique in the API. i.e. 1. getify and 2. bradtraversy
/// Middleware Function to Check Cache
checkCache = (username) => {
redis.get(username, (err, data) => {
if (err) {
console.log("====111111111111==========");
console.log(err);
}
if (data !== null) {
personInfo = data;
// console.log(data);
console.log("============222222222222=========");
return personInfo;
}
});
};
// Running Code
const resolvers = {
Query: {
getPerson: async (_, { username }) => {
await checkCache(username);
console.log(username);
if(null != personInfo) {
console.log("=======333333333=======")
console.log(personInfo);
return JSON.parse(personInfo);
}
else {
console.log("Fetching Data from API")
console.log(username);
const response = await fetch(`https://api.github.com/users/${username}`).then(response => response.json());
redis.SETEX(username, 300, JSON.stringify(response));
// console.log(response);
return response;
}
}
}
I think you might want something like Apollo's Data Sources, assuming you are getting data from other REST APIs. They have a section specifically about using Redis/memcached as a cache instead of an in-memory one.
So the gist of this answer is, if you're using Apollo Server and wanting to cache responses from REST APIs, you can use Data Sources with apollo-server-cache-redis
I'm new to Next Js and functional comoponents. I'm trying to retrieve data from /api/retrieve2
//this is retrieve page
export default function Retrieve() {
const onSubmit = async data => {
const { user } = await axios.post("/api/retrieve2", data);
console.log(user) // user here is undefined
};
return (...);
}
//this is retrieve2, inside the API folder
export default async (req, res) => {
try {
const { data } = await axios.post(myBackendUrl, req.body);
console.log(data) //this is printing the right data - { email: 'casas#gmail.com', code: '123123' }
res.json(data);
} catch (e) {
res.json({ err: e.message || e });
}
};
What am I missing, is this something about Next? About functional components?
You should read about ES6 destructuring
You try to destructure user but the axios respons witch is a object doesnt contain the key user
For data it works because there is a data property in the response
Here are all properties that you can destructure:
{ data, status, statusText, headers, config, request }
You need to get the full URL to make http request to using getInitialProps, here Home is the name of your component
const Home = ({ENDPOINT}) => {
const onSubmit = async data => {
const { data } = await axios.post(`${ENDPOINT}/api/retrieve2`, data);
// consider changing `user` here to `data` since Axios stores response in data object
console.log(data) // should be defined
};
return (...);
}
Home.getInitialProps = ctx => {
const ENDPOINT = getEndpoint(ctx.req);
return { ENDPOINT };
};
// You should store this somewhere you can reuse it
export function getEndpoint(req) {
return !!req
? `${req.headers['x-forwarded-proto']}://${req.headers['x-forwarded-host']}`
: window.location.origin;
}
I have a situation , where i have to send some data to server with query strings.
import * as actions from './actions';
import AXIOS from 'services/axios';
export function getLastEvent({campaign_name, with_campaign} = {}) {
return dispatch => {
return AXIOS.get(`/events/last-event?${campaign_name && `campaign_name=${campaign_name}`}&${with_campaign && `with_campaign=${with_campaign}`}`)
.then(response => dispatch(actions.getLastEventResponse(response)));
};
}
And also i have to check it with express-validator in my backend.
router.get('/last-event', roleChecker('customer'), [
query('with_campaign').optional().isBoolean(),
query('campaign_name').optional(),
], async (req, res, next) => {
try {
// .... some actions
return res.status(OK).send(result);
} catch (err) {
next(err);
}
});
As you can see , i am validating with_campaign if it is Boolean. From my client side there are cases that i don't send with_campaign option. How to best structure my URL not to be such a long ? And if i don't have both properties , then i am getting an URL like this
localhost:3000?&