0

Summary

Alright, so I'm kind of missing a piece of the puzzle here, so bear with me.

First, I have a slim API setup for handling the cart of an online store. Please refer to Snippet A down below to understand how this works.

Next, I have an AJAX request being made to this API in order to return this request. Please refer to Snippet B down below to understand how this works.

The problem is that I'm having trouble formulating a simple step by step process for this data to transmit through. This was ok at first, because all I did was add and remove items from the cart, but now I want to be able to update the entire cart with AJAX.

Desired Formula

  1. Request Data Using AJAX from Script
  2. Process Data on Server
  3. Return Data to Script

The problem is returning that data, but the actual issue is unknown.

Troubleshooting

Async Requests

At first, I tried returning data to my data from my API to AJAX script just to confirm that it worked. I used async requests, which I was warned were deprecated, and they didn't really work. Should this of worked?

Timing It Maybe?

This is a ridiculous plan, but one I had nonetheless. It's where I would send an update via API, and wait a bit, then request cart contents via AJAX.

Success or Error?

This one was annoying. So I read somewhere that I should use the success: function() { //Do stuff here } to replace async requests. However, it seemed like my API would randomly return "success" and "error" - making it impossible to use reliably. I could request a cart refresh in "success" and "error" - but that seems like a bad idea. I thought it would be better to ask this community and learn how it's suppose to work.

Question

What's the 'jQuery' way of sending an AJAX request, receiving a response, and acting on that response?

Snippet A

PHP

# This is my Slim Route, it responds when a post is made to domain/cart/api
$app->post('/cart/api', function($request) {
  # Variables
  global $products; // All Shop Products in an Array
  $type = $request->getParsedBody()['type']; // Gets Type
  $id = $request->getParsedBody()['id']; // Gets ID

  # This 'if' statement determines what kind of request is being made.
  if ($type == 'add_item') {
     // Notice the "main" in "$products['main']" - that's just a product category
    foreach($products['main'] as $product) {
      // Checking if product exists
      if ($product['id'] == $id) {
        echo "Product found, name is: ".$product['name'];
        array_push($_SESSION['cart'], $product);
      }
    }
  } else if ($type == 'remove_item') { // Removes item from cart (in session)
    unset($_SESSION['cart'][$id]);
  }
  # I just put return here because it felt right.
  return;
});

Snippet B

JavaScript

# Adding Item to cart (item_id identifies item)
function addToCart(item_id) {
  $.ajax({
    url: "/cart/api",
    type: "POST",
    data: {type: "add_item", id: item_id},
    error: function(){
      console.log("Failure");
    },
    success: function(){
      console.log("Success");
      window.location = "/cart";
    }
 });
 return;
}

# Removing item from cart (item_id identifies item)
function removeFromCart(item_id) {
  $.ajax({
    url: "/cart/api",
    type: "POST",
    data: {type: "remove_item", id: item_id},
    error: function(){
      location.reload();
    },
    success: function(){
      console.log("Success");
      window.location = "/cart";
    }
 });
 return;
}
Evert
  • 93,428
  • 18
  • 118
  • 189
Jacob
  • 890
  • 10
  • 30
  • @Evert, you removed ReST because you said this API was not ReST. Can you send me an example of what ReST would look like? – Jacob Mar 08 '17 at 11:52
  • 1
    There's many different definitions of REST, and different people will give you different answers. One thing that is generally accepted though is that you should be transferring resource state. Your API is more RPC-like. I can't sum it up in a comment, there's plenty of research on REST out there though if you're genuinely interested. – Evert Mar 08 '17 at 16:21
  • I think I've found the answer to this here - http://stackoverflow.com/questions/6068113/do-sessions-really-violate-restfulness - In short, this is not transferring a resource state simply because sessions aren't considered to be resource states? Are there any other reasons that you could consider this not to be a REST API? – Jacob Mar 16 '17 at 09:53
  • Also Evert, in my specific case, it may be prudent to build in some RPC API abilities as well as some REST API abilities. REST in the way that we may be adding different users with their own accounts. RPC in the way that we will want live updating AJAX carts. It may eventually become completely REST when we save the carts on our actual server, and not just within sessions. Does this sound like I understand the difference between the two? I'm still learning. – Jacob Mar 16 '17 at 10:08
  • Hi Jacob, there's a few different sign for this not being REST. 2 things I notice immediately is that: 1. Your representation contains an action (`add_item`) and 2. everything goes through the same url and you're using POST for everything. – Evert Mar 17 '17 at 01:10
  • A RESTful version of this API would probably mean that you: Replace the entire shopping cart with PUT OR you create separate resources (with separate urls) for every item inside the shopping cart. I want to make sure that you understand that I'm not telling you that you need REST. Not at all in fact. I'm just saying that this is not REST, and maybe that's ok. – Evert Mar 17 '17 at 01:12
  • I understand, I'm just not exactly sure what the difference is. All I can really be sure about is that I'm using an HTTP request to complete various actions. My only concern is that I do think it would be nice to know what exactly I'm doing. It's a bit odd to say "Yes, I can build an API, but I don't have any idea what kind of API I build." – Jacob Mar 18 '17 at 02:14
  • 1
    The comments section is a bit too tiny to get deeply into it, but it seems that this website might be a good starting point: https://www.smashingmagazine.com/2016/09/understanding-rest-and-rpc-for-http-apis/ . After that, you might want to read about the 'Richardson Maturity Model' – Evert Mar 18 '17 at 17:22

1 Answers1

2

In terms of the Slim code, you must return a $response from your route callable so you can then control the HTTP status code. For an error, use a status code of 400 or higher.

i.e.

$app->post('/cart', function ($request, $response) {
    return $response;
}

Some other notes on your PHP code:

  • Don't use # for comments
  • Don't use global. Inject your $products or import using use ().
  • If you are using $_SESSION, ensure that jQuery passes the session cookie back to the PHP.
  • Always return a response to the jQuery. This should probably be JSON, so something like:

    $data = ['result' => true];
    return $response->withJson($data, 200);
    

    for a successful case.

  • Removing an item with unset($_SESSION['cart'][$id]); will not work as that's not how you added the product to the cart in the first place.

    This is because array_push() will add an item to the $_SESSION['cart'] array with a sequential index (first product added has an index of 0, second one has an index of 1 etc. unset($_SESSION['cart'][$id]) will remove the item at the index of the id and there is no relationship between $id and the array index created by array_push() when the product was added to the array.

Rob Allen
  • 12,643
  • 1
  • 40
  • 49
  • Also, you said `unset($_SESSION['cart'][$id]);` won't work... But it does. Does this just mean I'm writing really dirty code? – Jacob Mar 08 '17 at 11:54
  • In modern PHP, C style comments are used, not perl style. – Rob Allen Mar 09 '17 at 07:04
  • I've added an explanation of the array_push/unset issue. Try it in a simple PHP script to prove it to yourself. e.g. https://3v4l.org/erCKH – Rob Allen Mar 09 '17 at 07:14