-
Okay, next within our API difficulties controller, let's take care of our store method, which is in charge of creating a difficulty.
-
Now, as part of the previous series, we did set up validators as well as actions for these CRUD based operations, which will simplify all of this for us.
-
So for example, we can get the validated data by doing const data equals await request, validate using and reach directly for our difficulty.
-
And you can see that we have a validator for destroy, order update, and then our overall difficulty validator there, which we can import and use here. If we take a look at what this is defining
-
and go ahead and scroll on down to the bottom, we can see that this is exporting a const difficulty validator, where it's setting up an object with a name field and a color field. The name field has a max length of 50
-
and the color field has a max length of 20 and also specifying that it should be a hexadecimal code. So the data that we're going to end up getting back is going to be an object with a name of string
-
and a color of string. Those are all defined within our validators folder within our app directory. In addition to that, we also have actions for all of our different resources here.
-
And let's take a look at our difficulties. So for our difficulties, we have an action for destroying, storing, updating a difficulty order, and then updating an overall difficulties data.
-
These actions take care of the overall operation that we're going to need to do to store a difficulty, update a difficulty, destroy a difficulty, so on and so forth. We set all this up in the previous series.
-
So if you're interested in why we're doing any of this or what we're doing here, be sure to check that series out. Even if you're not interested in the inertia stuff, you can still check out the operational logic
-
that we're doing inside of AdonisJS throughout that series. So we're going to be able to make use of these actions throughout this series as well, since they're isolated in scope in what they do.
-
The store difficulty is simply going to create a difficulty. It's going to take in the data that it needs to do such a thing and then perform that operation, kicking back related data to us.
-
And then if you're not familiar with actions, they are just very specific classes that perform a single operation. It's similar to services,
-
except a single service method here would be a class. And then the service itself would be similar to a folder, just an alternative way to structure code there. So back inside of our difficulties controller,
-
what we need to do with this validated data is get back our newly created difficulty by doing await store difficulty. Let's run the handle method from that action
-
and pass in our organization and that validated data. Now we need to grab our organization out of our HTTP context. So let's go ahead and do that and then pass that into the handle method.
-
So organization and then data just like so, and that should return back to us our brand new created difficulty, which in turn we can go ahead and return back
-
as our response for our storage. So our store API endpoints ultimately going to end up returning the newly created difficulty from the store operation.
-
We set up our resource within our version one routes. So the route definition for this is already good to go. So let's go ahead and jump back into Hopscotch here. I've got it back in full screen mode
-
to give us a little bit more working room. And one thing that we did not do is save our previous difficulties get request. So let's go ahead and do that here.
-
Let's do save as and do get difficulties. And then we want to create a new collection for it, which will be our difficulties collection. Go ahead and save that.
-
And we can select that collection to house it within. Hit save there. And now we have a difficulties folder over here inside of our collections panel. All right, cool.
-
Now there's several different options that we have for getting these headers shared between these requests. So one easy way to get a new request with all of our previous header data
-
is to just right click and we can duplicate that saved request. So now we have get difficulties duplicate and we can switch this to instead be called
-
store difficulties, save that, let's open it up. And now we need to switch the HTTP method from get to post. And in addition to our header information,
-
we also want to provide body information here as well. In order to add a body from the content type select, we'll select the appropriate content type that we want to send up. Since this is an API,
-
application JSON is most likely going to be the use case that we want there. But you also have typical form based options down here as well,
-
if you want to use a REST client to mimic form data. Okay, so let's go and select application JSON and that's going to give us a little JSON text editor here.
-
We can provide in an object with a name and we'll call this API test one and a color and we'll provide something invalid.
-
So I'm not a hex code there. If we go ahead and send this up, we get back a response redirecting to home path. Now, the reason that you might be thinking we're getting this redirection response
-
rather than the actual application JSON of our validation error is because we have forgotten to add in the accept header with application JSON specified for content negotiation.
-
However, if we were to actually add that into our headers array, you're going to see that we're going to get back the exact same response as before. And that's actually because there's a server issue
-
at play here from our web application and that's our CSRF protection. It didn't apply up until this point because CSRF protection by default
-
is only enabled for post, put, patch and delete requests, which thus far we've just been working with get requests. Because up until this point, this has just been a web application.
-
We haven't adjusted anything within our shield or protective middleware to allow API based access, which won't have access to a CSRF token.
-
We can verify that this is the issue by jumping into our terminal and we'll see that we have some invalid or expired CSRF token warnings directly inside of here. So in order to fix this,
-
what we want to do is jump back into our text editor, jump down into our configuration and we should jump into our shield configuration down here.
-
You'll see that we have CSRF enabled right here with the methods post, put, patch and delete. So since we're sending a post request,
-
this is now what we're running into with our API. So within our accept routes, let's go ahead and switch this to a callback function that takes in our HTTP context
-
and do ctx request URL dot starts with slash API. Now, any request that comes through our application
-
where the URL starts with slash API, which is going to be all of our API routes, AdonisJS will now exclude them from our CSRF requirement altogether,
-
meaning that we should no longer get an invalid CSRF token with our API requests. Now, if the application interfacing with our API was inside the front end of this application itself, we wouldn't need to worry about this
-
because we would be able to send the CSRF token either via an XSRF cookie or directly within the header information or to the script itself to that front end
-
to interface with our API and use this CSRF token. Since however, the applications interfacing with our API
-
are going to be external applications from this application, we're going to be explicitly dealing with cross site requests.
-
So CSRF protection is not applicable to those. So we'll go ahead and save this, excluding our API endpoints from our CSRF protection, and we can close out our shield
-
and we can close out our configuration and let's jump back in the hopscotch and let's try sending this now one more time. And cool, now we get back a JSON response. Let's switch over to JSON view
-
to make it a little bit easier to read with an errors array stating that the color field must be a valid hex color code. It gives us back the rule that it errored out on
-
as well as the field name from our body. So awesome, that's all now working perfectly fine. And the error that we get back is a 422 unprocessable entity,
-
noting that it's a validation error. So let's go ahead and switch our color now to a valid hex code. So maybe EBEBEB, I think that's a gray, but nonetheless, it's a valid hex code.
-
And let's go ahead and send that off now. And we get back the newly created difficulty with our response with an ID of nine,
-
a color of EBEBEB and a name of API test one. Furthermore, we get back a status of 200, which is okay. Awesome, let's go ahead and save that request now
-
into our difficulties collection. Now that we have that working, before we round out this lesson, an alternative approach to keeping our headers propagated continuously throughout all of our requests
-
is to define them at the collection level. So if we go into the more options of our collections, go into the properties, we have the ability to select headers
-
at the collection level. As it notes, this header will be set for every request in the collection. So that we don't have to do that for all of the resources that we have,
-
we can create an overarching collection for our application, which we'll just call API. Go ahead and save that. And let's move our organizations into our API collection
-
and our difficulties into that API collection as well. Now we have our organization and difficulties nested within the API collection, with which we can add a new property
-
with a header set to accept application JSON, so that we have that automatically set for all of these. And then if we want to authorize all of these as well,
-
we can set authorization and then reach for our token environment variable and give that a save. Now, one thing that would be better, which I accidentally did in the last lesson
-
is rather than defining our token directly as a variable is to make it a secret instead. That way it's not synced anywhere with Hopscotch here. So we can go ahead and clear out
-
our token environment variable, switch over to the secrets tab. As it notes, secrets are not synced to Hopscotch. So let's go ahead and plop this in there, call it token yet again,
-
and plop the secret value in there. We can show it real quick to make sure it looks okay and all looks good. So we should be able to save that and our token should now still exist,
-
but it will now treat it as an actual secret, not actually showing it to us and not actually syncing out the Hopscotch. So since we're still in development here, that's not a huge hiccup, but if you're working with a production token,
-
that's best to do it as a secret there within your environments. Okay, so back into our collection, since we have these headers defined
-
at the API collection level, they should now cascade through to all requests within here, meaning that if we get rid of our authorization
-
and our accept header, switch over to our body now and switch this from API test one to API test two, send this off one more time. Ah, fudge. It looks like we actually do get
-
an unauthorized access error. Let's head back over to our headers. If we go ahead and try and close this out, let's see if we can just reload it.
-
I'm going to bypass saving changes just in case. Let's go ahead and reopen it, take a look at our headers and okay, yeah, that doesn't seem to be coming through as expected,
-
but I think if we go ahead and delete this store difficulties and we create a new request and we'll call this store difficulties here,
-
create it, we'll open it up, see headers. Okay, we have an accept header that came through and an authorization token header. No, ah, there we go. Okay, so we remove that. It is down there.
-
I just had to scroll a little bit. So now these are properly coming through from our API collection level as automatic headers. Let's see if we hover over the info icon here,
-
we get this header is inherited from a parent collection API. So now these will be automatically set with any requests that we define from here on out. We'll go ahead and just leave our get difficulties
-
and get organizations as is. No need to change that. We can switch this back to a post, give ourselves a application JSON body back
-
with an object, a name of API test two
-
and color of, and I'll just do EBEBEB again for lack of being able to come up with a better color. Okay, we'll go ahead and send that off
-
just to make sure everything's working and cool. We do get back our API test number two. So that is indeed working. Go ahead and save that to update it within our collection store.
-
And we're now good to move onward.