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!");
}
};
We recently spoke with Zopi developers @Zopi about how dropshipping businesses can enha...
By JasonH Oct 23, 2024A big shout out to all of the merchants who participated in our AMA with 2H Media: Holi...
By Jacqui Oct 21, 2024We want to take a moment to celebrate the incredible ways you all engage with the Shopi...
By JasonH Oct 15, 2024