Cart session Not Found When Using Axios Post - javascript

I am trying to implement cart functionality using bumbummen99/LaravelShoppingcart where the user can increase/decrease quantities of items in their cart. Pressing '+' or '-' fires an onclick javascript function called updateCart().
updateCart() uses Axios to send a post request to my CartController#updateCart() where I run the logic to update the cart quantities.
Problem: I lose access to the global cart session after submitting the post request.
Once I'm in updateCart() in CartController, I can access the request
variables from axios successfully. However, I am unable to access my
cart session. I can't locate the cart items even though I have the
correct rowId.
My cart has items in it but typing Cart::content() or Cart::get() returns error 500 because it thinks my cart is empty.
As soon as I can retrieve my cart, I can implement the logic to update the quantity using Cart::update(), etc. Please help!
Hitting + or - triggers updateCart(action,rowId)
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
function updateCart(action,rowId) {
axios.post('/api/update-cart', {
action: action,
rowId: rowId
}).then(response => console.log(response)).catch(error => {
console.log(error.response)
});
}
</script>
Api.php
Route::post('update-cart', 'CartController#updateCart')->name('update-cart');
CartController.php
public function updateCart(Request $request) {
//works, returns '620d670d95f0419e35f9182695918c68'
return $request->get('rowId');
//works, returns 'add' or 'subtract'
return $request->get('action');
//fails, returns empty array
return Cart::content();
//fails, error 500 because cannot find cart instance
return Cart::get('620d670d95f0419e35f9182695918c68');
return 200;
}
When ran, I lose access to Cart::content() and related Cart functions. It's trying to return Cart::content() which should display my entire cart.
this is when I return Cart::content() on any other page

