How to use routes in Shopify app built using Shopify CLI , React and Shopify App Bridge - node.js

I have a problem with using routes in my application, it is a template built using Shopify CLI, React and Shopify App Bridge guided by this documentation here.
Every route I trigger does get sent to the _app.js file within my project as I can log most of the output in the console, but I can't get it to actually include paths of subpages in my apps like https://{apphost}/custompage will not navigate to custompage but an error handler and the custompage gets included in the query. The route and pathname fields of the props return
{
...
router: "_error",
pathname: "_error ",
...
}
instead of
{
...
router: "custompage",
pathname: "custompage",
...
}
I expected the above to be the result but it isn't. But the custompage url does however appear in the asPath field like this asPath: "/custompage?hmac={hmac}&host={host}&shop={shop}" pretend everything in {} has actual information.
The query field gets the fields it needs as it does on a working page. So the main issue is just routing.
With this in mind I have concluded that maybe I have issues on my side and triggering the server side routes handler, but I do not know where to start redirecting to exact pages instead of the index page that came with the boilerplate code. And I looked on their documentation but they skip most parts that are required to actually explain handling routing with their boiletplate codes. I do not want to edit major functions because I am worried they might stop the whole app from working but I need to be able to handle routes on the app without getting the An unexpected error has occurred. error when trying to route to subpages. Even extensions to whitelisted urls within my app trigger that error, so I think I need help with adding routing to the app or server.
Can anyone help me figure out what I am missing?

I am still new to Shopify but I can say that working with Shopify is a nightmare.
I am not sure if this is the final solution but for now this works: make sure that all the files you are trying to route to have the same naming as your path.
If you are routing to https://{appURL}/subpath then your JS file should be subpath.js . I currently can only get it to work if the file is in the same folder as my _app.js. If I move the file from ./subpath to /dir/subpath then I need to change the extension to https://{appURL}/dir/subpath in my Shopify app settings. It seems to operate relative to the _app.js file's location so keep that in mind.
If you used the Shopify CLI and shopify node create to create your app then this could help with your routing 400 headache.

Related

Add an express use handler that changes the base route

I have a svelte/sveltekit app. It says you could just your app like so
import { handler } from './build/handler.js';
app.use(handler);
But I already have another app in this express server, eg
app.use(otherhandler)
So I was hoping there was a way to do this
app.use('/newapp', svelte)
And it works, but, my svelte app has an auto redirect to /login if you are not logged in. So then the express app immediately redirects to /login whereas I was hoping it would go to /newapp/login. Is there a way to do this?
When you have a different base, you probably should configure that via config.kit.paths.base which then can be imported from $apps/path and added to the various links and redirects (at the very least in the UI this will be necessary, as stated by the docs).

Setting up Swagger Ui in Firebase Functions Server

