Building a custom cart - Storefront API Vs Embedded app

danabdn
Shopify Partner
16 0 6

Hello,

 

I am new to Shopify but can cope with Angluar apps - in fact I have created an Angular 7 "tour event product" based cart creation app - so far it works really well.  I do however have custom logic depending on the needs of the customer i.e. anyone who needs to sit at the event will require two places (so I need access to query existing orders and amend product quantities - this is something I cannot do alone with Storefront API due to the authentication method i.e. there is none - other than a public key).

 

In order to query the orders (as there can only be one sitting place) and amend the products (amend the quantity since two places are taken up), I need to somehow query the Store database.

 

Question A - how can I access the database from StoreFront API?  I presume I cannot - therefore can a REST call be made from a private storefront app to an external endpoint (which can then do a OAuth REST API call) or will this cause cross domain scripting issues?

 

Question B - can an embedded app be used to create a custom storefront experience instead (placed into a Shopify page) whereby I might have access to the FULL API for creating a cart, order lookup, product amendment?

 

Note: I don't need the "tour booking calendar" on another website-  just inside the Shopify store.

 

Thanks for any assistance,

Dan.

 

 

 

 

 

Replies 14 (14)

Alex
Shopify Staff
1561 81 341

Hey @danabdn,

 

To answer your questions in order:

 

  1. The storefront API is only made to consume what you can see on the storefront itself (as if you were a customer). So you won't be able to see anything in much detail beyond that, it's meant to create storefront applicable experiences. You will not be able to make a cross-origin request to Shopify's Admin API from a browser since we would deny this immediately. Even if you make the request from the shop's storefront itself which is no longer cross-origin, you're then in a situation where you're rendering credentials in the DOM, and you definitely don't want to do that. Short answer: delegate to a back end to make the request from the front end.
  2. What do you mean exactly by embedded app? Do you mean embedded on the storefront, or embedded in the admin? If the former: you would again want to be delegating to the back end. Customer clicks a button (look up orders), sends a request to your back end, your back end uses the admin API, responds to the front end caller with the data it requested.

I hope that helps a bit!

 

Cheers.

Alex | Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

danabdn
Shopify Partner
16 0 6

Hi @Alex / fellow developers,

 

When you say talk to the backend - I think this is where I'm getting confused and unstuck.  I need extra functionality at the pre-populating cart stage.

 

I'm honestly just looking for a way, any way (embedded or otherwise) to build a custom shopping cart for the customer with some custom logic requiring access to the shop database before adding items to the cart with the app being visible to customers of the shop (i.e. not admin).  Suggestions on how to proceed very welcome.

 

You said below - and I don't know how this should be achieved - public app? private app? embedded app?  How can I make a request to Azure if Azure is on a different domain and refused due to cross-origin?

Customer clicks a button (look up orders), sends a request to your back end, your back end uses the admin API, responds to the front end caller with the data it requested.

 

With a private app I cannot talk to a web service say in Azure because it's on a different domain - this would fail right due to cross-origin?

If it were to work, how would I attach a private hash since it's just a front end UI and no where safe to keep the secret key - or can I retrieve the key/secret somehow from shopify to use in the back end?

