Fetch api in javascripts - javascript

So i am creating a javascript searchbar that uses a fetch command to fetch data from a server. This server is not my own and i just used it as a template. This script works fine.But what i want to do is replace the fetch api with my own
Demonstation of code
const userCardTemplate = document.querySelector("[data-user-template]")
const categoriesSearch = document.querySelector("[data-user-cards-container]")
const searchInput = document.querySelector("[data-search]")
let users = []
searchInput.addEventListener("input", e => {
const value = e.target.value.toLowerCase()
users.forEach(user => {
const isVisible =
user.name.toLowerCase().includes(value) ||
user.email.toLowerCase().includes(value)
user.element.classList.toggle("hide", !isVisible)
})
})
fetch("https://jsonplaceholder.typicode.com/users")
.then(res => res.json())
.then(data => {
users = data.map(user => {
const card = userCardTemplate.content.cloneNode(true).children[0]
const header = card.querySelector("[data-header]")
const body = card.querySelector("[data-body]")
header.textContent = user.name
body.textContent = user.email
categoriesSearch.append(card)
return { name: user.name, email: user.email, element: card}
})
})
I think ive made my own fetch api via github which follows.
https://gist.github.com/UllestReal/09ca3d968dda94535e8fc25b998a6ce5#file-gistfile1-txt
But when i replace the first template api with my own, it wont fetch the code. Can someone tell me what im doing wrong?
I just wrote everything in one go it was alot easier. Just look above for my entire problem

What you have there is just a json file. But whats missing is a server that would serve the file upon a request.

Go to the link you pasted
Click Raw button
Copy the url
const url = 'https://gist.githubusercontent.com/UllestReal/09ca3d968dda94535e8fc25b998a6ce5/raw/705e7b335cd24e382c15e851ea8888fbdc9cdae4/gistfile1.txt'
fetch(url).then(res => res.json()).then(console.log)

Related

How to create internationalized blog with Strapi using Next.js getStaticPaths & getStaticProps

I have a problem figuring out how to localize my content with Next.js and Strapi.
my current file structure looks like so:
pages/
blog/
- [post].tsx
- portfolio.tsx
Inside portfolio I am fetching data for all posts created on Strapi, depending on which locale is currently set, like so:
export const getStaticProps = async ({ locale }) => {
const res = await fetch(
`https://strapi.com/api/articles?locale=${locale}&populate=*`
);
const data = await res.json();
return {
props: {
articles: data.data,
},
};
};
In [post] it looks like that:
export const getStaticPaths = async ({ locales, locale }) => {
const res = await fetch(
`https://strapi.com/api/articles?locale=${locale}&populate=*`
);
const data = await res.json()
const ids = data.data.map((post: any) => post.id);
const paths = ids
.map((id: any) =>
locales.map((locale: any) => ({
params: { post: id.toString() },
locale,
}))
)
.flat();
return {
paths,
fallback: false,
};
};
export const getStaticProps = async (context: any) => {
const id = context.params.post;
const res = await fetch(
`https://strapi.tincors.com/api/articles/${id}?populate=*`
);
const res_blocks = await fetch(
`https://strapi.tincors.com/api/articles/${id}?populate[blocks][populate]=*`
);
const data = await res.json();
const blocks_data = await res_blocks.json();
const block_data_slider = blocks_data.data.attributes.blocks[0].files.data;
return {
props: { article: data.data, slider: block_data_slider },
};
};
Note that each article on Strapi has different id for it's localized version - so as an example:
article_1_pl has id of 10
but it's english variant has id of 12.
fun fact - on portfolio.tsx data is fetched successfully, and post miniature cards are properly displaying based on the current domain (on dev I am using two different hosts for i18n - localhost:3000 for PL & example.com:3000 for EN).
However once I try to redirect myself to the full article, by clicking on the post miniature card, I get the 404 page not found error in the browser, with these errors poping each second in the console logs Error.
It doesn't matter which local host I am currently at.
cards are wrapped in a <Link href="/blog/${id}" locale={route.locale} />
However the moment I change my code in [post].tsx by removing the "locale" from the endpoint:
const res = await fetch(
`https://strapi.com/api/articles?locale=${locale}&populate=*`
);
to:
const res = await fetch(
`https://strapi.com/api/articles?populate=*`
);
suddenly each of my PL articles on localhost:3000 are displayed properly, and only the english variants aren't working (404 page not found).
I assume that it is due to the fact, that by removing the "locale" from the API endpoint it only fetches the polish articles, not the english ones, but it baffles me why it's not working at all, when I use the localized endpoint source.
How I want my app to work:
I want article description (which is generated as a dynamic route) to display in active language, by fetching localized data by the post id.
My question is:
How do I fetch the proper localized data from Strapi in [post].tsx
when using getStaticPaths & getStaticProps. What is wrong with above code and how do I fix it?
I apologize if the above description is too chaotic to understand - feel free to ask for more explanations if necessary :)

