Testing HTTP APIs

Pro Members Only

This lesson is available if you have an active subscription.

Alternatively, some member might be able to gift it to you.

If you already have a subscription, you can sign in.

Testing HTTP APIs

javascript
typescript
react
playwright

Enjoy free content straight from your inbox 💌

No spam, unsubscribe at any time.

Transcript

00:00

HTTP APIs are a core part of modern web development. A great thing about playwright is that in addition to testing the user interface of our web application, we can use it to easily test HTTP APIs as well. To demonstrate this, we have a very simple to-do MVC style application that works on top of an HTT PAPI. When the application loads, it requests all the currently defined to-DOS by making an HTP call to get all. You can see that the application is currently not showing any to-dos and this is verified by the get all response as well, which returns an empty items array.

00:33

Now let's add a simple to-do into the ui, for example, by milk. This makes an H TT P call to the add endpoint and sends the payload with a message containing the string by milk. The server adds this to do item into the database and returns its ID for future reference. A third API that this particular application uses is the set all API. This comes into action. For example, if we mark all of the to-dos as completed here you can see that a request has been made to the set all API with an updated list of to-dos such that all of the items have completed set to true

01:07

for this particular API. The server simply responds with adjacent payload with status success. While it's a good idea to understand the objectives of an API from a user interface viewpoint, when you are working on the API, it is best to play around with data in isolation. There are lots of tools for this, but for this demo we will be using a simple visual studio code extension called REST Client. As you can see, it is a very popular extension and just to make it easier for you to find here is a visual reference for what the current extension homepage looks like.

01:39

This extension works on top of HTTP files, so we created a new one called SPECT htp. Within our project, we create a simple variable that will point to the main API route and this will make our specification more easier to maintain in the long run. The first API that we have in our application is the get all API and it simply consists of the API endpoint followed by slash get all. And here we are making a simple HTDP get request. For the add method we make an HTP post request to the slash add API and this accepts adjacent payload and here we are hard coding one with a message by milk.

02:16

And finally we have the set all API, which is a put method that also accepts adjacent payload. And here we are providing an empty items array to essentially clear any to-dos that the server might currently have. We currently have no dues in the backend, so if you make a get all request, you can see that we get back an empty items array. Next we added A to do to buy milk and the server comes back with a new ID for this to do. Now if you try to get all the to dos, you can see that the items array consists of the single to do buy milk. Finally, if you send a request to set all with an empty items array

02:49

and then try to get all the to-dos, we get back an empty items result, which is exactly what we expect. Now that we understand the API that we want to validate, let's Create a simple playwright test to ensure that our API continues to work as expected. We start off with an empty playwright test file called API spec ts. We bring in the usual suspects of test and expect from playwright test and then we define our first test, which verifies that we should be able to clear all the current items just like we have previously accepted the page fixture within our playwright test.

03:22

Hey, we are accepting the request fixture. We use the request object to make HDP requests. For example, we can make a put request to the set all API and provide it a data payload that consists often empty items array. This comes back with a promise and we simply await that to get the final response. The response has a number of methods on it. For example, we can use response okay to make sure that the response succeeded. We can additionally look at the status by itself as well and we expect the status for this particular HTP response to be 200. And similarly we can even pass the response as the JS object

03:58

by using the JSON method, which again returns the promise and we simply get that final value by using a weight. In this particular case, we are asserting that that response object is going to be equal to status success to ensure that this does indeed clear all the items in the backend, we make another get request to the get all API endpoint. We make sure that that is okay and that is status 200. And then we also ensure that the response contains an empty items array, thus verifying that the set all works as expected. And now for the moment of truth,

04:31

let's just execute this test using playwright. And as you can see, it passes with flying colors and also it runs extremely quickly. With playwright, it is perfectly fine to create local utility functions in our test files. Additionally, in this particular example, playwright is installed as a part of our web application, which is something that we covered in a previous lesson. So we can even take it a step further and bring in some common types to make it easier to create these utilities. And then to write these tests within an empty spec file, we bring in the usual suspects of test and expect,

05:04

but we also bring in an additional import called API request context. This is the type that represents the request fixture that we previously used in our test function. Next we bring in some types for the common data structures within our application. This includes the to-DO item type as well as the request and response structures for the set all add and get all HTT P endpoint. We define our API route as a simple variable so that we don't need to keep copy basing this all over our code base. And then we define our first utility function called set. All this function expects

05:37

to be passed in the request fixture which we annotate as API request context and then a data payload which we annotate as set all request. The body of this utility function is going to be pretty simple. We use the request object to make a put request to API slash set all and provide it the data payload. Then we simply return an object consisting of the response as well as the past Jason, which we annotate as set all response. Now that we have this utility created, the other utilities are going to follow a similar pattern. We have the ad utility which takes the request fixture.

06:12

A data of the type ad request makes a request using post to the add endpoint, providing the data payload and then again returns the response in the past. Jason, finally, we have a utility for our get all endpoint, which only takes a request fixture as the get endpoint doesn't take any payloads and we simply use request dot get to get the response and again once more return the response and the pass Jason And that's it for the utilities. Next. To make it easier to test the different behaviors before each test, we use the request fixture

06:45

and then use our set utility to clear any previous to-dos that might be hanging around. We can verify that this set all clearing is working as expected and also sort of ensure that the get all method is working by simply getting all of the to dues, checking that the response is going to be okay, the status is going to be 200 and that the J payload will equal an empty items array. Next discreted test to make sure that the add endpoint is also working as expected. We invoke the add utility with the request and a simple payload that consists of the message test

07:18

and then we expect the response to come back with adjacent payload such that it has an ID which should be of some string. Expect out any creates something which payout calls an asymmetric match. And essentially this is making sure that the ID should match anything that has been created using the built-in string type. Additionally, after we've added this message test, if you try to get all the items, the response Jason should come back with an items array which could consists of a single item with an of type string completed falls and the message test, an additional behavior worth testing.

07:54

Is that set all it should be able to update all of the items present within the to-dos. So for this particular test we add a simple to-do with the message test, then we get all the to-dos from the backend, load up the first item and modify it so that the completed property turns to two. And then we make a request to set all with this updated item. And now if you make a request to get all again, then the response should match this updated items array. There are lots of other tests that we could write for this API as well, but these cover it enough

08:26

to give us confidence in its current usage. And now for the moment of truth, let's just run all of these tests within API spec TAs through playwright. And no surprise, all of them pass because our API is working as expected and our tests are making sure of that simple fact.