App reviews, troubleshooting, and recommendations
I'm using the React/PHP Shopify App template. I'm trying to connect the React frontend to the PHP backend using web.php to define my routes and using the php Controller classes outlined in the template.
GET requests to my own Controller endpoints are working fine, but when I try to make a POST, I get the following http response:
Response code: 419
"message": "CSRF token mismatch.",
"exception": "Symfony\\Component\\HttpKernel\\Exception\\HttpException",
"file": "/Users/ryan/Repos/ddm-spring-calculator/web/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php",
"line": 389,
"trace": [
{
"file": "/Users/ryan/Repos/ddm-spring-calculator/web/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php",
"line": 332,
"function": "prepareException",
"class": "Illuminate\\Foundation\\Exceptions\\Handler",
"type": "->"
},
{
"file": "/Users/ryan/Repos/ddm-spring-calculator/web/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
"line": 51,
"function": "render",
"class": "Illuminate\\Foundation\\Exceptions\\Handler",
"type": "->"
},
{
"file": "/Users/ryan/Repos/ddm-spring-calculator/web/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 172,
"function": "handleException",
"class": "Illuminate\\Routing\\Pipeline",
"type": "->"
},
etc...
In my `web.php` file, I have this line (along with everything else that comes in the template:
Route::post('/api/springs', [SpringsController::class, 'getSprings']);
My react code looks like this:
const fetchSprings = async () => {
const response = await httpService.post(`/springs`, {1: "ryan"});
setResultText("The response is: " + response[1]);
};
import { useAppBridge } from "@shopify/app-bridge-react";
import { authenticatedFetch } from "@shopify/app-bridge/utilities";
class HttpService {
private authFetch;
constructor() {
this.authFetch = authenticatedFetch(useAppBridge());
}
public async post(route: string, data: any) {
try {
const response = await this.authFetch(this.getFullRoute(route), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const responseData = await response.json();
console.log(responseData); // Handle the response as needed
return responseData; // You may want to return the data for further use
} catch (error) {
console.error('Error making POST request:', error);
throw error; // Rethrow the error or handle it as needed
}
};
private getFullRoute(route: string): string {
const normalizedRoute: string = route.startsWith("/api") ? route : `/api${route}`;
return `${normalizedRoute}?shop=quickstart-f783802a.myshopify.com`;
}
}
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class SpringsController extends Controller
{
public function getSprings(Request $request)
{
// Get the JSON data from the request
$jsonData = $request->json()->all();
// Access the value using the key '1'
$value = $jsonData['1'];
$data = array();
$data[1] = $value;
return response()->json($data);
}
}
In my .env file, I have these values (obfuscated here):
APP_NAME="DDM Spring Calculator" APP_ENV=local APP_KEY=base64:*** APP_DEBUG=true APP_URL=https://quickstart-f783802a.myshopify.com LOG_CHANNEL=stack LOG_LEVEL=debug ## sqlite ## DB_CONNECTION=sqlite DB_FOREIGN_KEYS=true DB_DATABASE=/Users/ryan/Repos/ddm-spring-calculator/web/storage/db.sqlite SHOPIFY_API_KEY=*** SHOPIFY_API_SECRET=***
Any idea why I am getting the CSRF token issue?
Solved! Go to the solution
This is an accepted solution.
I was able to solve this using the extremely helpful post here: https://rafaelcg.com/blog/developer/csrf-on-shopify-apps/ (Thanks Rafael!)
There is 1 caveat though. I got it working based on this general idea. Here is how I actually got it working:
import { useAppBridge } from "@shopify/app-bridge-react";
import { authenticatedFetch } from "@shopify/app-bridge/utilities";
const MyComponent: React.FC = () => {
const fetch = authenticatedFetch(useAppBridge());
const csrf = useCsrf();
const getMyStuff = async () => {
const response = await fetch('/api/stuff?shop=quickstart-f783802a.myshopify.com', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': await csrf()
},
});
if (!response.ok) {
setResultText("Rats and shucks!");
throw new Error(`HTTP error! Status: ${response.status}`);
} else {
setResultText("Oh snap, it worked!");
}
};
This is an accepted solution.
I was able to solve this using the extremely helpful post here: https://rafaelcg.com/blog/developer/csrf-on-shopify-apps/ (Thanks Rafael!)
There is 1 caveat though. I got it working based on this general idea. Here is how I actually got it working:
import { useAppBridge } from "@shopify/app-bridge-react";
import { authenticatedFetch } from "@shopify/app-bridge/utilities";
const MyComponent: React.FC = () => {
const fetch = authenticatedFetch(useAppBridge());
const csrf = useCsrf();
const getMyStuff = async () => {
const response = await fetch('/api/stuff?shop=quickstart-f783802a.myshopify.com', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': await csrf()
},
});
if (!response.ok) {
setResultText("Rats and shucks!");
throw new Error(`HTTP error! Status: ${response.status}`);
} else {
setResultText("Oh snap, it worked!");
}
};
Starting a B2B store is a big undertaking that requires careful planning and execution. W...
By JasonH Sep 23, 2024By investing 30 minutes of your time, you can unlock the potential for increased sales,...
By Jacqui Sep 11, 2024We appreciate the diverse ways you participate in and engage with the Shopify Communi...
By JasonH Sep 9, 2024