The proposed application allows users to create and use KANBAN boards. If you are reading this and are unsure what a KANBAN board is then Atlassian provides an excellent explanation that I recommend reading.
The application needs to be able to provide this functionality in real time, without page refreshes that will ruin the users experience. In order to achieve this the application will make use of AJAX. The requests will be received by the server, passed through its routes to the appropriate controller which will handle any business logic that needs to be processed.
At the time of writing the application has over 800 lines of JavaScript so this blog post will not cover everything, just the parts that are important. The modification of the DOM tree by creating HTML elements will not be covered as it is repetitive code that has no interaction with the server. Despite not covering everything, this entry is longer than the other entries in the blog series, this is because it is giving an overview of the most complex page of the application.
The Environment
The Board
The board created has several key parts to it that are highlighted below.
Tasks can be dragged from column to column, with their position updating when dragged. When the user stops dragging a column and 'drops' it into another column an HTTP request is sent to the server telling it to :
'find the task in the database with the ID x and change its column_id foreign key to the value of y'
How this is handled is laid out in this blog entry. A lot of this functionality is handled with JavaScript, which will be covered but the changes are handled and persisted on by the server with Laravel.
CSRF Tokens
There are multiple ways to store a CSRF token on a page, and in hindsight the method that I have chosen is not the most straight forward way however it works and could potentially be refactored although the end result would be the same. In the following image there are several lines that contain @csrf which gets rendered into a hidden HTML Input tag that contains a token ( a string ).
Any HTTP request going to the server that aims to make modifications to the database requires this token so in this instance I created a JavaScript function to pull the token out of the page.
This function finds all input tags with the class name of _token and selects the value from the first one. After looking into this, I found that each CSRF input contains the same value.
Creating A Task
The creation of tasks and columns follows the same pattern with differing implementation specifics, so the creation of a task will be covered as it is more complex than the creation of a column and it encompasses all of the techniques used creating a column with some extras.
To create a task a form is used, however when forms are submitted they refresh the page by default. As previously stated, page refreshes ruin the user experience so this needs to be prevented. The following functions is trigged by an onsubmit event and the first line prevents the page from refreshing when this event occurs.
When a task is created it requires a column_id as a foreign ID, meaning this needs to either be stored when the page is rendered or determined at runtime. As a column can also be created using AJAX it needs to be determined at runtime otherwise new columns would not be able to have new tasks created for them. The following function receives the target of the onsubmit event, which is the form and retrieves the column element that is the parent of its parent. The function then takes this string and pulls out only the numerical values using a basic regular expression. ( You can see examples of it in action here ) Once the function has the value of the CSRF token and the columns ID the HTTP request can be constructed and sent using the fetch API.
This function returns a promise and resolves if the response status code is equal to 201, which means that the task has been created successfully. Any other response and the function will reject with a string message that will ultimately get console.warn() 'ed to the console. This HTTP POST request goes to the servers IP address, passing the column ID and the task name entered by the user in the body. The CSRF tokens value is put into the HTTP requests headers with the key 'X-CSRF-TOKEN', which the server automatically searches for. If this is not present then the server will return an error to the client for security reasons.
Handling The Request
In order to handle the request the server needs to be explicitly told to listen for POST requests on the /tasks route. This is done in the app_route / routes / web.php file by specifying a new route.
Now when the server receives a HTTP POST request with the /tasks route it will pass the request to the TaskController classes store method. Use of this route requires the client sending the request to be authenticated. This functionality is enabled by adding the auth middleware to the classes constructor method.
The store method in the above image parses the body of the request and retrieves the column ID. Following this, the method then attempts to check that this column exists in the database, if it does not it will return an error ( the database will return a foreign key constraint error if the client attempted to add a column ID that doesn't exist in the columns table ). The store method above makes use of a gate to ensure the authenticated user is authorised to add a task with the given column ID, these are covered in more detail in the previous blog entry.
If the server responds with an HTTP status code of 201 then the client will generate a new task element on the screen without a page refresh by modifying the DOM tree, and will add a new hidden CSRF input to the element as well so that it can be instantly functional without requiring php to re-render the page.
Deleting A Task
Deleting a task follows the same format as creating a task however the HTTP request differs in some ways.
The request uses the tasks ID in its body again however the HTTP method used this time is not a POST request but a DELETE request. The route differs slightly as well, in a way that simplifies the logic contained within the destroy method in the TaskController file.
The $task argument is equal to the task ID that was contained within the route passed as an argument to the fetch method. This method also uses an auth gate that prevents unauthorised users deleting content that belongs to other users. When the record is deleted successfully an HTTP response is sent back to the client with a status code of 200. When the client retrieves this the task element is removed from the DOM tree in real time.Concluding Remarks
Pairing AJAX requests with a Laravel backend is an easy procedure. If certain actions require authorisation then providing this authorisation is a simple process that involves sending the value of the CSRF token in a header with the right name and mounting the auth middleware in the given controller. Implementing the functionality required for the application was not a difficult process, it was timely due to the amount of JavaScript required however the amount of php required to handle the requests was minimal.
This is another example of Laravel shining by abstracting away a lot of the complexity that the developer generally does not need to worry themselves with.
Comments
Post a Comment