I've created a React JS app and added a fetch() event to a class but I'm unable to work out how to locate the file path as the resulting code leads to a 404 Not Found error in the console.
LoginForm.js:11 POST http://localhost:3000/api/user-login 404 (Not Found)
I am trying to locate user-login.js within /src/api/user-login.js
This is my folder structure:
https://monosnap.com/direct/DT5zykUaHOVz8YMJy9O96B762bOsvQ
Here is the relevant code within the class from LoginForm.js:
class LoginForm extends React.Component {
handleSubmit(event) {
var user = {
'clientname': 'client name here',
'email': 'client email here'
};
fetch('/api/user-login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(user)
})
}
render() {
// Stuff that gets rendered
}
}
I have attempted every variation of /app/user-login that I can think of, including:
app/user-login
app/user-login.js
/app/user-login
/app/user-login.js
./app/user-login
./app/user-login.js
../app/user-login
../app/user-login.js
Could somebody please enlighten me on how I can link to this file? Sorry if this is a stupid question, I've only been learning React JS for a couple of days. Thanks for your help.
I hadn't set-up an API server which is why this was showing a 404 error. I had to use ExpressJS which means that any time my React app makes a request to something that’s not a static asset (not an image or CSS or index.html, basically), it will forward the request to the server.
I used the following tutorial to do this:
https://daveceddia.com/create-react-app-express-backend/
Related
I'm completely new to Node and Spring Boot and am having a difficult time performing a fetch call in my Node.js app. The overall structure of the project is a React front-end with a Java/Spring Boot back-end and Gradle. I'm trying to create a service that automatically runs in the background that the user will never interact with or even know of its existence.
I'm using Google BigQuery for this task and am running some simple SQL queries using the Node.js client library that Google provides. My issue is that after pulling in my data from BigQuery, I want to take that information and perform a POST call using fetch. However, this requires a Java function to make use of this external service I'm trying to trigger with my POST call and when I try running node GetBigQuery.mjs in my terminal I get an error message:
TypeError: Failed to parse URL from /api/delayorders
[cause]: TypeError [ERR_INVALID_URL]: Invalid URL
input: '/api/delayorders', code: 'ERR_INVALID_URL'
I'm not using node-fetch, axios, or any external library to make the POST request as I'm running node 18.8.0 that comes built-in with fetch.
Three main files in total:
BigQuery.js
Includes boilerplate code copied and pasted from Google's documentation.
GetBigQuery.mjs
// There is more code above and below but it's not
// necessary in order to understand my question
value.forEach(element => {
fetch("/api/delayorders", {
method: "POST",
body: JSON.stringify({
"orderIds": element.OrderReferenceId,
"date": tomorrow,
"time": "12:00",
"minutesFromUTC": new Date().getTimezoneOffset(),
"buCode": element.StoreNo,
}),
headers: {
"Content-Type": "application/json",
}
}).then(response => {
console.log(response);
})
})
Delay.java
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
#Log4j2
#RestController
#AllArgsConstructor
#RequestMapping("api")
public class Delay {
#Getter
private final OrderDelayService orderDelayService;
#PostMapping("/delayorders")
#ResponseStatus(HttpStatus.OK)
public String delayOrders(#RequestBody OrderDelayDto orderDelayDto) throws Exception {
orderDelayService.delayOrders(orderDelayDto.getOrderIds(), orderDelayDto.getDate(), orderDelayDto.getTime(), orderDelayDto.getMinutesFromUTC(), orderDelayDto.getBuCode());
return "OK";
}
}
When you make an HTTP request in a browser, you can use a relative URL. The absolute URL will be computed using the URL of the HTML document as the base URL.
So if you had an HTML document at http://example.com/ and make an HTTP request to /foo then the request would go to http://example.com/foo.
When your code is running in Node.js, there is no HTML document. There is no base URL. There is no automatic conversion of a relative URL to an absolute one.
You need to use an absolute URL. (Or a mechanism that supports relative URLs and lets you specify the base URL).
I've started working with React and Node.js for the first time, on building an private Shopify App. The app's purpose is to listen to an add to cart button, when clicked it should create a custom product in the Shopify Backend with the Shopify Product API. I've worked plenty in basic JavaScript and have great experience in jQuery, to handle the more basics of this project. The tought part is binding the POST event to the add to cart click, creating the product and adding it to the cart.
I'm trying the following solution for creating the product in the backend. Is this the correct way of doing it, or is there a better solution for doing this?
How can i bind this Fetch function to an click event?
let new_product = {
product: {
title: Custom,
body_html: test,
vendor: Custom,
product_type: customproduct,
tags: Customproduct
}
};
fetch('/admin/api/2020-07/products.json', {
method: 'post',
body: JSON.stringify(new_product),
headers: {
'X-Shopify-Access-Token': process.env.SHOPIFY_API_SECRET_KEY,
'Accept': 'application/json'
},
})
I'm using Isomorphic Fetch in my project, which should work server and client side.
Any help and guidance would be appreciately recieved.
Thank you!
You have got several questions there. Before answering, it is important to clear few misconceptions that I assumed from your wording and sample code. There are 3 types of Shopify Apps.
Public
Custom
Private
So if you are building a Private app, then provided code will not work for creating Product because Private apps use Basic authentication while Public and Custom apps manage authentication with OAuth 2.0.
I'm using Isomorphic Fetch in my project, which should work server and
client side.
Even though it works on Server and Client ends, do not call Shopify API from Client side as this will expose your private app credentials.
To implement what you are trying to do, you need to modify React App as well as Backend code.
Add an event listener to Button
Send a POST request to Backend server
Create Product on Shopify via API
Add the product to cart using ID returned in previous step
Return the Cart URL in response
Sample code in React would look like
function Product() {
const addProduct = async () => {
const cart = await fetch("/your-end-point", {
method: "post",
body: JSON.stringify({
// add product params
}),
});
};
return <button onClick={addProduct}>Add Product</button>;
}
ReactDOM.render(<Product />, document.getElementById("root"));
Then inside your Node.js application, handle the Shopify API part. Instead of using fetch, I will recommend using Official Node.js module for Shopify.
Sample code will look like
const Shopify = require("shopify-api-node");
router.post("/your-end-point", async (req, res) => {
try {
const shopify = new Shopify({
shopName: "your-shop-name",
apiKey: "your-api-key",
password: "your-app-password",
});
const product = await shopify.product.create(req.body);
// use product ID from previous request
const checkout = await shopify.checkout.create({
/*checkout params */
});
res.status(200).send(checkout);
} catch (ex) {
console.log(ex);
}
});
Our server is setup as follows, using react, graphql, mongo and express:
public
index.html
service.js
src
assets
client (has 2 client side js files)
components (for react)
game.jsx
server (graphql server)
server.js
I need to register a service worker so that I can send push notification to players; the call is from game.jsx (the one that gets loaded when I want the serviceWorker to be registered):
const swreg = await navigator.serviceworker.register('service.js');
This causes a get request to ourURL.com/service.js (hence why I have service.js under public, as that's where it's served)
This is fine and dandy, but then I keep getting import errors in service.js:
Uncaught SyntaxError: Unexpected token {
this is the offending code in service.js:
import { saveSubscription } from "src/queries/queries";
Where saveSubscription is a graphql mutation call, and is defined in src/queries/queries.js.
I have tried other forms of importing, but they give me a syntax error of somekind. Googling told me that I need a type="module" tag, which obviously does not apply to this case.
How can I solve this problem? Thanks!
I fixed it... sort of.
I removed the import line, and instead used a fetch within the function.
fetch(url, {
method: "POST", // get can't have body
'Content-Type': 'application/graphql',
body: JSON.stringify({graphQLQuery})
});
I'm very much new to Vue so please excuse my lack of knowledge here.
In one of my (child) components (Product_Collection.vue) I make an axios request to get some products from my Shopify store via their GraphQL API:
data: () => {
return {
products: null
}
},
methods: {
getProducts: function(){
// 1. axios code here...
// 2. ...then assign result to "this.products" data property
}
}
The products are displayed as thumbnails (let's say there's 10 t-shirts). I then click a product to view it in more detail with more product info and images etc (very much an Amazon-like experience).
The product is shown on it's own in a Product_Single.vue component. So far so good.
But here's the problem...
When I click back to the products page (Product_Collection.vue) (the page with the 10 t-shirts on) the axios request to the Shopify API gets called again and the component is re-rendered from scratch.
My question is how do I tell Vue to stop fetching the data from the Shopify API each time the component is rendered? Thank you
Sounds like you want cache-control, which Axios supports with an extension.
https://github.com/kuitos/axios-extensions
import axios from 'axios';
import { cacheAdapterEnhancer } from 'axios-extensions';
const http = axios.create({
baseURL: '/',
headers: { 'Cache-Control': 'no-cache' },
// cache will be enabled by default
adapter: cacheAdapterEnhancer(axios.defaults.adapter)
});
http.get('/users'); // make real http request
http.get('/users'); // use the response from the cache of previous request, without real http request made
http.get('/users', { cache: false }); // disable cache manually and the the real http request invoked
Or you could go a more complex route and cache the results yourself into an object, and check if that object exists, but then you'll have to deal with when you want to expire the data in that object.
If you use a cache-control, and cache-control headers and expiry, you can drive all that from the API layer and not have to deal with manually managed stale data in the application.
If you are not using Vue Router, and hiding the list page, you can try a simple option.
Instead of v-if, use v-show. The component will be hidden and displayed again. It won't be re-created.
Also, where do you call the API? From created or mounted hook?
If You are using GraphQL then there is the Apollo state management way which integrates nicely with graphQL. Check this out: https://dev.to/n_tepluhina/apollo-state-management-in-vue-application-8k0
So instead of rewriting the app with axios and adding vuex in the mixture, maybe Apollo client would be more convenient
I’m trying to connect my Backbone app with my server api (using Slim) and I’m using Tuppola / Basic Auth Middleware.
The example is very simple, I’m just trying to get it work. I can achieve this in my server acting directly in the browser. I get the popup window, type the user and password and I get the data.
However when I try to do the same thing using my Backbone app I get all the time the same 401 Unauthorized error.
This is my php code. As I said, works fine when using the browser directly.
My class Container
$container["auth"] = function ()
{
return new \Slim\Middleware\HttpBasicAuthentication([
"path" => "/app_rutas",
"realm" => "Protected",
"users" => [
"test" => "123",
],
"environment" => "REDIRECT_HTTP_AUTHORIZATION"
]);
};
My class Routes
class Routes
{
public static function callbacks($app)
{
$app->add( \Controller::class . ':middleware');
$app->add('auth');
$app->get('/app_rutas/clients', \ClientController::class . ':selectAllClients');
$app->get('/app_rutas/client/{type}/{values}', \ClientController::class . ':selectClient');
$app->put('/app_rutas/client', \ClientController::class . ':newClient');
}
}
And this is my js code where I suppose the problem is that I'm not being able to pass correctly the params to the middleware. I've tried many ways a none works. I thought this should be the one it isn't.
fetchData() {
if (!_.isEmpty(this.clients_id)) {
this.url = this.apiUrl('client', this.clients_id);
this.fetch({ headers: {'Authorization':'Basic test:123'} });
}
},
Thanks for all comments in advance.
This was the correct way to pass the username:password using Backbone:
this.fetch({ headers: {'Authorization':'Basic ' + btoa('test:123')} })
Needed a base64 encode function. Now it finally works.