Purchase Courses Endpoint
In this lesson, we're going to create the purchase courses endpoint
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the The newline Guide to Fullstack ASP.NET Core and React course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to The newline Guide to Fullstack ASP.NET Core and React with a single-time purchase.

[00:00 - 00:08] Now that we have our clear basket endpoint, let's start working on the purchase courses endpoint. This one is not as straightforward as the previous one.
[00:09 - 00:24] And to add courses to user's account, we need to create a relationship between users and courses. And this relationship will be a many to many relationship because a user can have multiple courses and a cost can have multiple users.
[00:25 - 00:43] And since we are using a code first approach, we will have to make some changes to our models. First of all, let me clear all the fields from here and we'll have to create a new table, which will be called user cause since it will work as a connection between user table and the cost table.
[00:44 - 01:00] So what we can do is inside entity, let's create a new model and let's call it user cause. Now this table will have a user ID column and a cost ID column.
[01:01 - 01:17] So what we can do is we can start with user ID and this has string as an ID and let's call it user ID. Since we are creating a connection, we will also pass user property with the same name.
[01:18 - 01:28] So below this, we can use user with the same name user. Let's now create cause ID property, which has a type, Gued.
[01:29 - 01:42] So prop, Gued and this is called cause ID. Let's import Gued using system and like a user model, we also need a cost model .
[01:43 - 01:54] So let's write cause with the name, cause. Now that we have created the user cause model, we need to add this to other two models.
[01:55 - 02:03] Let's start with the user. So let's open the user model and inside, we need to add an eye collection of user cause.
[02:04 - 02:24] So let me write eye collection of user cause and the name can be user causes. And let's import eye collection using system collection generic.
[02:25 - 02:37] The same way inside cause model and it's going to be the same property. So we can copy it and go to the cause model and below, we can paste it doing this.
[02:38 - 02:47] We are establishing a connection between the user model and the cause model. And this is the requirement if you want to create a many to many relationship inside entity framework.
[02:48 - 02:54] Now, inside the store context, we'll have to create a new DB set. So let me go to the store context.
[02:55 - 03:15] Here we will have to create a new DB set of type user cause. So let me write DB set of type user cause and it will have a name user causes doing this won't be sufficient.
[03:16 - 03:25] We will have to write the configuration to. So inside the one model creating method, we will have to create a new configuration.
[03:26 - 03:33] So let's do it here and let me go a bit on top. This is going to be for entity user cause.
[03:34 - 03:51] So we can write builder dot entity of type user cause. Since this table will have two keys, we can write dot has key and let's write us with stands for user cause.
[03:52 - 04:06] This will be new us dot user ID and us dot cause ID. Now let's write configuration for many to many relationship.
[04:07 - 04:43] So below this, let's write builder dot entity of type user cause and since one user can have many causes, they will write dot has one and inside you see, which goes to you see dot user. So one user will have many causes and for that we can write dot with many and this time, let's simply call it you, which will go to you dot user causes.
[04:44 - 04:51] And this time they will have a foreign key of user ID. So we can write dot has foreign key.
[04:52 - 05:05] And here you see goes to, let's make it small and you see dot user ID. We can copy the same to establish other side of the relationship.
[05:06 - 05:17] So let me copy it. And now let me replace user with cause and here it will be cause ID.
[05:18 - 05:24] Everything else will stay the same. So a user will have many user causes and a cause will have many user causes.
[05:25 - 05:36] This is how we established many to many relationship inside code first approach of entity framework call. Now that we have established the relationship, we can make a new migration to apply these changes.
[05:37 - 05:57] So let's open the terminal and inside the server, let me close this and go to the root level. And now we can type dot net EF migrations add and let's call it user causes added.
[05:58 - 06:17] Our starter project is API and the project is infrastructure. Now that the migration is successful, we can go back to the API project and run this.
[06:18 - 06:28] We can now open the database and see if it has created the user causes table. So let's open database, learn if I dot TV and inside SQLite explorer.
[06:29 - 06:40] Yes, we have a user causes table. And now we don't have anything but it has created a table which has a user ID and a cause ID.
[06:41 - 06:49] And now that we have created a table, let's create an endpoint which will add causes and users to this table. We can do this inside users controller.
[06:50 - 06:59] So first of all, let's save it and close the terminal and close this, this and this. We can now go to the users controller.
[07:00 - 07:10] So let me write users controller and here I can create a new HTTP method. So let's make it here.
[07:11 - 07:27] So for this, we will create a new HTTP post method. So let me write HTTP post and let's call it purchase courses.
[07:28 - 07:41] This should be an authorized method. So on top, we can write authorize because we don't want any anonymous user to be able to add causes.
[07:42 - 07:47] So let's import it using a spinet authorization. We are not going to return anything from this method.
[07:48 - 08:04] So we can simply write public async task of action result. And we can simply call it add causes.
[08:05 - 08:16] Inside the method, we will first extract the basket. So let me write war basket and again, await extract basket.
[08:17 - 08:26] And since it's an authorized request, we can use user dot identity dot name. Now let's fetch the user.
[08:27 - 08:44] So let me write my user and this will be equal to await user manager dot find my name async and we can pass the same user identity name. So let me copy it from here and paste it here.
[08:45 - 08:55] Now here we simply have to map over the basket items and add each cause inside the basket to the user causes table. So what we need to do is we will create a for each loop.
[08:56 - 09:19] So here let's write for each and since items inside the basket is of type basket item, that's right basket item cause in basket dot items. Inside this loop, we will write a variable user cause.
[09:20 - 09:36] This will be equal to new user cause and here we have to pass the user ID and the cause ID. So let's start with the cause ID and this will be equal to the cause the individual cause which is inside the basket.
[09:37 - 10:01] So let's write cause dot cause ID and the user ID will be equal to user dot ID. And after we create a user cause, we can use context dot user causes dot add and we can add the user cause.
[10:02 - 10:08] So the number of times it will loop over the basket items. It will keep on adding those items inside the user cause is stable.
[10:09 - 10:26] And this way we will add all the causes inside a basket to the users causes table. At this moment, the data is still in memory and to make it available inside our database, we'll have to save it using result.
[10:27 - 10:37] And like always, I will await context dot save changes async. And if it's more than zero, that means it is successful.
[10:38 - 10:46] So if the result is true, which means it's more than zero, we will return. Okay.
[10:47 - 10:58] Otherwise, we will return a bad request. So let's write bad request and inside we can use new API response.
[10:59 - 11:07] And here we will pass 400 status. And the message can be problem adding causes.
[11:08 - 11:20] We can now go back to the agent file again. So let's open agent and inside users, we can create a new endpoint, which can be called add cause.
[11:21 - 11:27] This will be a post request. So what we can do is we can write requests dot post.
[11:28 - 11:40] And here the end point is users slash purchase courses. And since it's a post request, we will pass an empty body.
[11:41 - 11:45] Now we can use this inside the checkout component. We need to call this method before clearing the basket.
[11:46 - 12:04] Otherwise there will be nothing to add. So what we can do is before removing the basket and as soon as it is succeeded, we can use await agent dot users dot add costs.
[12:05 - 12:18] Once it's successful, it will go on and show notification and then it will remove basket from Redux and as well as from the database. And as you know, the button inside checkout summary is responsible for invoking the handle payment function.
[12:19 - 12:29] So we have to pass this function to the checkout summary component. So we can go to checkout summary component and write the interface.
[12:30 - 12:43] So let's write interface props. And as props, we not only want to send the handle summit function, but also stripe because if stripe is not available, we can disable the button.
[12:44 - 12:53] So let's write stripe, which will have a type stripe, which we can import from stripe. And it can be null.
[12:54 - 13:00] So we can write pipe and null with stripe. We also want to pass the handle submit function.
[13:01 - 13:10] So let's write handle submit. And this function will take event of type synthetic event.
[13:11 - 13:19] It will not take it is already taking a here. We are passing event of type synthetic event.
[13:20 - 13:33] So again, we are mentioning the same thing here. And since we are using asynchronous functions inside, we can write return promise of type void.
[13:34 - 13:42] Now here, let's destructures, type and handle submit. So like stripe and handle submit.
[13:43 - 13:57] And that's destructured it from props. And this function, we can write one click is equal to handle submit.
[13:58 - 14:09] And we can also pass the disabled property, which is equal to opposite of stripe. So if stripe is not available, it will be disabled.
[14:10 - 14:26] Now from our checkout component, we can pass this to our checkout summary. So let's write stripe is equal to stripe and handle submit is equal to handle payment.
[14:27 - 14:36] Now let's open the browser to see if everything is working as expected. So first of all, let's see if is there anything in our terminal and it's fine.
[14:37 - 14:49] Now let's go to the browser. Let's log in as an instructor to be safe instructor and rate test.com and password and rate 123.
[14:50 - 14:57] Now we can add two items to the cart. Let's go to the basket.
[14:58 - 15:15] Let's keep our terminal open to see if there are any errors. Now let's click on checkout to see if the method is successful and yes, we can check the payment intent ID and decline secret.
[15:16 - 15:37] So let's check here and we have the payment intent ID and the client secret. Now we can fill in the information and I will simply write my name and for testing this card, there is a number which you can use for to for to for to for to for to for to for to and this will work for test environment.
[15:38 - 15:51] Expired it can be anything and CVC should be three digits. So I will write 123 and now we can click on make payment.
[15:52 - 16:07] And now as you can see, we have a notification which says your payment is successful and all the methods that we created are giving us 200 status, which means everything is working fine. And also we are pushed to the profile page after the request was successful.
[16:08 - 16:23] So whatever we have created is working fine. We can also check the user courses table and see if we have something added and yes, we do have user ID and course ID because we added two courses to the basket.
[16:24 - 16:26] So everything is working as expected. Let's take it a bit forward in the next lesson.