import { addBanner, addArticle, addTitle, addHeader, addParagraph, addClassParagraph, addCaption, addSubHeader, addOrderedList, addUnorderedList, addBlockquote, addQuote, addInset, addInsetList, addInsetCodeListing, addInsetBulletList, addImageWithCaption, addButtonGroup, addSidebar, addSyntax, menu, global_menu } from '/scripts/import.js';
import { local_menu } from '/scripts/webdev.js';
const heading = document.querySelector(".heading");
const global = document.querySelector(".global_menu");
const local = document.querySelector(".local_menu");
const sidebar = document.querySelector(".sidebar");
const main = document.querySelector(".main_content");
heading.append(addTitle("Learning REST APIs"));
heading.append(addParagraph("Morten Rand-Hendriksen - LinkedIn Learning - February 2018"));
heading.append(addParagraph("Chapter 2 - Request"));
main.append(addHeader("Anatomy of a REST Request"));
main.append(addParagraph("For this part of the course, we will need access to some sort of API so that we can test requests. The course video uses the API for a local installation of WordPress but I will be using either the same API as I used for the course Introducing Postman or the REQ|RES API."));
main.append(addParagraph("A request is made up of two parts, the HTTP method and a URI. To demonstrate this, recall the request we sent from Visual Studio Code as shown in figure 7. As a reminder, the request is"));
main.append(addSyntax("GET https://reqres.in/api/users"));
main.append(addParagraph("This might be a bit of an over-simplification because the URI can be a lot more complex, we might add parameters to the URL for example. Nevertheless, the distinction is important and we can see that here with the GET method and a relatively simple URI. Let's look at another example."));
main.append(addSyntax("GET http://localhost:3000/api/boards"));
main.append(addParagraph("The request along with its response is shown in the image taken from Visual Studio Code in figure 8."));
main.append(addImageWithCaption("./images/vsc1.png", "Figure 8 - the response and request showing a list of boards from the API."));
main.append(addParagraph("This is a very simple and straightforward request but we can also send some metadata with the request in the form of headers. To send a request that updates an existing record in the API's database, this gets more complicated again because we have to send the data we want to be inserted into the database and we would normally use the POST method for that."));
main.append(addParagraph("When including headers and/or parameters in a request, you would normally do that via some type of script, usually using JavaScript. In plain old JavaScript, the request shown in figure 8 would look something like this."));
main.append(addInsetCodeListing([ "var xhr = new XMLHttpRequest();", "xhr.open(\"GET\", \"http://localhost:3000/api/boards/\", true);", "xhr.onload = function() {", " console.log(xhr.responseText);", "};", "xhr.send();" ]));
main.append(addParagraph("Calling a request from JavaScript is something I have never done before so I tried to do that in a way that seems sensible and it does seem to have almost worked! I did that by creating two functions in a JS script. The reason I created two is because I wanted to use one to send the request and get the response in a way that could be displayed and the second is used to create a paragraph. The idea is that the JavaScript file that is used to generate the content for this page, can call what is essentially a helper function to generate an appropriate HTML element to be added to the relevant HTML document (that is, the HTML page this file is generating)."));
main.append(addParagraph("The getBoards function is imported into the file generating this page which should allow me to call the function with something like"));
main.append(addSyntax("main.append(getBoards());;"));
main.append(addParagraph("You can view these functions by clicking here to open up a page entitled sample1 which displays the contents of the JavaScript file."));
main.append(addParagraph("Trying to make this call is generating a CORS error at the moment because the browser sees the localhost as being from a different source than this website. Fixing this is beyond the scope of the course, at least at this point, so I will just nte that it is possible to call the function from the webpage and more information can be found in the MDN Web Docs under Reason: CORS header 'Access-Control-Allow-Origin'missing. From here, I can see that a header needs to be set and this should be:"));
main.append(addSyntax("Access-Control-Allow-Origin: https://localhost:3000/"));
main.append(addParagraph("I'm not completely sure if the port number is required there. Doing a little research, I found that you can add a heeader to the request with a command such as:"));
main.append(addSyntax("xhr.setRequestHeader(\"Access-Control-Allow-Origin\", \"https://localhost:3000/\")"));
main.append(addParagraph("Adding this to the request doesn't work, which is actually what I expected because I would assume that the API should set the parameters for what requests are allowed or not allowed rather than letting the request to confirm whether it was allowed to access the site. As a matter of interest, the full error is:"));
main.append(addSyntax("Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:3000/api/boards/. (Reason: CORS request did not succeed). Status code: (null)."));
main.append(addParagraph("So that is a GET request, and as you can see, it can start to get a little bit complicated. If we want to issue a POST request, it does get a little bit more complicated again, but I don't want to delve too deeply into this as we did with the GET request. We might use something like Ajax in jQuery to send a POST request and it should look something like this."));
main.append(addInsetCodeListing(["$.ajax({", " url: \"https://site.com/wp-json/wp/v2/posts\",", " type: \"POST\",", " date: {", " title: \"Angela creates a new new task generated from the REST API\",", " content: \"This is the content for the new post.\",", " author: 10,", " },", " success: function(response) {", " console.log(response);", " }", "});"]));
main.append(addParagraph("Briefly, what we are doing here is:"));
main.append(addInsetBulletList(["Defining a URI", "Send a POST request to that URI", "Adding some data to it", "If the request is successful, capturing the response to be logged in the console."]));
main.append(addHeader("Discovery"));
main.append(addParagraph("Recall that one of the constraints associated with REST is that it shouldprovide a guide to its use by providing the user with links to available resources. In many cases, the API will provide extensive online documentation, but it should be self-descriptive, allowing you to discover things like what resources are available and what methods you can use, even if there is no documentation."));
main.append(addParagraph("The first step in doing that is to use the OPTIONS method. For example, consider this request."));
main.append(addSyntax("GET http://localhost:3000/api/boards"));
main.append(addParagraph("This returns a list of boards from the API from the Introducing Postman course and note that it uses the GET method. If you want to know what other methods you can use, you can find out using the OPTIONS method like this."));
main.append(addSyntax("OPTIONS http://localhost:3000/api/boards"));
main.append(addParagraph("The request and response are shown in figure 9."));
main.append(addImageWithCaption("./images/options.png", "Figure 9 - the response and request showing the available methods for boards."));
main.append(addParagraph("In this case, the methods we can use are GET, POST and HEAD. This is a really sumple sample API so we are not seeing very much in the response but you may also see more extensive descriptions of these methods and the parameters that you can use with them. In essence, this means that if you are working with a REST API without amy documentation, you can simply ask it to provide the details you need to at least begin experimenting with it."));
main.append(addSubHeader("Resource"));
main.append(addParagraph("In this section, we will dig a little deeper into what is meant by the terms, Resource and Representation."));
main.append(addSyntax("Resource"));
main.append(addParagraph("The following quote shown in figure 10 is taken from a dissertation by Roy Fielding, the originator of the REST architectural style. The title of the dissertation is Architectural Styles and the Design of Network-based Software Architectures."));
main.append(addQuote("The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. \"today's weather in Los Angeles\"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource. A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time.", ""));
main.append(addQuote("More precisely, a resource R is a temporally varying membership function MR(t), which for time t maps to a set of entities, or values, which are equivalent. The values in the set may be resource representations and/or resource identifiers. A resource can map to the empty set, which allows references to be made to a concept before any realization of that concept exists -- a notion that was foreign to most hypertext systems prior to the Web [61]. Some resources are static in the sense that, when examined at any time after their creation, they always correspond to the same value set. Others have a high degree of variance in their value over time. The only thing that is required to be static for a resource is the semantics of the mapping, since the semantics is what distinguishes one resource from another.", "Figure 10 - Roy Fieldings definition of a resource - Fielding, Roy Thomas. Architectural Styles and the Design of Network-based Software Architectures. Doctoral dissertation, University of California, Irvine, 2000."));
main.append(addParagraph("The key concept here is that of a conceptual mapping. If we skip back to our analogy of REST as a librarian. Let's say that there is some resource, a red book, and it is located in cubby number 4. The resource is the red book in cubby number 4, but this doesn't take into account the contents of the book. We could switch this out for another book in the same location and the resource is pointing to that new book. The resource, in other words, is the item itself, the red book, and its location, cubby number 4. If we move that book to a new location, let's say cubby number 2, the resource is now the red book in cubby number 2."));
main.append(addParagraph("This might seem strange in that your intution is probably telling you that this is the same resource in both instances, just in diffrent locations. However, bear in mind that if you have an API that is being used to deliver some service, in other words, making some resource or resources available over the internet, in order to provide that service, the API will need to know where the resource is. Furthermore, in this example, the resource corresponds roughly to a physical item - a book in this case - but a resource could just as easliy be some data such as a weather forecast, a book review and so on. Consider a resource provided by this website (it's not something that can be described as a REST resource because this is not a REST API, but the principle applies)."));
main.append(addParagraph("In figure 9, shown above, we have an image and that image has a filename which is options.png. It can be displayed in this page because there is an image element in the HTML with a src attribute telling the server where to locate that file. Either of these on their own would not allow a web server to display the image. With just a location, it wouldn't know which image to display and with just a filename, it wouldn't know where to look for the image."));
main.append(addParagraph("One other point to remember about resources is that a resource can be a single item like the red book in cubby hole 4 or it can be a collection such as all red books in the library."));
main.append(addParagraph("In terms of location, this will often be a bit more complicated than just cubby hole 4 and bear in mind that it may not correspond to a physical location or even seem to. What I mean by that is that the rec book in cubby hole 4 sounds like it is describing a physical object in a real location. If we were representing this in an API, we would probably have a folder representing a bookcase which contains a folder containing books and we might subdivide these further so that we have folders for red books, green books, blue books and so on. You might see that this suggest a hierarchical structure with the mist general location being at the top level and the most specific (that is, the folder that contains the book) at the bottom so we are starting with the most general location and narrowing this down to the most specific."));
main.append(addParagraph("Let's say that our book is a pdf file caled book1.pdf and is stored in a folder called 4 which is inside a folder called cubby and this, in turn, is inside the books folder. The resource would therefore be"));
main.append(addSyntax("bookcase/books/red/cubby/4/book1.pdf"));
main.append(addHeader("Representation"));
main.append(addParagraph("Fielding's definition of Representation (or part of it) is shown in figure 11."));
main.append(addQuote("REST components perform actions on a resource by using a representation to capture the current or intended state of that resource and transferring that representation between components. A representation is a sequence of bytes, plus representation metadata to describe those bytes. Other commonly used but less precise names for a representation include: document, file, and HTTP message entity, instance, or variant.", "Figure 11 - Roy Fieldings definition of a representation - Fielding, Roy Thomas. Architectural Styles and the Design of Network-based Software Architectures. Doctoral dissertation, University of California, Irvine, 2000."));
main.append(addParagraph("This is essentially a fancy way of saying that when we access a resource, we don't access the actual data of that resource, but rather a copy that can be tailored specifically to our requirements within the constraints of the API. For example, the data might be records in a database, but the representation might be provided as an HTML table with appropriate headings. This also means that a REST API can simultaneously server different views of the same data to multiple clients."));
main.append(addParagraph("Summing up, a resource is some data in a specified location, a representation is the view of that data which the API serves to the client."));
main.append(addHeader("Methods (Verbs)"));
main.append(addParagraph("Whenever you interact with an API, you do that using some HTTP method such as GET or POST. Actually, this also applies when you are using a web browser to access an Internet site where you might be sending a GET request in order to retrieve the web page specified by the URL you entered into the browser. Note that in the case of a browser, the browser handles this so you don't have to explicitly specify that you want to send a GET request when accessing a site or a POST request when submittingh a form."));
main.append(addSubHeader("GET"));
main.append(addParagraph("The GET method simply says here is the address of some resource, please return that resource to me (the resource might be a web page, a pfd file, a weather forecast or anythung else that falls into the definition we gave for a resource). If the request is successful and the resource is found and returned to you, it will also be returned with a 200 status indicating that everything is okay. If it isn't, for example if the resource cannot be located or is invalid, you will get a 404 response which you may have seen when typing a URL incorrectly into the browser's address bar."));
main.append(addParagraph("There are three different methods the client can use to send data to the server and these are POST, PUT and PATCH."));
main.append(addSubHeader("POST"));
main.append(addParagraph("POST is used to create new resources and to add to existing resource collections. As an example, if you have a collection of product records store on the the internet and you want to add a new product record, you would use the POST method. The POST method is sent along with the product data in JSON format and the REST API will create the new resource and give it an id and a URI. If the request is successful, a 201 response will be returned indicating that the resource was successfully created. There are a number of reasons why a POST request might fail, so there are several possible responses including"));
main.append(addInsetBulletList(["401 - Unauthorized", "409 - Conflict", "404 - Not Found"]));
main.append(addSubHeader("PUT"));
main.append(addParagraph("A PUT request is similar to a POST request, but it is intended to update content by replacing an existing resource with the data passed to it with the request. For that reason, a PUT request sends the URI of the resource to be updated along with the contents. A successful PUT request will return a HTTP 200 status for OK and it may return a 204 status to indicate that the resource content cannot be found. Notice that this is not an error response and this is because the API may allow a new resource to be created with the provided URI. If the resource cannot be located, a 404 status us returned."));
main.append(addParagraph("You can only use a PUT request with a singleton resource, so another status you may see returned is 405, indicating that the method is not allowed and you will see this if you try to send a PUT request to a collection."));
main.append(addSubHeader("PATCH"));
main.append(addParagraph("As noted, PUT updates a resource by replacing the entire resource with new data that you provide. For example, the resource might be an address and so PUT overwrites the address with the new address sent with the request and so that address must be complete. With PATCH, you can send along instructions for replacing the data that you send so you can modify a resource without replacing it entirely. For example, if you want to update the postcode for an address, you can send a patch address with the new postcode and an instruction to update the postcode field. The responses you will see for a PATCH request are the same as those you might see for a PUT request."));
main.append(addParagraph("Like PUT, PATCH can also be used on singleton resources only so the possible responses include the 405 response."));
main.append(addSubHeader("DELETE"));
main.append(addParagraph("As you might expect, DELETE will delete the resource with the provided URI. It can also only be used with a singleton resource, so you will see a 405 response if you try to use it with a collection."));
main.append(addSubHeader("OPTIONS"));
main.append(addParagraph("This is a less common method and it restunrs a description of the communication options with the resource that you provide the URI for."));
main.append(addSubHeader("HEAD"));
main.append(addParagraph("Again, this is not a commonly used method. It is similar to the OPTIONS method but it only returns the head section of the response that you would see returned by OPTIONS."));
addSidebar("webdev");