You cannot access sessions within API routes.
APIs are based on tokens, not sessions. Read about "JWT" (JSON Web Token) or "OAuth" or "Laravel Passport".
You can still enforce sessions if you really want to:
Open app/Http/Kernel.php
Find protected $middlewareGroups =
Where you should see 'api' => [
Just add this:
\App\Http\Middleware\EncryptCookies::class,

I suggest you to use cart in database.
Let say someone use your api with web, then he was add to cart. Next day he back to your shop but use mobile app. So if we use session, i think its can not with api. But if use database, you can store cart data base on User ID right.

Related

Shopping Cart item list across frontend and backend

I'm working on an E-Commerce store using Node.JS, Stripe and HTML. I have the frontend JS file in which users add/remove/change the quantity of cart items which also affects a list with all the cart items to access later (Price SKUs and Quantity). A typical cart list would look like this:
["price_1LWgytARYjIsWfAV0lZI6mgW", "1", "price_1LWgytARYjIsWfAV0lZI6PXv", "3"]
To get the checkout in stripe, you need to provide Node.JS with the line items of the Price SKUs and Quantities. I am trying to access this cart items list in the backend. I have tried things such as local storage but it is undefined and null because it isn't running on the webpage.
Can anyone help me to access this list in the backend server? Thank you
Local storage is a feature that lets you store information client-side in the browser. An example is storing someone's preferred locale or timezone if you don't want a cookie/session server-side. So it's expected that your server-side code in Node.js will not have access to those values.
What you need to do instead is make a request to your server that will contain all the line items they have in their cart. In Javascript, this is usually done in two ways
You have your own form in HTML and you pass all the information in the form and submit it which redirects the whole page.
You write code using the Fetch API so that you can send your line items (usually as JSON) to your server and have it reply asynchronously.
In your case, the second option is usually best. You'll have a button that someone can click on when they are ready to pay. At that point, the code will take all your line_items and send them as a JSON array/hash to your server-side code.
It's important to note that the format of your line items right now doesn't really work well because you have an array alternating a Price id price_123 and then the quantity, and then another Price id, etc. making editing quite hard. Usually, you'd want to use an array of objects instead, which would be quite similar to what you would send to the Create Checkout Session API's line_items parameter. What you want to send should look more like this:
var cart = {
line_items: [
{
price: "price_ABC",
quantity: 1
},
{
price: "price_123",
quantity: 7
},
{
price: "price_XYZ",
quantity: 2
}
]
};
This format makes it a lot easier because you have a hash/object that is your cart. It has a line_items property that is an array array of line items. It contains 3 elements, and the first element's price is price_ABC and its quantity is 1 which will be a lot easier to parse and modify in Javascript both client-side and server-side.
Here's a basic example of how to send your cart variable/content to your server with fetch():
fetch(
"/checkout_session_creation",
{
method: "POST",
body: JSON.stringify(cart)
})
.then(function(response) {
return response.json();
})
.then(function(data) {
console.log("Got the response: ", data);
});
This will post to /checkout_session_creation though you have to put the route you are expecting there. It will sent the cart variable/content in the POST body as JSON. Then it expects a response back in JSON that you can parse.
The idea here is that after creating the Checkout Session in Node server-side, you will get the url property that you then need to return to your client. You then need to redirect client-side to that URL.
With all of that said, I'd highly recommend going through Stripe's official Checkout Quickstart end to end as they walk you through most of this.

Nextjs creating a url that only processes code with no view

I am creating a new site using NextJS, the issue i am having is in regards to a password reset verification endpoint.
When a user triggers a password reset, it goes to the API, does all the processing and then returns them to the NextJS frontend at /verifyreset, which saves a code into localstorage, does a small bit of processing and then forwards them onto another page.
The issue is that there is a Default layout wrapping the component in my _app.js like so;
function MyApp({ Component, pageProps }) {
return (
<DefaultLayout><Component {...pageProps} /></DefaultLayout>
);
}
which means that the layout shows on the /verifyreset endpoint, and I only want that endpoint to process data.
Is there any way around this? to have an endpoint that can access localstorage but not be a 'page' so to speak
I did partially understand your question, it would have been clear if you had attached more code snippets in the question.
Anyway, from your statement below:
When a user triggers a password reset, it goes to the API, does all
the processing and then returns them to the NextJS frontend at
/verifyreset, which saves a code into localstorage, does a small bit
of processing and then forwards them onto another page.
what I understood is:
User triggers a password reset [lets say from PageA]
API is invoked; some processing happen
API then, redirects user to /verifyreset page [lets say it PageB]
Navigating to the page, information is saved into localstorage
Once that is completed, user is redirected to another page [lets say it PageC]
Correct me if I am wrong, so your question is, how could you actually skip users to view /verifyreset page but do the things like save to localstorage and other background operations.
Answer 1: The api is being invoked from PageA (see 1). Instead of the api redirecting user to /verifyreset page on the frontend, send some data (JSON or XML) to the calling function (in PageA components..). Based on that data, do the processing and once every thing is complete, redirect the user to PageC. [no need to worry about PageB i.e. /verifyreset page]. Please find the code snippet below:
**API End Point**
async resetPassword(req, res) {
try {
const model = model.body || {};
let data = await PasswordBusiness.reset(model);
//data needs to have information that you require on frontend
return res.json({success: true, data: data});
} catch (error) {
return res.json({success: false, error: error});
}
}
** Frontend - pageA **
import Router from 'next/router';
const resetPassword = (model) => {
callApiEndPoint(model).then(data) {
// do what you want to do with data
//finally navigate to page c
Router.push('url-to-page-c');
});
};
return <button onClick={resetPassword}> Reset </button>
Answer 2: If you require redirecting to the page any how from the API [I think you don't necessary require this], once operation/processing is completed on API end, redirect the user directly to the pageC with some query params with data (if they are not security vulnerable data). e.g. /pagec?token=sometokens&otherinfos=otherinfos and do things on pageC itself. Once completed, remove the query string from the page without refreshing the page.
You have to put /verifyreset at the api folder.
This is what Next.js said in their documentation :
Any file inside the folder pages/api is mapped to /api/* and will be treated as an API endpoint instead of a page.
Reference : https://nextjs.org/docs/api-routes/introduction

Trying to understand Flux stores - so if the state is held in the store, is this also where I do database calls?

I'm trying to build a contacts list app to teach myself reactjs, and I am learning fluxible now.
1) A new contact is entered. Upon submit, a newContact object is created that holds:
firstName
lastName
email
phone1 (can add up to 3 phones)
image (right now its just a text field, you can add a URL..)
2) This newContact object is sent as a payload to my createNewContactAction, and dispatcher is "alerted" that a new contact has been made.
3) At this point, ContactStore comes into play.. This is where I am stuck.
I have gotten my object to this point. If I want to save this object to my database, is this where I would do that?
I'm a bit confused as to what to do next. My end goal would be to show all the contacts in a list, so I need to add each new contact somewhere so I can pull all of them.
Can someone point me in the right direction?
I would make a request to the server to save the newContact object before calling the createNewContactAction function. If the save is successful, then you can call the createNewContactAction to store the newContact object in the ContactStore. If it isn't successful, then you can do some error handling.
To understand why I think this pattern is preferable in most cases, imagine that you saved the contact in the store and then tried to save it in the database, but then the attempt to save in the database was unsuccessful for some reason. Now the store and database are out of sync, and you have to undo all of your changes to the store to get them back in sync. Making sure the database save is successful first makes it much easier to keep the store and database in sync.
There are cases where you might want to stash your data in the store before the database, but a user submitting a form with data you want to save in the database likely isn't one of those cases.
I like to create an additional file to handle my API calls, having all of your xhttp calls in your store can clutter things very quickly. I usually name it with my store, so in this case something like "contacts-api.js". In the api file I export an object with all of the api methods I need. eg using superagent for xhttp requests:
module.exports = {
createNewContact: function(data, callback) {
request
.post('/url')
.send(data)
.end(function(res, err) {
if (callback && typeof callback === 'function') {
callback(res, err);
}
});
}
}
I usually end up creating 3 actions per request. First one is to trigger the initial request with data, next is a success with the results and last is one for errors.
Your store methods for each action might end up looking something like this:
onCreateNewContactRequest: function(data) {
api.createNewContact(data, function(res, err) {
if (err) {
ContactsActions.createNewContactError(err);
} else {
ContactsActions.createNewContactSuccess(res);
}
});
},
onCreateNewContactSuccess: function(res) {
// save data to store
this.newContact = res;
},
onCreateNewContactError: function(err) {
// save error to store
this.error = err;
}
DB calls should ideally be made by action creators. Stores should only contain data.

Emberjs: Save persistent data from remote API to local storage

I am still a little confused about the way Ember fetches data from remote API and save them in the browser.
So I have created a REST Adapter to get sets of records with an Ajax call, a serializer, and the corresponding model. Suppose they are posts, and I have successfully made a posts index page where the user can click on any post to get into the post detail page.
The Ajax call happens on the index page, and using the Ember inspector, it is clear that all the records are stored in the local store.
But when I click the "back link" which is available on every post detail page, it does redirect to '/posts/' but it seems to make the ajax call again. So all the posts are fetched from the API once again making the page much less responsive.
Here's my questions:
How does that part of Ember work and how do I make Ember simply get the records from the local store without making Ajax call again and again? (unless the user refresh the browser)
If I make a GET request to 'post/1' , no data will be available since in this route no Ajax call should be made. But how do I let the data show? Should I set up another REST adapter for individual post or is it possible to get the record from the local store if an Ajax call has been made?
Hope that makes sense and thanks in advance!
Update:
My post adapter:
App.PostAdapter = DS.RESTAdapter.extend({
findAll: function(store, type, sinceToken) {
var url = 'THE URL TO GET JSON BACK';
return $.getJSON(url).then(function(data) {
return posts;
})
}
});
My Post and Posts routes:
App.PostRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('post', params.postId);
}
})
App.PostsRoute = Ember.Route.extend({
model: function() {
return this.store.find('post');
}
})
Regarding your first question: It depends on the model callback of your route. If you use the all method of the store, the Ajax Request won't be made again. (But: You'd be responsible to get the data the first time around. You way want to sideload it somewhere or may want to call find if all didn't return anything. It depends on your application.
Regarding your second question: The RESTAdapter should be available for single data items as well as for lists. You can implement a model hook in the route using find. If you link-to this route with an object (instead of an ID), this hook won't be called. So the hook would only be called when needed.

Pagination by token in sever side and ember.js

I have in the frontend an ember.js application with ember-data to abstract the models and in server side I have a REST Api. When I need a list of the items in the server I do a GET request for /items in the case that the list have more than 10 items I receive a json just like that:
{
nextPageToken:"token",
items:[
...
]
}
The nextPageToken is a token to be used to get the items in the next page, in this particular case making another GET request with the page token included: /items?pageToken=token.
I don't know the best way that I can use this tokens to create a page showing the items with a link to the next and the previous pages (storing the token from the previous page) with ember and ember-data.
UPDATE
After some research I found a solution to navigate to next page extending the extractMeta function in the RESTSerializer to store the nextPageToken as metadata.
App.ApplicationSerializer = DS.RESTSerializer.extend({
//...
// Extract the pageToken and store it as metadata from the desired type.
extractMeta: function(store, type, payload) {
store.metaForType(type, { nextPageToken: payload.nextPageToken });
}
}
And then in the controller from my page create a property based in the stored page token.
App.ItemsController = Ember.ArrayController.extend({
//...
// Get the page token store as metadata from the item model.
nextPageToken: function(){
var meta = this.store.metadataFor("item");
return meta.nextPageToken;
}.property('item')
}
Now it's possible to use the page token in your template to create a link to the next page.
With that, part of the problem is solved, but I still need to find a solution to navigate to previous pages.

Categories

Resources