Due to either of these, I cannot reach the back end from a private app using only Storefront API (correct me if I've misunderstood).

 

I would be happy to host (on Azure) the experience as a website  (where I can have access to secret keys and OAuth REST for direct lookups).

But then I'm don't think I'm allowed an iframe because it would be interacting with cross-origin again?  I just tried putting an iframe in a shop page and it didn't like it.  So then I'm not sure how to self host and have the experience on a page / product page.

 

Refused to display '<URL>' in a frame because it set 'X-Frame-Options' to 'sameorigin'.

 

So then I started looking into app proxies and wondered if I could add app proxies for each of my backend queries - this would this allow me to query a backend on a different domain while providing a secure hash?  I would just be returning JSON.

 

However, app proxies are only available for public apps.  So that led me to thinking about a public app (unlisted).

I understand that public apps set an env file with the secret keys and then the values are processed and return a token for passing with REST queries.

Other than that they are similar to private apps?

 

So could I use a Storefront API but instead of creating a private app, I could have a public app with app proxies to open non-cross-origin domain calls to Azure? 

Can I still put this public app on a customer facing page?

 

Thanks,

Dan.

Alex
Shopify Staff
1561 81 341

Private apps are essentially just a set of API credentials, there's no concept of embedding one of those to be more specific. Public apps (published or unpublished) can be embedded in either the admin or on the storefront via an app proxy. 

 

If you were to use a private app, you would probably be just inserting liquid code on the shop to make callbacks to your backend app which actually possesses the credentials. This isn't very scalable if you want to be able to go past several installs though, since you'd have to create a private app on each shop (or you'd have to instruct the merchant to).

 

I'm not incredibly familiar with Azure but can't you control CORS or frame options rules on the web app itself? Or does Azure override these rules?

 

An app proxy would do the trick if you're ok with how and where it ends up living on the storefront, I can't help too much with your frame options issue though. That's dictated by the server (or I guess maybe Azure?). As you observed, you would indeed need to be a public app. Public apps, make requests with an access token that they acquire via the oauth flow. This is not the same as private apps, which authenticate with just their api key and secret.

 

I hope that clarifies some things but let me know if I can expand on anything a bit more.

 

Cheers.

Alex | Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

danabdn
Shopify Partner
16 0 6

Hi @Alex,

 

I shall kindly take you up on your offer for more explanation as this is all starting to fall into place...and it's making me giddy...

 

 

Private apps are essentially just a set of API credentials, there's no concept of embedding one of those to be more specific.

Private apps have a username and password and the the StoreFront token (the latter I understand).  I have struggling to understand why there is a username and password designed to work in a url - surely to pass the username/password as a URL which can be network sniffed is no security at all - how is this any different from a using a public key?  How would someone typically use the username/password here?

 

 

 

Public apps (published or unpublished) can be embedded in either the admin or on the storefront via an app proxy. 

Sounds good but I thought app proxy was to embed external code e.g. HTML - why is app proxy used to embed an public app installed on store?

 

(I've still to try public app so it may be my lack of experience here and this may be just be how it is done)

 

 

If you were to use a private app, you would probably be just inserting liquid code on the shop to make callbacks to your backend app which actually possesses the credentials. 
This isn't very scalable if you want to be able to go past several installs though, since you'd have to create a private app on each shop (or you'd have to instruct the merchant to).

If the liquid code can contain a private app's credentials - that would make it visible to the user if they inspect the HTML.  Probably similar to the question above but how is this secure?  I'm not sure how I could make use of the credentials without exposing it - will have to give that some thought.

 

It's just the one website for me - and I'm the owner of the website - so geek out with private apps if that's the best/easiest (and secure) solution.

 

 

I'm not incredibly familiar with Azure but can't you control CORS or frame options rules on the web app itself? Or does Azure override these rules?

Yes indeed you are correct - thank you for educating me.  Does this mean I could make a HTTP request from a private app to my own web service hosted on Azure if the CORS was set to allow the shopify and custom domain I apply to the store (theoretically)?  Although yes I would have to solve the issue of creating a hash based on a key that cannot be kept secret because it's all a front end app with only basic authentication (to ensure that the request comes from Shopify only).

 

An app proxy would do the trick if you're ok with how and where it ends up living on the storefront, I can't help too much with your frame options issue though.

So an app proxy would allow me to host a mini-website in Shopify that mostly interacts with my backend.  Sounds like an option too.

That's ok - sounds like Google has a CORS set up that does not allow this (and understandable).

 

As you observed, you would indeed need to be a public app. 
Public apps, make requests with an access token that they acquire via the oauth flow. 
This is not the same as private apps, which authenticate with just their api key and secret.

Yes, I wrote my own OAuth2 flow to connect with my Withings scales (for monitoring my weight) so familiar with this flow.

 

So to summarise...

 

Option 1 - Public App with OAuth and StoreFront

So - the plan going forward is to create a public app, install it on my demo store. 

Then setup a Azure function/website endpoint with CORS set to allow Shopify domain.

By using the OAuth based security of a public app (unlisted) I should be able to make calls to the Shopify database.

Once I have verified the capacity of the event with regards to accessibility I can then use the StoreFront API to create a cart and lead the customers to pay.

Is this right?

 

 

Option 2 - Build a small website hosted in Azure that retrieves data via REST (and OAuth2) and then use App Proxy to embed into the shop.

Is this a reasonable viable option?

 

Option 3 - INSERT HERE 🙂

 

Your help has been REALLY appreciated.

 

Cheers,

Dan.

KarlOffenberger
Shopify Partner
1873 184 900

Hey guys, nice techie discussion going on here!

 

I see apps and backends and serverless functions on Azure and ... hang on a minute! What do your customers need and what do you need to meet their needs?

 


@danabdn wrote:

 

The challenge

An event takes 20 people max.  Unless there is a wheelchair visitor – this would take two places.  There can only be one wheelchair at an event (this will change in the future but for the sakes of describing the challenge let’s say 1). 

I have added 20 standing tickets and 1 wheelchair ticket as products (though maybe I could add products on the fly as I provide them dynamically - open to alternative ways).

I have to check if the event already has the maximum number of wheelchair tickets purchased i.e. 1.
I have to check if the total standing tickets have not exceeded 18 (because one wheelchair takes 2 places).
I have to check if a wheelchair ticket cannot be purchased if there are already 19/20 standing tickets purchased.
If 18 tickets are purchased and then one wheelchair ticket, the standing tickets will need to be reduced by 1.  I’ll worry about cancellations later on.
I would ideally like to query a remote service to confirm ticket availability.

 

original post from https://community.shopify.com/c/Shopify-APIs-SDKs/I-m-new-I-m-baffled-help-with-customer-facing-appr...


So that is the requirement. This is what we need to focus on... well actually you should. Technology for the sake of technology won't solve that requirement (even though most of us here adore tech more than we should admit openly or in front of our spouse).

 

So here are the rules

 

  1. 20 seats available per event
  2. Max 1 wheelchair per event
  3. 1 wheelchair counts for 2 regular seats

And here are the requirements

 

  1. Can I sell a regular ticket?
  2. Can I sell a wheelchair ticket?

That's all there is to it in it's simplest form void of lingual clutter. With that in hand you may realise it is entirely possible to do this with out-of-the-box Admin features and a little help of Liquid in your theme. Even the ability to use your Liquid theme as a query endpoint for 3rd party services to check availability.

 

I'd definitely recommend to first explore the simplest possible avenue before applying the sledgehammer 😄

 

 

Best wishes!

 

 

 

 

danabdn
Shopify Partner
16 0 6

Hi @KarlOffenberger,

 

That's a great name for my new app "Sledgehammer 1000" 🙂

 

I went down the route of Private Apps but due to the security model didn't have safe access to the Admin features.  

But it sounds like an unlisted public app will let me do the same as private app only via the safer mechanism of OAuth and give me access to Admin functions and still retaining access to StoreFront API to build the cart.


At the end of the day, it's just a bit of custom stock checking before creating the StoreFront API basket.

If I can access the Admin features, there is a far reduced need to use Azure.

I will need to use some sort of web service (Azure) to amend the stock following the order of a ticket.

 

If it pans out to be this simple i will be delighted  🙂

 

While you are here, I do have another question that has been raised with me.

Should I create one "Tour" product WITH VARIANTS for each EVENT DATE? How many variants are supported?

Should I create one "Tour" product PER EVENT?  How many products does shopify support? (Probably going with Shopify / Shopify Advanced).

Should I create one "Tour" product PER EVENT, with variants for Standing (20), Wheelchair (1)

Should I create one "Tour" product PER EVENT, with a custom attribute on the order indicating when a wheelchair is needed

 

There was a concern that when the product was deleted after the event, that customer's order history would no longer display the order.

I presume that deleted products where an order has taken place still exist?  Or does only a brief copy of the description of what the customer ordered exist?

 

Can you expand on what you said here:

Even the ability to use your Liquid theme as a query endpoint for 3rd party services to check availability.

@Alex mentioned something like this too - how does liquid (HTML with syntax) help to become and endpoint?  Do you mean can have a bit of Javascript to make web service calls?  The problem I had with this approach (unless you wish to correct me) is that I have no way to create a secret hash because there is no where to safely keep a key.  Alex also mentioned that liquid has access to the keys.  Would love some sample code of this working - I just can't fathom how you would safely use a secret key unless it's being processed on a backend.  If it's output in liquid e.g. hidden field, it's still open to prying eyes.

 

Now to get stuck into the documentation and coding again - this time with public apps.

 

Thanks,

Dan.

 

 

I turn coffee into Overwatch scores and long forum posts - since 2016

KarlOffenberger
Shopify Partner
1873 184 900

Haha, yeah you sure do make good use of that coffee!

 

I was referring to exploring possibilities of leaving out apps entirely. No private app. No public app. Consider the cost of maintaining these - the time it takes to develop an app, the cost it takes to maintain an app as Shopify keeps pushing updates, the cost of running your own servers even if some do come cheap or manage to squiggle in to the free tier. Why would you burden yourself and your clients with all that overhead if there is a chance you could accomplish the same using a much simpler approach? That's all I am asking - of course, that's not to say that every requirement can be solved without apps, but first I'd always try to exhaust every possibility of avoiding apps (whether my own or 3rd party). I am sure you've heard of the K.I.S.S. principles.

 

What @Alex and myself alluded to with Liquid templates as an endpoint has been discussed many times here, elsewhere and so on and so forth so I won't go over it again. Just as an example, go to one of your product pages and simply add .json to the URL. Instant naive API endpoint!

 

From within your product template you can also check variant inventory_quantity to control the rules I outlined in my previous reply.

 

Which brings me to your "newer" questions on how to manage these products. Personally, I'd go for

 

  • Events are collections of products (filter by event tag or type which equals collection handle)
  • Seats are product variants where the default variant is standing and other variant is wheelchair
  • Availability of seats is managed by Shopify's inventory so when you create the standing variant, inventory level is 20 and wheelchair is 
  • When either of the product variants sell out, you hide the product

You would need to handle your rules though so in your product template (and some others) you would need to check for the aforementioned inventory_quantity. Expressing that logic using Liquid is simple and effective.

 

When an event sells out i.e. inventory level simply drops to 0 (and some tweaks for your rules) it simply becomes unavailable for purchase and hidden from the storefront. Though you could still show the events as these are collections for neat features such as past events.

 

You could apply the same principles to avoid seat purchase for events that haven't sold out but have happened.

 

NOTE: I haven't actually implemented any of this, but don't see any major stumbling blocks which is why I keep repeating: explore the solution that requires least effort, time and money first before yielding the sledgehammer 😉

 

Best wishes!

danabdn
Shopify Partner
16 0 6

ok @KarlOffenberger I am trying it your way 🙂  

 

But I'm stuck with something embarrassingly simple.  Adding the private app to a public page.

Doesn't seem to be in the documentation and cannot find any other forum posts to answer it...so maybe I'm overlooking a basic concept...

 

I have created a simple Angular 7 app to display a calendar that can add items to a cart and proceed to checkout.  All working fine (locally).

Following "installation" of the app, how do I then add my private app to a content page / dummy product page?  I don't mind editing liquid if that's what's needed.

 

K.I.S.S   K.I.S.S

Dan.

danabdn
Shopify Partner
16 0 6

Never mind (sigh) - it's just dawned on me that apps don't actually get published rather some pointer configuration is what gets "published".

My website/service needs to be hosted somewhere and Shopify is providing a window to my website/service.  Facepalm.

 

So I think I'll create two public apps:

One public app (unlisted) will be the events calendar and Storefront API (just need to work out if I'll get the data via liquid json query or public app OAuth query).

One public app (unlisted) will be the administration functionality.

 

Connecting the dots one at a time...

The app extensions diagram makes a lot more sense now. 🙂

 

Thanks,

Dan.

KarlOffenberger
Shopify Partner
1873 184 900

Dan, I meant literally 0 apps. You do not need an app.

kentendo
Visitor
1 0 0
Did you ever get this working? I need to do something similar and these APIs are confusing.
I'm looking to add a calendar to a checkout to choose a delivery day. Then I need to limit how many deliveries can be made on certain days.
garrettbryan
Shopify Partner
12 2 10

@danabdn @KarlOffenberger @Alex

 

Great discussion guys. I totally agree with Karl to keep it simple. I have a similar question, that I don't think can be reduced to the storefront API and theme changes.

 

Here are the requirements:

Customer should be able to upload an image or reference an online image

  1. Customer should be able to view the image in the store UI
  2. Customer should be able to highlight square sections of interest "anchored" to a pixel location on the image
  3. Sections of interest will have metadata -- type, notes, etc.
  4. Sections of Interest should be stored as customer metafield.

Is Option 1 the only viable solution for this project.

Can you offer any corrections to the following diagram to improve my understanding? I'm confused by the Backend Server and Public App Server.

 

 

Following the customer metafield change request:

  1. Request from client to backend via AJAX post
  2. Backend verifies the request, sends request via Admin API or Custom API
    1. I'm confused here. Do I have an extra server?
  3. Shopify Admin updates the customer metafield. Reponds to Backend with success or failure
  4. Backend responds to client AJAX request
  5. Client confirms update (toast or banner notifcation)

 download.png

 

Again thanks again everyone for explaining the inner workings of shopify

garrettbryan
Shopify Partner
12 2 10

@danabdn @KarlOffenberger @Alex

 

Hey Guys,

Just wanted to follow up, since my diagram was pretty confusing. LOL.

I was able to create an endpoint on my Nodejs server for shopify's app proxy. I'm still working on the details of the image upload, but I was able to send data to the endpoint to update the metafields.

 

For anyone who lands here looking for help, the tutorials and the forum have enough information to power through setting this up.

 


garrettbryan
Shopify Partner
12 2 10

@garrettbryan wrote:



 ... but I was able to send data to the endpoint to update the metafields

 



I made a mistake, to recap...

  1. I've been able to successfully proxy a request to my server and validate that the request came from Shopify.
  2. I've not been able to successfully update nor read metafields from my app's server.

 

How can one access the Admin API from a proxied app?