I spent the day setting up ssl on my local machine. I am running a wamp stack to build an api locally for testing. This endpoint is set up for ssl now and works perfect. I have a simple route setup that returns a json response.
https://localhost/api/test
It works via firefox by visiting that address.
Now, I am running a react app on
localhost:3000
The problem I am having is that I am trying out the fetch() api and using an example found on the react site (https://reactjs.org/docs/faq-ajax.html). Here is the code but it's extremely simple.
import React, { Component } from "react";
class Api extends Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
items: []
};
}
componentDidMount() {
fetch("https://localhost/api/test")
.then(res => res.json())
.then(
result => {
this.setState({
isLoaded: true,
items: result.items
});
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
error => {
this.setState({
isLoaded: true,
error
});
}
);
}
render() {
const { error, isLoaded, items } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<ul>
{items.map(item => (
<li key={item.name}>
{item.name} {item.price}
</li>
))}
</ul>
);
}
}
}
export default Api;
The kicker is, if I look at the console, I am getting a 200 response code from the request and also the actual JSON response with the proper data....yet for some reason in the app it is printing NetworkError when attempting to fetch resource.
I would understand the error if it wasn't getting the proper response or code but this just doesn't make sense.
Any advice would be helpful and appreciated!
Well, it looks like it was a CORS issue...which I didn't think would be a problem since everything is local. I had to add the following to my Flight Api backend.
Flight::before('json', function () {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET,PUT,POST,DELETE');
header('Access-Control-Allow-Headers: Content-Type');
});
You have to make sure that CORS is enabled in your HTTP headers which you can do from server side and for client side you have to just write mode:'cors' in your fetch api call, because the server would throw an error and your browser would not be able to load the content served for the requested client.
Related
I'm working with React.js and I have the following problem:
import axios from "axios";
export default function Home() {
const [products, setProducts] = useState([]);
const ax = axios.create({ headers: { Accept: 'application/json' }});
function test() {
const res = ax.get("https://vtexstore.codeby.com.br/api/catalog_system/pub/products/search").then((response) => {
// expected the setProducts to be filled with the return of this request
setProducts(response.data);
});
}
test();
// and when I get here to see if the products have been filled, I get an empty array [ ]
console.log(products);
/*
as the products variable was not filled within the axios promise by setProducts,
there is no way to throw the products array here in the HTML to make a forEach or
a map to look cute together with the tags
*/
return (
<sup>how sad, with the product array empty, I can't put the data here '-'</sup>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
See how the result comes out in the IDE console:
I'm in Visual Studio not knowing what to do, I'm new to ReactJS with NextJS and from an early age I've been trying to see if I could solve this problem, but without success.
What can I do to bring the products to the HTML page?
UPDATE: As per the solution below, I created a possible workaround that indicates a path that could have returned a solution
ax.get("https://vtexstore.codeby.com.br/api/catalog_system/pub/products/search/", {})
.then((response) => setProducts(response.data))
.catch((error) => {
console.log(error); // AxiosError {message: 'Network Error', name: 'AxiosError', ...}
console.log(error.status); // undefined
console.log(error.code); // ERR_NETWORK
});
useEffect(() => {
console.log(products);
}, []);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.2/umd/react-dom.production.min.js"></script>
and I'm getting the same error that I put in the comments of the first answer below:
but when I change the setProducts by the console.log to see if it returns the same result, this appears in the terminal where my next.js application is running
that:
ax.get("https://vtexstore.codeby.com.br/api/catalog_system/pub/products/search/", {})
.then((response) => console.log(response.data.length)) // returns the length of the products array
returns this when I update my app:
NOTE: That's why I'm not able to understand my application in Next.js. I'm following all the correct guidelines, writing the code perfectly using axios and when I run the application on the website it gives a network error and doesn't show exactly the amount of products that were displayed in the terminal where my application is running.
I've already configured all the request headers correctly, enabling CORS to allow external requests with other API's, and I still don't succeed in returning the data to my application's page.
Wrap the stuff you have to fetch products inside useEffect hook
useEffect(()=>{
const ax = axios.create({ headers: { Accept: 'application/json' }});
function test() {
const res = ax.get("https://vtexstore.codeby.com.br/api/catalog_system/pub/products/search").then((response) => {
// expected the setProducts to be filled with the return of this request
setProducts(response.data);
console.log(response.data)
});
}
test();
},[])
Then in your return of the component, you can use map on products array with null and undefined checks
Like
{products && products.map(product=>{})}
I am currently working on a project which requires me to make multiple queries/mutations. I tried setting up my apollo client with BatchHttpLink and I can see the data I am requesting in the network tab in the browser. It is coming back at an array of objects instead of JSON.
But the issue is when I try to grab the data in my component data is undefined. I tried using HttpLink instead of BatchHttpLink and I can get the data back from the hook.
My suspicion is the shape of the object that comes back from the response is different, I tried looking into documentation but I can't find much about batching.
Currently using "#apollo/client#^3.0.2"
Here's my client set up.
import { ApolloClient, InMemoryCache, ApolloLink, from } from '#apollo/client'
import { BatchHttpLink } from '#apollo/client/link/batch-http'
import { onError } from '#apollo/client/link/error'
const BASE_URL = 'http://localhost:4000'
const httpLink = new BatchHttpLink({
uri: BASE_URL,
credentials: 'include',
})
const csrfMiddleware = new ApolloLink((operation, forward) => {
operation.setContext(({ headers = {} }) => ({
headers: {
...headers,
'X-CSRF-Token': getCSRFToken(),
},
}))
return forward(operation)
})
const errorMiddleware = onError(({ networkError }) => {
if (networkError && 'statusCode' in networkError && networkError.statusCode === 401) {
window.location.assign('/accounts/login')
}
})
const client = new ApolloClient({
link: from([errorMiddleware, csrfMiddleware, httpLink]),
cache: new InMemoryCache(),
})
This is the react hook I'm trying to console log.
const {data} = useQuery(GET_USER_PERMISSIONS_AND_PREFERENCES)
Figured it out. You need to add another middleware to return the data that the useQuery hook can recognize. The data that comes back in the batch call is an array of objects shaped
{
payload: {
data: { ... }
}
}
So something like this did the trick for me
const batchParseMiddleware = new ApolloLink((operation, forward) => {
return forward(operation).map((data: any) => data.payload)
})
I have been having a similar issue, and have so far only been able to solve it by breaking batching and converting to a normal HttpLink
So I'm practicing React and Redux, and I'm loading a local json file into the store like this ...
import { LOAD_BOOKS } from "./booksConstants";
import axios from "axios";
export const loadBooks = data => {
return {
type: LOAD_BOOKS,
payload: data
};
};
export const asyncLoadBooks = () => {
return async dispatch => {
const response = await axios.get("books.json");
const data = response.data.books;
dispatch(loadBooks(data));
};
};
And here's the reducer ...
import { LOAD_BOOKS } from "./booksConstants";
import { createReducer } from "../../store/reducerUtil";
const initialState = {
books: []
};
export const loadBooks = (state, payload) => {
return {
...state,
books: payload
};
};
export default createReducer(initialState, {
[LOAD_BOOKS]: loadBooks
});
And I'm connecting the App.js to the store with connect() and firing the 'asyncLoadBooks()' in 'componentDidMount()' like this ...
componentDidMount() {
try {
this.props.asyncLoadBooks();
} catch (error) {
console.log(error);
}
}
And everything is working just fine when I loop over the data and display them, however, if I'm on any other route other than "/" and refresh the app manually it gives me this error Failed to load resource: the server responded with a status of 404 (Not Found)
I tried to move the methods to the constructor instead of 'componentDidMount' but it didn't work.
What should I do here? And please keep in mind that I want to use axios and redux to practice them.
Edit
I put a console.log into each async action creator and apparently when I'm on any route other than the home "/" it tries to get the JSON file from this path and can't find it GET http://localhost:3000/category/books.json 404 (Not Found)
How can I solve this?
Ok, guys, I figured it out, the problem was in axios trying to the fetch the JSON file from different paths when you're on different routes, I fixed that by setting a global default baseURL for axios in the index.js file like this ...
import axios from "axios";
axios.defaults.baseURL = "http://localhost:3000/";
And now you can refresh in any route and the data will be fetched successfully.
I have an Angular 4 application where I am trying to fetch a single row (using ID) from a MySQL database. I am using NodeJS with ExpressJS. However, I am struggling finding a way to get the ID from the URL without sharing the exact URL-path, as that would lead to the website only rendering the JSON-object, and not the components.
server.js
app.get('api/books/:id', (req, res) => {
console.log(req.params.id);
});
If the URL is localhost:3000/books/3, the console will log :id. localhost:3000/api/books/3 will however log the correct ID to the console. The issue is that using the latter as my URL in my Angular routing will result in a shared path, which will not work.
Here's an example of how I use Angular's HttpModule to send a GET-request to the server:
this.http.get('api/books/:id')
.map(res => res.json())
.subscribe(data => {
this.bookDetail = data;
});
Here is my path from the routing using Angular's RouterModule:
{ path: 'books/:id', component: BookDetailComponent }
How would I go about solving this issue?
You need to create a function that on the init of that component, the angular app triggers the HTTP request to the server. for example, I have a blog application.
{ path: 'blogs/:id', component: BlogComponent },
ngOnInit() {
this.route.params.subscribe(params => this.blog = params.id);
this.getBlog(this.blog);}
getBlog(blog) {
this.blogService.getBlog(blog).subscribe(
data => { this.foundBlog = data;
if (data.comments) {
this.comments = data.comments;
}
getBlog(blog): Observable<any> {
return this.http.get(`http://localhost:3000/api/blogs/${blog}`).map(res => res.json());
}
the first is my route, the second is the init function on my blog component
the third is the get blog function on the blog component
the last is the get blog function on my blogservice, that send the HTTP request
hopefully that helps.
We are currently using React-Native to develop a mobile project. Our app depends on an API. So we use React's fetch method to get data from the API. Our issue is that the fetch method works differently based on APIs. When we use our API, fetch method throws Network request failed error. We have tried another public API to test, It works perfectly, no error.
I tested all APIs on browser and Postman (testing API), all of them shows JSON response properly. However, we test it on fetch method, it works differently. Here's some code snippet to understand the situation:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
AlertIOS
} from 'react-native';
class Test extends Component {
constructor() {
super();
state = {
airports: []
}
}
onAfterLoad = (data) => {
AlertIOS.alert(
"Fetched Successfully"
);
this.setState({
airports: data.airports
});
}
componentWillMount() {
// Fails
let api1 = 'http://kolaybilet.webridge.co/api/v1/airports/ist/';
// Fails
let api2 = 'http://jsonplaceholder.typicode.com/posts/1/';
// Works
let api3 = 'https://randomuser.me/api/';
fetch(api1)
.then((r) => {
return r.json();
})
.then(this.onAfterLoad)
.catch((e) => {
AlertIOS.alert("An Error Has Occurred!", e.message);
});
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
</View>
);
}
}
The issue centers around the App Transport Security policy in iOS. The randomuser API is SSL while the others are not.
In your XCode project's info.plist file, add the key NSAllowsArbitraryLoads under the NSAppTransportSecurity dictionary with a value of YES. This will allow your other endpoints to be successfully fetched.