I've developed an API on Firebase Cloud Functions and I want to include a docs path to it.
I'm using swagger and I could successfully test it locally (localhost:PORT/docs) but when I deploy the function to Firebase it's not working, it redirects me to an authorization page.
I think I figured out why this is:
Let's say the name of my Cloud function is cfunc. Then the base url for it is something like https://region-name-project-name.cloudfunctions.net/cfunc. Based on how I included the swagger documentation:
const swaggerDoc = require('./docs/swagger.config.json')
app.use(
'/docs',
allowCors,
swaggerUi.serve,
swaggerUi.setup(swaggerDoc, {
customCssUrl: '/assets/swagger.css',
customSiteTitle: 'My Function Title',
customfavIcon: '/assets/logo.ico',
swaggerOptions: {
supportedSubmitMethods: [] //to disable the "Try it out" button
}
})
)
the docs should be located at https://region-name-project-name.cloudfunctions.net/cfunc/docs. When I try to access that URL, watching "Network" in my browser DevTools, it attempts a GET at that URL with response 304 and then redirects to https://region-name-project-name.cloudfunctions.net/docs and that's what brings up the Google Authentication page, since there's no Cloud Function named "docs" so Google thinks I'm trying to access something else in Firebase Cloud Functions (the same thing happens if I do something like https://region-name-project-name.cloudfunctions.net/tomato)
But I still don't know how to fix this redirect or why it's happening. I tried adding the Cloud Function URL to the host parameter of the swagger.config.json file, and some modifications to CORS, like allowing more Request Methods, adding json as content type, allowing authentication on headers, but nothing seems to be working.
Hope I was clear enought, if not tell me any other info you need (it's one of my first posts here :B)
Found the SOLUTION
After testing a BUNCH of different things, I found out that the redirection was in fact happening always removing one slice of the path after, for example I changed the docs endpoint to '/something/docs' and when accessing the URL that would be https://region-name-project-name.cloudfunctions.net/cfunc/something/docs it redirected to https://region-name-project-name.cloudfunctions.net/cfunc/docs which did not bring up the Google Authentication thing but now wasn't a valid path for my docs so it returned a 'Cannot GET /cfunc/docs'.
For some reason this redirection DOES NOT happen if you add an extra forward slash ('/') at the end of the documentation URL. So, in the first case, where the endpoint for the documentation is only '/docs', accessing the URL https://region-name-project-name.cloudfunctions.net/cfunc/docs/ does it. I do not know why that is, I'm probably posting an Issue on the swagger repo, but if someone has some extra data on why or how to make it work otherwise it would be awesome to hear.
Hope this helps someone else!
EDIT:
Oh and another thing I forgot, it's apparently better if you setup swagger-ui as if you were using express Router, even if you are not (maybe Firebase loads the Cloud Function with something like a router), so instead of app.use('/docs', swagger-ui.serve, swagger-ui.setup(swagger-file)) do app.use('/docs', swagger-ui.serve) and then app.get('/docs', swagger-ui.setup(swagger-file))

Electron + Vue + msal-nodejs + Azure Ad: redirect URL issue

I'm building a desktop app using Electron and Vue as framework.
I also need to authenticate the user using Azure AD and I'm using msal-node.js as library to do that.
I'm able to authenticate with the server in azure and get the user info, but I cannot figure it out how to set the redirect URL.
First I have to say that the behaviour between dev and prod change drastically and I'm going to explain both scenarios and, in both of them I'm going to use history mode or not
DEV - using createWebHistory
Return Url in Azure and .env file: http://localhost:8080/
This is what I've got from the devTools during the normal navigation (no authenticated)
And this is what I've got after the authentication (the call to the API is successful):
Blank page in the app.
DEV - using createWebHashHistory
Return Url in Azure and .env file: http://localhost:8080/#/
After the authentication (failed):
Blank page in the app.
PROD
In prod I must use createWebHasHistory otherwise I've got blank page from the beginning.
The first problem I've got in production is the url itself.
When I create the window I call the following url:
await win.loadURL('app://./index.html')
In azure I cannot use the same url because it's not a valid url.
If I use just:
await win.loadURL('app://index.html')
I've got blank page
Any idea?
Thank you
The solution I've found it's pretty simple. Probably it's not the most "elegant", but it works, at least for prod. In dev I've still got the same weird problem described above.
Basically I'm starting a node server (localhost:3031 for example), within the app itself, then I'm catching the redirect url with it (localhost:3031/redirect) and serving the internal url from it:
expressApp.get('/redirect', async (req, res) => {
await win.loadURL('app://./index.html#about')
})
As I said, it works and I don't see any security issue with that, but, if you have any other idea or suggestion, please let me know.
Thank you
UPDATE
I've found the issue with Dev as well. In order to authenticate I'm using what Microsoft is suggesting in its documentation.
If you look at the file AuthProvider.js there is this portion of code, at the beginning:
const CUSTOM_FILE_PROTOCOL_NAME = process.env.REDIRECT_URI.split(':')[0];
Down below, in the method "getTokenIteractive" there is this other piece of code that applies the new protocol:
protocol.registerFileProtocol(CUSTOM_FILE_PROTOCOL_NAME, (req, callback) => {
const requestUrl = new URL(req.url)
callback(path.normalize(`${__dirname}/${requestUrl.path}`))
})
In Dev my REDIRECT_URI is "http://localhost:3031/redirect", but the app protocol must be "app" (or whatever you have chosen) in order to work with Vue. So, I've just wrapped this last method in a condition based on the environment and now everything works as expected everywhere.
I hope all this can be useful to someone.
I ran into a similar issue and your solution helped me out, thank you! Can I ask how you handled the logout redirect?
Also have you tried onBeforeRequest to handle the redirects, instead of a node server?
It was used as an example in an auth0 blog: https://auth0.com/blog/securing-electron-applications-with-openid-connect-and-oauth-2/

Entering wrong URL or refreshing in React/Express app causes all pages to error until user returns to homepage

I have an Express.js app with a React front-end. Everything works until I enter a URL for a non-existing resource (or even add a ? to the end of an existing URL): I get a 500 "Internal server error", and then even navigating to a real URL afterward throws the same error. It will only go back to normal functioning after returning to the homepage (which makes me think the issue may be on the React side, with something I'm not understanding about single-page React apps).
The error I see on the back-end is: TypeError: path must be absolute or specify root to res.sendFile, which corresponds to this bit in my code (where I point Express to the React build files):
app.use(express.static('../client/build'));
app.get('/*', function(req, res) {
res.sendFile('../client/build/index.html');
});
What's the best way of handling (or ideally, preventing) this error? Note that it doesn't crash the app, it just requires revisiting the homepage to reset things.
EDIT
It results in the same error even if I just refresh a (working) page.

Node.js (MERN) Serving static files and API's

Im currently building a simple app using the MERN stack to learn. What Ive done so far:
-User Registration and Login (API)
-TODO List (API and Frontend with static files)
Ok, Everything works good and as expected, except for one thing.
I attempt to use my API's for any request, but at the same time I want my whole app to work rendering in a web browser (TODO list). So, the process I've followed is:
-Start node instance
-npm run build (To build react project files)
I did a research on how to use React build in node project and I did the following:
app.use(express.static('myproject/build'));
app.get('/*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'myproject', 'index.html'));
});
Good! So when I go to http://localhost:4000, it renders my index file and it actually works with my Login API, but I have some API's that are only available for consuming data and not rendering UI.
So, my problem is that when running the app, if I go to: http://localhost:4000/api/users/getdata
I get an error saying: Error: ENOENT: no such file or directory pointing the index.html
Ok, if I uncomment the code I posted before, then of course my app is not rendering UI, but my routes from API's work normally.
I know this might be setup/configuration process, but Im trying my best to understand this. If somebody could assist me with this problem please.
The hierarchy im working goes as follows:
myproject (contains models, routes (API's), middlewares, index.js)
frontend (inside folder 'myproject') (build, src (Components))
I did what #MaxAlex suggested. Changed the code from:
app.get('/*')
to
app.get('/')

Resources