How to correctly display images on React frontend that are returned by Laravel as StreamedResponse objects?

The idea is as follows:
Images/documents are stored privately on the server
A logged-in user on frontend clicks a button which sends an axios request to backend to get an aggregated result of ModelA from TableA and it's associated attachment file list from TableB
For each ModelA, numerous requests are made to endpoint to fetch images which are returned as \Symfony\Component\HttpFoundation\StreamedResponse via Storage::download($request->file_name)
This works in the sense that files are returned.
Note - I tried attaching all files to response in step 2 but this didn't work, so added the extra step to get file list and get individual files after that based on the list. This might kill the webserver if the amount of requests becomes too high, so would appreciate any advise on a different approach.
The problem
How to display the files in React and is this the right approach at all considering potential performance issues noted above?
I've tried the following:
Create an octet-stream url link with FileReader but these wouldn't display and had the same url despite await being used for the reader.readAsDataURL(blob) function:
const { email, name, message, files } = props
const [previews, setPreviews] = useState<string[]>([])
const { attachments } = useAttachment(files)
useEffect(() => {
const p = previews
files && attachments?.forEach(async filename => {
const reader = new FileReader()
reader.onloadend = () => {
p.push(reader.result as string)
setPreviews(p)
}
const blob = new Blob([filename])
await reader.readAsDataURL(blob)
})
}, [files, attachments, previews])
Create src attributes with URL.createObjectURL() but these, although generated and unique, wouldn't display when used in an <img /> tag:
useEffect(() => {
const p = previews
files && attachments?.forEach(filename => {
const blob = new Blob([filename])
const src = URL.createObjectURL(blob)
p.push(src)
setPreviews(p)
})
}, [files, attachments, previews])
Results example:
<img src="blob:http://127.0.0.1:8000/791f5efb-1b4e-4474-a4b6-d7b14b881c28" class="chakra-image css-0">
<img src="blob:http://127.0.0.1:8000/3d93449e-175d-49af-9a7e-61de3669817c" class="chakra-image css-0">
Here's the useAttachment hook:
import { useEffect, useState } from 'react'
import { api } from '#utils/useAxios'
const useAttachment = (files: any[] | undefined) => {
const [attachments, setAttachments] = useState<any[]>([])
const handleRequest = async (data: FormData) => {
await api().post('api/attachment', data).then(resp => {
const attach = attachments
attach.push(resp)
setAttachments(attach)
})
}
useEffect(() => {
if (files) {
files.forEach(async att => {
const formData = new FormData()
formData.append('file_name', att.file_name)
await handleRequest(formData)
})
}
}, [files, attachments])
return { attachments }
}
export default useAttachment
Try Storage::response(). This is the same as Storage::download() just that it sets the Content-Disposition header to inline instead of attachment.
This tells the browser to display it instead of downloading it. See MDN Docs Here
Then you can use it as the src for an <img/>.
Solved it by sending the files in a single response but encoded with base64encode(Storage::get('filename')). Then, on the frontend, it was as simple as:
const base64string = 'stringReturned'
<img> src={`data:image/png;base64,${base64string}`}</img>```

Node does not receive React's POST request

Here's my React code in posting:
const [nickname, setNickname] = useState('')
const [title, setTitle] = useState('')
const [content, setContent] = useState('')
const [agree, setAgree] = useState(false)
const [thepost, setThePost] = useState({})
const DoSubmit = async () => {
setHasAlert(false)
if (nickname == '' || nickname == null) {
setAlertContent("Please enter a Nickname!")
setHasAlert(true)
return
}
if (title == '' || title == null) {
setAlertContent("Please enter a Title!")
setHasAlert(true)
return
}
if (content == '' || content == null) {
setAlertContent("Cannot post an empty content!")
setHasAlert(true)
return
}
if (agree == false) {
setAlertContent("Please agree to the post rules!")
setHasAlert(true)
return
}
const data = {
title: title,
nickname: nickname,
content: content
}
setThePost(data)
await fetch('http://localhost:3001/posts', {
method: "POST",
body: thepost
})
.then(res => {
setIsError(false)
setAlertContent("Posted Successfully!")
setHasAlert(true)
console.log(res)
})
.catch(err => {
setAlertContent(err.message)
setHasAlert(true)
})
}
And for my Node/Express backend:
router.post('/', async(req,res) => {
const post = new Post({
nickname: req.body.nickname,
title: req.body.title,
content: req.body.content
})
console.log(req.body)
try {
const savedPost = await post.save()
res.json(savedPost)
console.log(savedPost)
}
catch(err){
res.json({message:err})
}
})
However, req.body is empty on my backend. And on React, it says "Successfully Posted!" and its status is 200 (so there were no errors). It just doesn't save and it doesn't see the data from that was sent from React as well.
Any ideas? Thank you!
BTW: On React, all the fields (nickname, title, content) are completely working on the frontend.
UPDATE
I'm using /posts in react but / in node since I already used a middleware on node's main app.js like this:
const postsRoute = require('./routers/posts')
app.use('/posts', postsRoute)
I have a React page getting all the posts:
const fetchData = async () => {
const data = await fetch('http://localhost:3001/posts')
const dataPost = await data.json()
setAllPosts(dataPost)
}
And it's all working fine.
This appears to be failing for three separate reasons, each of which would independently cause the symptoms you are describing.
You are passing the wrong variable
You collect the data in data
You call setThePost(data) to update the state
You pass thepost to the body
The problem is that thepost is the previous value of the state. You won't get the new value until the component is re-rendered and a new DoSubmit function created, but which time it is too late — you're working with the existing DoSubmit function.
Don't use the state for this. Just use the data immediately.
You are passing fetch an object
Look at the MDN docs:
Any body that you want to add to your request: this can be a Blob, BufferSource, FormData, URLSearchParams, USVString, or ReadableStream object
A plain object is none of those things.
You should create a suitable object with either URLSearchParams or FormData depending on what format the server is expecting the data in. You might also want to encode it as JSON (and set the right Content-Type header).
The server has no body parsing middleware
See the express docs:
By default, it is undefined, and is populated when you use body-parsing middleware such as express.json() or express.urlencoded().
You need to include body parsing middleware that matches the type of data you picked when you replaced the object with something suitable in the previous section of this answer.
The combination of URLSearchParams and express.urlencoded() would probably be most suitable.
You are fetching from url : http://localhost:3001/posts in your react code but in node js you are using router.post('/', async(req,res) but you should use router.post('/post', async(req,res) instead.
See in router.post you should add posts same as you are using for fetching.
Also after correction try to do hard reload the page or try to test on incognito mode on getting empty req.body.

How do I conditionally get items from DB using specific value in React(Next.js)?

In my database, there are files. every single file has 'IS_DELETE' row, which shows whether this file is deleted or not.
If 'IS_DELETE' row of a file is 0, it means it is not deleted by the writer of the post.
If 'IS_DELETE' row of a file is 1, it means it is deleted by the writer.
However, I use a GET request to render the items.
I made the code so that you can see it clearly. I might mispelled!
test = () => {
const [files, setFiles] = useState([]);
const getDetails = async () => {
await get(`URL`)
.then((res) => {
setFiles(res)
})
}
useEffect=(() => {
getDetails()
},[])
return (
<>
files.map((file) => (
<div>
{file}
</div>
))
</>
)}
With this code, I render every file, although some files have '1' in their IS_DELETE row.
I am wondering whether I can conditionally get the items from DB
or
I get every file and filter my array using a particular function.
FYI, I get the files in this format.
[
{PK:1, NAME:'Hello.jpg', IS_DELETE: 0}
{PK:2, NAME:'Nice.jpg', IS_DELETE: 1}
{PK:3, NAME:'To.jpg', IS_DELETE: 0}
]
Thank you. I'm not good at English. So please be understandable.
Waiting for your wisdom!
No, you cannot modify the response you get from server unless it specifically has an endpoint to do so. It's like sending a letter and awqiting the response - you cannot make the response diffeent unless your recipient allows you to send a letter with a specific request (eg. 'give me only non-deleted items'), but if you're not in charge of the server, the only thing you can do is indeed filtering the items you get in response.
const getDetails = async () => {
await get(`URL`)
.then((res) => {
const filtered = res.filter(file => file.IS_DELETE === 0);
setFiles(filtered);
})
}
you can pass the parameter is_deleted in the url concatenate with the main one
{url}?is_deleted=0
Depending on the database you are using, it is possible to do so. For example, in an SQL database, you could do SELECT * FROM files WHERE IS_DELETE != 0
But you can also do it in the frontend as shown below:
const getDetails = async () => {
const res = await get(`URL`);
setDetails(res.filter(file => !file.IS_DELETE));
}
my idea is to pass parameter in the url as query string and in the server side you get the value and put it in the database query
test = () => {
const [files, setFiles] = useState([]);
const getDetails = async () => {
await get(`URL?is_deleted=0`)
.then((res) => {
setFiles(res)
})
}
useEffect=(() => {
getDetails()
},[])
return (
<>
files.map((file) => (
<div>
{file}
</div>
))
</>
)}

Next JS and Vercel - development vs production

I’ve built a basic movie DB app in Next JS to see how the framework works. It’s an app that allows you to perform CRUD operations to firebase, utilising the NextJS API endpoints.
I have the app working fine in development, however it does not work at all once to Vercel. I was wondering if anyone can shed some light?
Here is the first 'get all data' call upon initialisation. The other API calls follow the same pattern. None work once deployed.
My index page has this getInitialProps function…
Home.getInitialProps = async () => {
const categories = await getCategories()
const movies = await getMovies()
const images = movies.map(movie => {
return {
id: `image-${movie.id}`,
url: movie.cover,
name: movie.name
}
})
return {
movies,
images,
categories
}
}
This fires off the getMovies function here…
export const getMovies = async () => {
const res = await axios.get('http://localhost:3000/api/movies')
return res.data
And the API endpoint it hits looks like this…
import firebase from '../../lib/firebase';
export default async(req, res) => {
const moviesRef = firebase
.collection('movies');
const snapshot = await moviesRef.get();
const movies = [];
snapshot.forEach(doc => {
movies.push({ id: doc.id, ...doc.data() })
})
res.json(movies)
Thanks in advance!
you should use your server link, not localhost.
You shouldn't hardcode http://localhost:3000 in the request's URL. You should omit it altogether since you're using Next.js API routes (same-origin).
export const getMovies = async () => {
const res = await axios.get('/api/movies')
return res.data
}
Edit: The above solution would work with API routes if the request was happening on the client-side only.
Since the request is made in getInitialProps, you should simply move the logic in your API route to a separate function (could very well be getMovies in this case) and call that directly in getInitialProps instead.
export const getMovies = async () => {
const moviesRef = firebase.collection('movies');
const snapshot = await moviesRef.get();
const movies = [];
snapshot.forEach(doc => {
movies.push({ id: doc.id, ...doc.data() })
});
return movies;
}

Categories