Organizing Your API Tests

One of the things that makes me happy about API testing is how easy it is to organize tests and environment variables.  I love having test suites ready at a moment’s notice; to run at the push of a button when regression testing is needed, or to run automatically as part of continuous integration.

This week I’ll be talking about some organizational patterns you can use for your API tests.  I’ll be discussing them in the context of Postman, but the concepts will be similar no matter what API testing platform you are using.

First, let’s discuss environments.  As you recall from last week’s post, an environment is a collection of variables in Postman.  There are two different ways I like to set up my Postman environments.  In order to explain them, I’ll use some scenarios.  For both scenarios, let’s assume that I have an application that begins its deployment lifecycle in Development, then moves to QA, then Staging, and then Production.

In my first scenario, I have an API that gets and updates information about all the users on my website.  In each product environment (Dev, QA, Staging, Prod), the test users will be different.  They’ll have different IDs, and different first and last names.  The URLs for the product environments will each be different as well. However, my tests will be exactly the same; in each product environment, I’ll want to GET a user, and PUT a user update.

So, I will create four different Postman environments:
Users- Dev
Users- QA
Users- Staging
Users- Prod

In each of my four environments, I’ll have these variables:
environmentURL
userId
firstName
lastName

Then my test collection will reference those variables.  For example, I could have a test request like this:

GET https://{{environmentURL}}/users/{{userId}}

Which environment URL is called and which userId is used will depend on which Postman environment I am using.  With this strategy, it’s easy for me to switch from the Dev environment to the QA environment, or any other environment.  All I have to do is change the Postman environment setting and run the same test again.

The second scenario I use is for situations like this one: I have a function that delivers an email.  The function uses the same URL regardless of the product environment. I like to pass in a timestamp variable, and that stays the same (it shows the current time) regardless of what environment I am using.  But I like to change the language of the email depending on what product environment I am in.

In this case, I am creating only one Postman environment:
Email Test

My one Postman environment has this variable:
timestamp

My test collection, however, has one test for each product environment.  So I have:
Send Email- Dev
Send Email- QA
Send Email- Staging
Send Email- Production

Each request includes the timestamp variable, but has a variation in what is sent in the body of the email. For the Dev environment, I use a request that contains “Dev” in the message body, for the QA environment, I use a request that contains “QA” in the message body, and so on.

When deciding which of these two environment strategies to use, consider the following:

  • what stays the same from product environment to product environment?
  • what changes from product environment to product environment?
If there are many variables that change from product environment to product environment, you may want to consider setting up multiple Postman environments, as in my first scenario.  If there are only one or two things that change from environment to environment, and if the URL doesn’t change, you may want to use the second scenario, which has just one Postman environment, but different test requests for each product environment.
Now let’s talk about ways to organize our tests.  First, let’s think about test collections. The most obvious way to organize collections is by API.  If you have more than one API in your application, you can create one collection for each of the APIs.  You can also create collections by test function.  For example, if I have a Users API, and I want to run a full regression suite, a nightly automated test, and a deployment smoke test, I could create three collections, like this:
Users- Full Regression
Users- Nightly Tests
Users- Deployment Smoke
Finally, let’s think about test folders.  Postman is so flexible in this area, in that you can use any number of folders in a collection, and you can also use sub-folders.  Here are some suggestions for how you can organize your tests into folders:
By type of request: all your POST requests in one folder; all your GET requests in another
By endpoint: GET myapp/users in one folder; GET myapp/user/userId in another
By result expected: GET myapp/users Happy Path requests in one folder; GET myapp/users bad requests in another folder
By feature: GET myapp/users with a Sort function in one folder, and GET myapp/users with a Filter function in another
As with all organizing efforts, the purpose of organizing your tests and environments is to ensure that they can be used as efficiently as possible.  By looking at the types of tests you will be running, and what the variations are in the environment where you will be running them, you can organize the Postman environments, collections, and folders in such a way that you have all the tests you need immediately at your fingertips.
Next week, we’ll be talking about running collections from the command line, and setting tests to run automatically!

Using Variables in Postman

This week, we’ll be talking about the many ways to use variables in Postman. We’ll be using the collection that we created a few weeks ago, so you may want to check that tutorial out before reading on.

The first thing to understand about variables in Postman is that they are organized into environments. A Postman environment is simply a collection of variables that can be used to run against a Postman collection. Creating an environment is easy! Click on the gear button in the top right corner of the window, and then click the “Add” button. Give your environment a name, such as “Pet Store”, and then click “Add”.

An environment isn’t helpful at all unless you give it some variables, so let’s add a variable now. After you added the new environment, you should have been returned to the “Manage Environments” popup window; click on your new environment to edit it. In the “key” section, add petId, and in the “value” section, add 100. Click the “Update” button, and your new variable has been added.

Close the “Manage Environments” window. In the upper right corner, you’ll see a dropdown selector, which currently says “No Environment”. Click on this selector and choose “Pet Store”. Now when you run requests in your Pet Store collection, it will run them with this Pet Store environment.

We have one variable set up now: petId, which equals 100. Let’s see all the different ways we can use this variable!

First, we can use it in the URL. In your “Verify Add Pet” request, change the URL from http://petstore.swagger.io/v2/pet/100 to http://petstore.swagger.io/v2/pet/{{petId}}.  When you add in the variable, you will see {{petId}} turn to orange. This is because Postman recognizes the variable from the current environment. If you ever forget to set your environment (an easy thing to do), you will see that the {{petId}} will be red. Save your changes, and run your request (you may need to run the “Add Pet” request first, so there will be a pet with an id of 100). You will see that the request was made for the pet with the id of 100, and that is what is returned in the response.

You can also use a variable in this way in the request headers. We won’t be doing that in this collection, but one example of how this can be used is if you need to send an authentication token with a request. Rather than typing in the token every time, you can save it as a variable named “token”, and then pass it in with the header like this: {{token}}.

Getting back to our petId variable, we can use it in the request body as well. Let’s open up the Add Pet request, and change the body of the request so it looks like this:

{
  “id”: “{{petId}}”,
  “category”: {
    “id”: 1,
    “name”: “Cat”
  },
  “name”: “Grumpy Cat”,
  “photoUrls”: [
    “https://pbs.twimg.com/profile_images/948294484596375552/RyGNqDEM_400x400.jpg”
  ],
  “tags”: [
    {
      “id”: 1,
      “name”: “Mixed breed”
    }
  ],
  “status”: “available”
}

We’ve replaced the id of 100 with our petId variable. You can see how using a variable like this would be helpful in testing. Suppose we decided that we didn’t want to add a pet with an id of 100, and we preferred to use some other number instead. It will be easy to change this, because now all we have to do is change the variable in one place (the Pet Store environment) rather than in every request where 100 was used. Be sure to save your Add Pet request.

Another place we can use this petId is in our assertions. Return to the Verify Add Pet request, and add this assertion to the Tests section:

var jsonData = JSON.parse(responseBody);
tests[“Correct pet ID is returned”] = jsonData.id == environment.petId;

You may notice that this assertion is different from the other assertions we have in this request. The other assertions are written in the new Postman assertion style, and this assertion is written in the old style. (If any of my readers knows how to do this assertion in the new style, please let me know in the comments section!) What this assertion does is compare the id value returned in the body of the response (jsonData.id) with the id value set as an environment variable (environment.petId). Save this request and run it, and you should see that this assertion passes.

Finally, we can set environment variables based on the body of a response. Let’s duplicate our Add Pet request (see instructions in Creating a Postman Collection for how to do this), and we’ll rename our copied request “Add Pet With No Id”. We’re going to use this request to add a pet without specifying the id, letting the program assign an id for us. Change the body of the request to:

{
  “category”: {
    “id”: 1,
    “name”: “Cat”
  },
  “name”: “Grumpy Cat”,
  “photoUrls”: [
    “https://pbs.twimg.com/profile_images/948294484596375552/RyGNqDEM_400x400.jpg”
  ],
  “tags”: [
    {
      “id”: 1,
      “name”: “Mixed breed”
    }
  ],
  “status”: “available”
}

Note that the id that was at the top of the request (the pet id) has now been removed. Now go to the Tests tab, and add in this instruction:

var jsonData = JSON.parse(responseBody);
postman.setEnvironmentVariable(“newPetId”, jsonData.id);

This instruction is parsing the JSON data and setting the id value returned to a new environment variable called “newPetId”. (Note that this is also in the old Postman assertion style. If you know how to do this in the new style, please add it in the comment section!) Let’s save this request and run it. After you’ve run the request, click on the eyeball icon in the top right corner of the screen.  This is the Environment Quick Look button, which allows you to quickly see what variables you have in your environment. You should see the newPetId variable, with a value of whatever id your new pet was assigned!  What’s nice about this feature is that you don’t even need to create the new variable in the environment first; the Postman request will create it for you.

We have only been looking at one variable- the pet id- in these instructions. You could also set variables for the pet name, the pet’s image URL, the status type, and so on. You may want to practice this in your Postman collection.The more variables you create in your environment, the easier it will be to maintain your tests in the future. 

Next week, we’ll talk about one of my favorite things- organizing tests and environments!

Adding Postman Assertions

This week, we’ll be talking about adding assertions to our Postman requests.  In last week’s post, we discussed what various API request responses mean, and how to write assertions for them in Postman requests.  Now we’ll be adding some more assertions that will test our requests more fully. 

We will be using the Postman collection that we created two weeks ago, so if you haven’t yet created that, you may want to set it up before you continue. 

The first type of assertion we’ll discuss is the Response Time assertion.  This verifies that the response to an API request is returned within an acceptable amount of time. Let’s say that the product owners of the Swagger Pet Store have decided that their end users should be able to add a new pet to the store in under one second.  We’ll add an assertion for this to our Add Pet request.  Click on the Add Pet request in the collection list on the left of the screen so it will open up in the main window. Then click on the “Tests” tab.  You should already have the Response Code assertion that you added last week.  Click underneath that assertion, and then click on the “Response time is less than 200 ms” code snippet on the right.  This will be added to the Tests window:

pm.test(“Response time is less than 200ms”, function () {
    pm.expect(pm.response.responseTime).to.be.below(200);
});

Currently the test is asserting that the response time should be less than 200 milliseconds.  We don’t need it to be that fast, so let’s change the assertion.  First, change the “Response time is less than 200ms” to be “Response time is less than one second”.  This is the title of the test.  Now let’s change the actual assertion.  Change the value in “to.be.below” from 200 to 1000 (this is one thousand milliseconds, or one second).  Save your request and click the Send button.  You should see in the Test Results section at the bottom of the screen that your assertion passed.  You can also look at the top of the results window and see the response time next to the response status code. 

Another helpful assertion is the Response Contains String assertion.  This simply asserts that the body of the request response has a certain string.  I often use this assertion when I am expecting an error message.  To see this in action, let’s add a new negative test to our collection.  We will trigger a 500 response by trying to add a pet to the store with a non-integer id. The easiest way to create this request will be to copy the existing Add Pet request and rename it to “Add Pet With Invalid ID”. (If you don’t know how to copy and rename a request, see Creating a Postman Collection.) 

We have a few changes to make to this request before we add in our new assertion.  In the body of the request, we’ll change the id of pet from “100” to “FOOBAR”.  Because we copied this request, we already have a couple of assertions in it: one that asserts that the response code will be 200, and one that asserts that the response time is less than 1000ms.  We know that our response code won’t be 200 any more, so let’s change that test to read:

pm.test(“Status code is 500”, function () {
    pm.response.to.have.status(500);
});

We can leave the Response Time assertion as is, or we can remove it.  Now we can add in our new assertion.  Look in the snippet list for “Response body:Contains string”, and click on it.  This will be added to the Test window:

pm.test(“Body matches string”, function () {
    pm.expect(pm.response.text()).to.include(“string_you_want_to_search”);
});

Let’s rename the assertion from “Body matches string” to “Error response is returned”, and change the response text from “string_you_want_to_search” to “something bad happened”. It’s worth noting at this point that Postman assertions are case-sensitive, so you won’t want to capitalize the word “Something”, since it’s not capitalized in the actual response.

Click the Send button and verify that you get Pass messages for both your Status Code test and for your Response Contains String test.

Now let’s look at a more powerful assertion: the JSON Value Check.  We can actually assert that the values returned in a response are the values that we are expecting.  Let’s look at the Get Pet request.  We are already asserting that the response code is 200, but that doesn’t really tell us much.  It’s possible that when we make our request that we are getting the wrong pet in the response!  We’ll want to assert that we are getting the right pet back without having to physically look at the response. So we’ll add a JSON Value Check.  Click below the Response Code assertion, and then look for the code snippet called “Response body: JSON value check”. Click on this snippet.  This will be added to your test window:

pm.test(“Your test name”, function () {
    var jsonData = pm.response.json();
    pm.expect(jsonData.value).to.eql(100);
});

Change the test name from “Your test name” to “Body contains pet id”. Notice that the next line of code creates a variable called jsonData. This is the parsed version of the JSON response. On the third line, we’ll change “jsonData.value” to “jsonData.id”. This is because we want to find out what the id of the response is.  Finally, we don’t need to change the value in “to.eql”, because we were looking for an id of 100, and that’s what it’s already set to. When you are done making your changes, the assertion should look like this:

pm.test(“Response contains id”, function () {
    var jsonData = pm.response.json();
    pm.expect(jsonData.id).to.eql(100);
});

Save your request changes and then click the Send button.  Both your Response Code assertion and your JSON Value Check tests should pass.

You may have noticed that there are other ids in the body of the Get Pet response:

{
    “id”: 100,
    “category”: {
        “id”: 1,
        “name”: “Cat”
    },
    “name”: “Grumpy Cat”,
    “photoUrls”: [
        “https://pbs.twimg.com/profile_images/948294484596375552/RyGNqDEM_400x400.jpg”
    ],
    “tags”: [
        {
            “id”: 1,
            “name”: “Mixed breed”
        }
    ],
    “status”: “available”
}

 How would we assert on the category id or the tag id?  We do this by parsing through the JSON response. In order to demonstrate this, copy the test you just created, and edit it to look like this:

pm.test(“Response contains category id”, function () {
    var jsonData = pm.response.json();
    pm.expect(jsonData.category.id).to.eql(1);
});

We’ve changed the test name in the top line of the code to reflect what we are actually asserting.  The second line of code remains the same. In the third line of code, we’ve changed “jsonData.id” to “jsonData.category.id”. This means that instead of looking at the id, we are looking at the category section, and then at the id within that section. Finally we changed the value that we were expecting from 100 to 1. 

Save your request and click the Send button again. Now you should see all three assertions on the request pass.

Now that you know how to create assertions, you can go through all of the requests in your Pet Store collection and add your own! You may have noticed that your POST and PUT requests return the pet in the body of the response, so you can add similar assertions to those requests.  You’ll definitely want to make sure that after you have changed your pet data with the PUT (Update Pet) request, the data you get back from your GET (Verify Update Pet) request has the updated information that you are expecting. 

This is just the beginning of what you can do with assertions!  Next week, we’ll take a look at how to set variables and use them in both your requests and your assertions. 

Response Codes Explained

If you have ever made a REST request or looked in the developer tools section of a browser, you have likely seen the three-digit response code that is returned with an HTTP request.  This week, we’ll be talking about the different types of response codes you might receive when doing API testing, and what those codes mean.  

100-level Responses:
A 100-level response indicates that the request should continue.  The most common 100-level type is the simple 100 Continue.  This can be used with large requests; it gives the server the opportunity to stop a large request before too much data is transmitted.  You probably won’t see this in your API testing, because the server response will continue and complete behind the scenes and will then return a 200-level response. 
200-level Responses:
A 200-level response indicates that the request was successful.  The most common response is the 200 OK.  This simply means that everything went as expected.  Here are some other common 200-level responses:
201 Created– this indicates that a new resource has been created as the result of the request.  For example, a GET request might create a log entry that shows the date, time, and content of the request.
202 Accepted– this indicates that the request was accepted, but is not complete yet.  An example of where this could be used would be a pending change that needs approval before being added to the database.
204 No Content– this means that the request was processed successfully, and that no data was returned.  This might be used with a PUT request, where the content is changed, but the developer saw no need to return the data with the response.  A 200 OK response can also return no data if the developer chooses, but a 204 response should never return any data.  
300-level Responses:
A 300-level response indicates that a resource has been moved.  The most common of the 300-level responses is 301 Moved Permanently. This response should include the new URI in the header, so that the client will know where to point the request next time.  
400-level Responses:
A 400-level response indicates that there was something wrong with the client’s request.  The most common of these is 400 Bad Request, which is usually used when the request is malformed or inaccurate in some way.  Examples of this would be a request where there is required data that is not present, or data that has some sort of validation error.  Other common 400-level responses include:
401 Unauthorized– this is usually returned when the client does not have the appropriate authentication to make the request, such as a JWT or a cookie.  
403 Forbidden– this is returned when the client has the appropriate authentication to make the request, but does not have the permission to view the resource.  For example, a user might be logged into the system and be able to request their own data, but should not be able to request another user’s data.
404 Not Found– this is returned when the client is making a request for a specific resource, and the server cannot find it.  An example of this would be if a customer with an ID of 100 was requested, and there was no customer with an ID of 100 in the database. 
409 Conflict– this is returned when the request puts data resources in conflict with each other.  One example of this would be if the client was attempting a POST request to create a resource with an id that was already being used.  
500-level Responses:
A 500-level response means that something has gone wrong on the server side of the request.  The most common is the 500 Internal Server Error response, which can be used for a variety of problems.  An example of this would be a request that was attempting to add a record to a database where the database table is not equipped to handle it, because it has too many characters or is the wrong type. Other common 500-level responses include:
502 Bad Gateway– this can happen when the responding server needs to make a request from another server, and the other server is returning an invalid response.
503 Service Unavailable– this is returned when the responding server is temporarily down for some reason. This response can be more helpful than the generic 500 response, because it indicates that the problem is with availability rather than with the database. 
Now that we understand what response codes mean, let’s try them out in our Postman Pet Store Collection!  If you have not yet created the collection, see last week’s post for instructions.  Click on the first request in the collection: Add Pet.  Underneath the URL of the request, click on “Tests”.  In the right-hand side of the window, there will be a list of code snippets that you can use to create assertions.  Scroll down until you find the snippet called “Status code: Code is 200”, and click on it. This will automatically add an assertion in the test field that looks like this:  
pm.test(“Status code is 200”, function () {
    pm.response.to.have.status(200);
});

The “Status code is 200” section of this code is the name of the test you are running.  The “pm.response.to.have.status(200)” section is the expectation of the assertion.  
Click the Save button on the request, and then click the Send button.  In the bottom section of the page, you should see a Test Results section with a “(1/1)” after the section title.  This indicates that 1 test passed, and 1 test was run.  If you click on the Test Results link, you should see “PASS” and “Status code is 200” in the response section.  You have successfully added an assertion to your request!
Let’s see what a failed assertion looks like.  To make the assertion fail, simple change the body of the assertion to:
pm.test(“Status code is 202”, function () {
    pm.response.to.have.status(202);
});

We have set our assertion to expect a 202 response instead of a 200.  Run the request again, and now you should see “(0/1)” next to the Test Results link.  Click on the link, and in the response section, you should see “FAIL” and “Status code is 202”.  This indicates that the test named “Status code is 202” has failed.  
Now change the assertion back to expect a 200 response, and add the assertion to all of the other requests in your collection, except for the request called “Verify Delete Pet”.  The “Verify Delete Pet” request is looking for a record that no longer exists, so we will not be expecting a 200 response.  Instead, we should be getting a 404 Not Found response.  Let’s add this assertion in the Tests section of the request:
pm.test(“Status code is 404”, function () {
    pm.response.to.have.status(404);
});

Click the Save button to save this assertion.  
If you run this request before you have run the Delete Pet request, you will see the assertion fail, because the pet with the id of 100 still exists.  But if you first run the Delete Pet request, and then run the Verify Delete Pet request, you will see the Delete Pet assertion pass, because the pet with the id of 100 no longer exists in the database.
Now that we have assertions on all of our requests, let’s try running the entire collection!  Hover over the name of the Pet Store collection, and click on the chevron (>) that appears to the right of the name.  Click on the “Run” button, and the Collection Runner will open.  Click on the name of your collection, and then click the “Run Pet Store” button.  You should see your tests run, and pass, very quickly!  Your results window should look like this:
At the top of the window, you’ll see that your six tests passed, and that zero tests failed.  You’ll see the name of each of the requests you created, and the name of each test that you ran for each request, along with the “PASS” indicator.
Next week we’ll add some more interesting assertions to our collection!  

Creating a Postman Collection

This week we’ll be finishing up our discussion of REST request types with an introduction to the DELETE request and how to test it.  We will also be looking at how to chain REST tests together in a Postman collection.

A DELETE request removes an entire record from a database table.  To see a DELETE request in action, let’s return to the Swagger Pet Store.  First let’s open up the GET /pet/{petId} request.  Click on the “Try it out” button, and put “100” in the petId field.  Then click the Execute button.  Take a look at the server response.  Was a pet returned?  If not, try a different petId.  Keep looking until you find an existing record.

Now that you have an existing record, open up the DELETE /pet/{petId} request and click on the “Try it out” button.  In the petId field, enter the same id that you used for the GET request.  Click the Execute button.  In the server response, you should see a success code of 200.

How can you tell that the record was really deleted?  Simply return to the GET request, put the same id in the petId field, and click the Execute button.  You should now get a “Pet not found” response.  You have successfully deleted a pet from the database!

Testing a DELETE request is fairly straightforward.  Since the only information you are passing into the request is the id of the record you want to delete, there’s not much room for variation.  You can test what happens when you enter an id for a record that doesn’t exist (you should get a 404 response) and what happens when you enter an invalid id such as “FOO”.  If the DELETE functionality in your application is limited to users with authorization, you can try deleting a record without the token or cookie that gives you the required permission.  You can try sending the request with an http URL instead of an https (or vice versa), or you can try sending a URL that doesn’t specify an id to delete.

Now let’s go to Postman and try chaining some requests together!  Imagine that you are putting together a test suite for the Swagger Pet Store.  You’d like to check to make sure that you can add a pet, retrieve a pet, edit a pet, and delete a pet from the database.  When you add a pet to the database, you’d like to make sure the record has really been added; so you’d like to have a GET request to verify that.  Similarly, when you edit the pet, you’d like to do a GET request to verify that the pet has been changed.  And finally, when you delete the pet, you’d like to do a GET request to verify that the pet has really been deleted.  Also, you’d like to have your test suite clean up after itself, so you aren’t adding more and more records to your database each day.  Chaining your requests together in a Postman collection will accomplish all of this.  This is the order of requests that you will make:

POST pet- to add the pet to the database
GET pet- to verify that the pet has been added
PUT pet- to change the existing pet
GET pet- to verify that the pet has been changed
DELETE pet- to remove the pet from the database
GET pet- to verify that the pet has been removed

To create a Postman collection, first click on the Collections tab on the top left of the screen. Then click on the icon with the folder and plus sign:

Give your collection a name, such as “Pet Store”, and click the Create button.  You will see a folder with your collection name in the left column of the screen.  Now click on the “+” tab in the main window of the screen to add a new request.  We’ll start with the POST pet request.  Create the request like this:

Request type: POST
URL: http://petstore.swagger.io/v2/pet
Headers: Content-Type: application/json
Body:
{
  “id”: 100,
  “category”: {
    “id”: 1,
    “name”: “cat”
  },
  “name”: “Grumpy Cat”,
  “photoUrls”: [
    “https://pbs.twimg.com/profile_images/948294484596375552/RyGNqDEM_400x400.jpg”
  ],
  “tags”: [
    {
      “id”: 1,
      “name”: “blue eyes”
    }
  ],
  “status”: “sold”
}

If any of this seems unfamiliar, you can see more detailed instructions in my post on POST requests.  

Once the request is ready and working, you can save it to your collection.  Click on the Save button in the upper right of the screen.  A popup window will appear.  Give your request a name, such as “Add Pet”, and then select the collection that you created earlier.  Click the Save button, and you should now see your request in the collection folder on the left of the screen.

We can repeat this process with the GET request:

Request type: GET
URL: http://petstore.swagger.io/v2/pet/100

As soon as this request is working, save it to your collection with a name like “Verify Add Pet”.  We are calling the request this because we will be using it to verify that the previous POST request worked correctly.

Next, we’ll edit the pet with a PUT request:

Request type: PUT
URL: http://petstore.swagger.io/v2/pet
Headers: Content-Type: application/json
Body:

{
  “id”: 100,
  “category”: {
    “id”: 2,
    “name”: “Dog”
  },
  “name”: “Droopy Dog”,
  “photoUrls”: [
    “https://upload.wikimedia.org/wikipedia/en/thumb/f/fd/Droopy_dog.png/150px-Droopy_dog.png”
  ],
  “tags”: [
    {
      “id”: 2,
      “name”: “Beagle”
    }
  ],
  “status”: “pending”
}

Once this request is working, save it to your collection with a name like “Update Pet”.

Now we’ll want to do another GET request, to verify that the PUT request worked correctly.  We already have a GET request saved, so we can just duplicate it in our collection.  Hover over the “Verify Add Pet” request on the left of the screen, and you’ll see three dots appear to the right of the request name.  Click on the three dots and choose “Duplicate”.  You should now have a request below the original “Verify Add Pet” request that says “Verify Add Pet copy”.  Click on this request and then on the three dots beside it and choose “Rename”.  Rename your request to “Verify Update Pet”, and click return.  Since we will be using this GET request to verify that the PUT request worked correctly, click and hold on the request and drag it below the PUT request.  

Next we’ll want to create a DELETE request:

Request type: DELETE
URL: http://petstore.swagger.io/v2/pet/100

Save this request to your collection with a name like “Delete Pet”.

Finally, we’ll want to do one more GET request, to verify that the DELETE request removed the pet correctly.  Duplicate the “Verify Update Pet” request, rename the copied request to “Verify Delete Pet”, and move it below the DELETE request.  Remember that when you run this request after your delete, you should get a “Pet not found” response.

We now have a collection with six requests that can be used to test the pet function of the Pet Store!  It should look like this:

Try clicking on each of these requests in order and using the blue Send button in the top right of the screen to run each one.  You should be able to add a pet, verify that it has been added, update the pet, verify that it has been updated, delete the pet, and verify that it has been deleted.

We will use this collection in the next couple of weeks to create assertions that will turn these requests into true tests.  Next week, we’ll discuss response codes and what they mean; then we’ll put some response code assertions into our requests.  Until then, have fun playing around with your Pet Store collection!


Testing PATCH Requests

Like PUT requests, PATCH requests modify an existing record.  But PATCH requests are much tricker to test!  This is because a PUT request modifies an entire record, whereas a PATCH request modifies only one part of the record.  There are many different operations that you can do within a PATCH request: you can add, replace, remove, copy, and move a value in your record.  I’ll describe some examples of each and discuss the various ways you can test them. 

Let’s use a very simple example of a data record for patching:
The JSON description of the first record would look like this:
{
    “id”: “1”,
    “firstName”: “John”,
    “lastName”: “Smith”,
    “homePhone”: “8005551000”,
    “workPhone”: null
}

Notice that our first record does not have a work phone.  Let’s do an add operation with our PATCH request in order to add one:
The URL for the request would look something like: https://app/customer/1, where the “1” is representing the id of the customer that you want to patch, and of course the http verb used should be PATCH.  The body of the request would look like this:
[
    {“op”:”add”,”path”:”/workPhone”,”value”:”8005551001″}
]
The “op” in this case is referring to the operation that you want to do for your PATCH.  Here we are using an add operation.  The “path” is showing which field you would like to add a value to, in this case the work phone field; the “value” is value that you want to add to that path, in this case the phone number itself.  
When this operation is completed, the JSON description will look like this:
{
    “id”: 1,
    “firstName”: “John”,
    “lastName”: “Smith”,
    “homePhone”: “8005551000”,
    “workPhone”: “8005551001”
}
Here are some ways to test a PATCH add operation:
  • Happy Path- patching where there is currently a null value
  • patching over the null value with an empty value of “”- this should add an empty string
  • patching over an empty value of “”- this should replace the existing empty string
  • patching over an existing value- this will replace the existing value, but ideally the replace operation should be used here instead
  • adding a value with too many or too fewer characters than allowed- an appropriate error message should be returned
  • adding a value with characters that are not allowed- an appropriate error message should be returned
  • adding a value of the wrong type, such as adding an integer when a string is expected- an appropriate error message should be returned

Next, let’s take a look at the replace operation.  Let’s use the second record this time, and we’ll replace the home phone.  This is what the record currently looks like:

{
    “id”: 2,
    “firstName”: “Amy”,
    “lastName”: “Jones”,
    “homePhone”: “8005551002”,
    “workPhone”: “8005551003”
}

The URL for the request will be https://app/customer/2, because we are patching the second record, and the body of the request will be:
[
    {“op”:”replace”,”path”:”/homePhone”,”value”:”8005551111″}
]
This operation will replace the original home phone of 8005551002 with a phone number of 8005551111, so the record will now look like this:
{
    “id”: 2,
    “firstName”: “Amy”,
    “lastName”: “Jones”,
    “homePhone”: “8005551111”,
    “workPhone”: “8005551003”
}

To test a PATCH replace operation, here are some things that you can try:
  • Happy Path- replacing one value with another
  • replacing the value with null- a remove operation would be better for this, but this should still work
  • replacing the value with the empty string “”- this should work
  • replacing a null value with a value- this will probably work, but it would be better to use the add operation
  • replacing with a value with too many or too fewer characters than allowed- an appropriate error message should be returned
  • replacing with a value with characters that are not allowed- an appropriate error message should be returned
  • replacing with a value of the wrong type, such as adding an integer when a string is expected- an appropriate error message should be returned
  • replacing where the existing value is bad in some way, such as having too many characters or having the wrong format- in this case the new good value should be allowed to replace the bad old value
Now let’s look at the remove operation.  We’ll start with this record:
{
    “id”: 1,
    “firstName”: “John”,
    “lastName”: “Smith”,
    “homePhone”: “8005551000”,
    “workPhone”: “8005551001”
}

To remove the home phone of this customer, we would again use this URL: app/customer/1, and we would use this body:
[
    {“op”:”remove”, “path”:”/homePhone”}
]
We will get this as a result:
{
    “id”: “1”,
    “firstName”: “John”,
    “lastName”: “Smith”,
    “homePhone”: null,
    “workPhone”: “8005551001”
}

A remove operation is fairly easy to test.  We just need to verify that the value has indeed been removed and replaced with null.  It’s also good to verify that no other value was removed by mistake, such as removing both phone numbers instead of just the home phone. We can also test that it’s not possible to remove a required field- this should return an appropriate error message.  
Now let’s look at the move operation.  Looking at the previous state of John’s record, let’s imagine that we have it wrong, and that what we have for his work phone is actually his home phone.  To move the phone number, we would use this request body:
[
    {“op”:”move”,”from”:”/workPhone”,”path”:”/homePhone”}
]
In this example, the “from” indicates where the current value is, and the “path” indicates where you would like the value to move to.  After this operation, our record will look like this:
{
    “id”: “1”,
    “firstName”: “John”,
    “lastName”: “Smith”,
    “homePhone”: “8005551001”,
    “workPhone”: null
}

Here are some ideas for testing a move operation:
  • Happy Path- moving an existing value to a location where the value is currently null
  • moving an existing value from location A to location B, where there is already a value in location B- in this case, the value in location B will be replaced with the value that was in location A
  • doing a move from A to B where the value of A is null- this should return an appropriate error message, because there’s nothing to move
  • doing a move from A to B where the validation constraints are different in location B, so A’s value should not be allowed- this should return an appropriate error message
  • doing a move from A to B where the value in A is bad- this should return an appropriate error message
  • moving a value from one location to a location that does not exist: this should return an appropriate error message
Finally, we’ll look at the copy operation.  This will copy an existing value and put it in a different location.  Let’s take this example:
{
    “id”: “1”,
    “firstName”: “John”,
    “lastName”: “Smith”,
    “homePhone”: “8005551001”,
    “workPhone”: null
}
If we want to copy the home phone so that the work phone will be the same number, we can do this request:
[
    {“op”:”copy”,”from”:”/homePhone”,”path”:”/workPhone”}
]
The “from” field shows us the location of the value we want to copy, and the “path” field shows us the location we’d like to copy to.  Our record should now look like this:
{
    “id”: “1”,
    “firstName”: “John”,
    “lastName”: “Smith”,
    “homePhone”: “8005551001”,
    “workPhone”: “8005551001”
}
Testing a copy operation is very similar to testing a move operation:
  • Happy Path: copying a value from one location to another where the value is currently null
  • copying a value from location A to location B, where location B currently has a value; this value will be replaced by the value in location A
  • copying from location A where the value of A is null- this should return an error message
  • copying from location A to a location that does not exist- this should return an error message
  • copying from A to B where the validation constraints are different in location B- this should return an error message
  • copying a bad value from location A to location B- this should return an error message
An important thing to note when patching is that PATCH requests can be chained together.  For example, if we start with this scenario:
{
    “id”: 2,
    “firstName”: “Amy”,
    “lastName”: “Jones”,
    “homePhone”: “8005551002”,
    “workPhone”: “8005551003”
}

And we run this PATCH request:
[
    {“op”:”remove”,”path”:”/homePhone”},
    {“op”:”replace”,”path”:”/workPhone”,”value”:”8005551111″}
]
We will wind up with this result:
{
    “id”: 2,
    “firstName”: “Amy”,
    “lastName”: “Jones”,
    “homePhone”: null,
    “workPhone”: “8005551111”
}

When we chain together requests in a PATCH, we need to test that any invalid operation will result in the entire request being invalid.  For example, if we had instead tried this request:
[
    {“op”:”remove”,”path”:”/homePhone”},
    {“op”:”replace”,”path”:”/workPhone”,”value”:”NOTAPHONENUMBER”}
]
we should receive an error message, and the first part of the PATCH should NOT have been executed.  In other words, we should still have a value in for the home phone.  
As you can see, PATCH requests are almost a set of HTTP verbs in themselves!  They should be used very carefully in an application, because there are so many different ways they can go wrong.  If your application is using them, be sure to test them alone and in combination.  Be sure to test both the Happy Path and the many ways they can fail validation.  If you are able to put bad data into your database, be sure to test patching over bad data.  
In next week’s post, I’ll discuss the DELETE request, and also how to create a Postman collection!  

Testing PUT Requests

In last week’s blog post, we discussed how to create and test POST requests.  This week, we will tackle testing PUT requests.  A PUT request is actually very similar to a POST request; the major difference is that POST requests are intended to create a new record, and PUT requests are intended to replace an existing record.

Let’s return to the Swagger Pet Store to learn how to create a PUT request.  Click on the PUT /pet request to open it:

As you can see, the endpoint and the body of the request are exactly the same as that of the POST request.  The only difference is the http verb used: PUT instead of POST.  To see how the PUT request works, let’s first do a POST with these values:
{
  “id”: 1,
  “category”: {
    “id”: 1,
    “name”: “Cat”
  },
  “name”: “Grumpy Cat”,
  “photoUrls”: [
    “https://pbs.twimg.com/profile_images/948294484596375552/RyGNqDEM_400x400.jpg”
  ],
  “tags”: [
    {
      “id”: 1,
      “name”: “Mixed breed”
    }
  ],
  “status”: “available”
}
Then do a GET to make sure that the pet was added correctly.  Now, let’s do a PUT with these values:
{
  “id”: 1,
  “category”: {
    “id”: 2,
    “name”: “Dog”
  },
  “name”: “Droopy Dog”,
  “photoUrls”: [
    “https://upload.wikimedia.org/wikipedia/en/thumb/f/fd/Droopy_dog.png/150px-Droopy_dog.png”
  ],
  “tags”: [
    {
      “id”: 2,
      “name”: “Beagle”
    }
  ],
  “status”: “pending”
}
Notice that all of the values in the body of the request have been changed except for the pet id. After you have submitted the request, do a GET to confirm that all of the values have been replaced.
A PUT request will always replace ALL of the values in the entire record, which means that if any of the values are missing, they will be removed.  For example, if we did a PUT request on that same pet id, and only included a name and a photo URL, that will be all that will be saved. Any tag or status that was present in the record before will now be gone.  
To talk about testing PUT requests, I’m going to move away from the Swagger Pet Store and use a different example. Let’s consider an application that stores a list of employees.  The application writes to a table that has these values:
The PUT request that will be used to update a record in the table will look like this:
{
  “firstName”: “Amy”,
  “lastName”: “Miller”
}
And the URL of the request will look like this: app/employee/1.  In this application, the employee id is passed in through the URL, rather than the body of the request, which is a common practice.  
The first thing we will test in our imaginary application is the Happy Path: if we send this request, does employee 1 now have the name Amy Miller instead of Fred Smith?  You could check this by querying the database directly, and by doing a GET request.  
Next, we’ll see what happens when trying to do a PUT request on a record that doesn’t exist.  Imagine doing the same request, but instead of using the URL app/employee/1, we’ll use app/employee/3.  As you can see in the data table, there is no record 3.  So this request should return an error, such as a 404 Not Found response.  You can also try passing in ids that make no sense, such as letters, words, or symbols, and passing in no id at all.  All these requests should return an appropriate error message.
Now let’s turn to the body of our request.  Let’s imagine that both the firstName and the lastName are required for the PUT request.  We should get an appropriate error message if we send in an empty body, or just the firstName, or just the lastName.  In a scenario where there are many more fields than we have here, you’ll want to test lots of different combinations where required and non-required fields are missing.  
As I mentioned above, a PUT request should replace ALL the values in a record; it’s like the record was completely removed and replaced with a brand new one.  So if we consider for a moment a scenario where the firstName is NOT required, and record 1 is currently Amy Miller, and we do a test where we send in only a lastName of “Brown”, record 1 should now have a NULL value for the firstName, and Brown should be the lastName.  
You could also see what happens when you try to pass in a request with fields that aren’t in the table at all!  In this example, you could try sending in 
{
  “firstName”: “Amy”,
  “middleName”: “Jo”
  “lastName”: “Miller”
}
and verify that the field is either ignored or an appropriate message is returned.  
Now we can go on to the individual fields themselves. What sort of values are allowed? What are the character limits?  You’ll want to test each individual field to make sure that you receive an appropriate error message when the limits are violated, and that you receive an appropriate error message when you try to pass in characters or values that are not allowed.  You’ll also want to try sending in values that could be used for cross-site scripting or SQL injection; these should either be rejected outright or sanitized in such a way that a malicious attack would not work.  
Finally, you can return to the http verb and the general request.  What happens if you change the PUT request to a POST request?  In our hypothetical application, a POST request with a URL of app/employee/1 will return a 409 error, because record 1 already exists.  You can also see what happens if you remove or change required headers on the request.  
Hopefully this post has given you a clear indication of how PUT requests behave, and the best ways to test them.  Next week, we’ll be on to the lesser-used PATCH request!  

Testing POST Requests

Last week, I introduced the concept of the GET request and how to test it.  This week we’ll move to POST requests.  POST requests are perhaps the most important of the RESTful requests, because they are what adds new records to your application’s database.  It’s very important to test your POST requests well, because they will have a direct impact on the quality of data in your database.

To learn about POST requests, we’ll once again use the Swagger Pet Store and Postman.  Navigate to the Pet Store (http://petstore.swagger.io) and click on the first POST request listed: “/pet”.  This POST request will add a pet to the pet store.  Take a look at the Example Value shown:

This is the body of the POST request.  Unlike GET requests, which usually don’t have a body, you will usually find some json or xml in a POST request.  The body represents the data that you are adding to the database.  Now click on the Model link:

This describes a bit about what all of the values in the body are.  You can click on the “>” icons to open up each section of the model.  I find this model to be a bit vague in terms of defining what a category is and what tags are, so I’m going to do a little guesswork.  Let’s walk through each section of the Pet model:
id: this is the id of the pet, which can be used in the GET request we tested last week
category: this represents what kind of animal the pet is.  The id is the unique identifier for the category, and the name is the word describing the animal.
name: this is the pet’s name
photoUrls: these are strings that link to pictures of the pet
tags: these are descriptive phrases that can be added to the pet.  The id is the unique identifier for the tag, and the name is the descriptive word describing something about the pet
status: this is the status of the pet in the store.  The status can be available, pending, or sold.

We can use the information in the model to create a POST to make a new pet.  Click on the “Try it out” link, and replace the body of the request with this information:
{
  “id”: 102,
  “category”: {
    “id”: 1,
    “name”: “cat”
  },
  “name”: “Grumpy Cat”,
  “photoUrls”: [
    “https://pbs.twimg.com/profile_images/948294484596375552/RyGNqDEM_400x400.jpg”
  ],
  “tags”: [
    {
      “id”: 1,
      “name”: “blue eyes”
    }
  ],
  “status”: “sold”
}

Before you click the Execute button, I do want to point out something in this POST request that is different from what you will most likely experience in the applications you test.  Generally, when you post an object with an id and that id already exists in the database, you’ll get a message that the record already exists.  In the case of the Pet Store, if that id already exists in the database, it will get overwritten with the object that you have posted.  
Now click the “Execute” button.  Take a look at what was returned in the body of the response.  You should see all the data you added.  It may be in a different order than it was in the body of the request, but that’s not important.
Let’s test to make sure that the new pet was really added!  Return to the GET pet/{petId} request, open it up, and click “Try it out”.  Enter “100” into the id field, and click “Execute”.  You should see the pet you added in the body of the response.  
Now that you have created a successful request in Swagger, let’s try one in Postman.  Open up the Postman application, and click on the plus button (+) to create a new request.  Click on the dropdown icon next to the word “GET” and choose “POST” instead.  Enter in the request URL: http://petstore.swagger.io/v2/pet. Click on the “Body” tab underneath the URL and select the “Raw” option.  In the body section just underneath, paste the request that you used earlier in Swagger.  You may want to vary it slightly by changing the id or the pet’s name.  
There’s one more step we need to do before we can send this request in Postman, and that is to add a header.  Headers are used in HTTP requests and responses to pass additional information to the server.  In this case, we need to tell the server what content-type to expect.  Click on the “Header” tab underneath the URL.  In the space underneath “Key”, add “Content-Type”.  In the space underneath “Value”, add “application/json”.  In this way, we are telling the server that it should look for a body in json format when we send our request.  Now click the “Send” button.  In the bottom half of the Postman window, you should see a 200 response code, and a response body that has all of the data you added.  Now you can use a GET request in Postman to check to make sure that your pet was added.  Return to last week’s blog post if you need help setting that up.  
Just as we found when we discussed testing forms, there are many different scenarios to test when testing POST requests.  First, we’ll want to test many Happy Path scenarios.  Try a number of different POSTs where you vary the id, the category of the pet and its id, the pet’s name, the photo URL, the tag and the tag’s id, and the status of the pet. You’ll want to make sure to test all three statuses of the pet: sold, available, and pending.  Also note that it’s possible to pass in more than one photo URL, and more than one tag.  Here’s an example of a body of a POST request where three photos and two tags are passed in:
{
  “id”: 102,
  “category”: {
    “id”: 2,
    “name”: “dog”
  },
  “name”: “Snoopy”,
  “photoUrls”: [
    “https://schulzmuseum.org/wp-content/uploads/2017/06/920608_FlyingAce-200.jpg”,
    “https://www.calmuseums.org/images/snoopy/snoopy.png”,
    “https://vignette.wikia.nocookie.net/peanuts/images/2/28/AmigosperdemoSono.png/revision/latest?cb=20110823202539”
  ],
  “tags”: [
    {
      “id”: 2,
      “name”: “beagle”
    },
    {
      “id”: 3,
      “name”: “flying ace”
    }
  ],
  “status”: “available”
}

Now that you have tested a number of Happy Path scenarios, it’s time to think about breaking the request.  First, you may have noticed in the Swagger Model that only two fields are required: the name of the pet, and one photo URL.  What happens if you pass in just those two fields?  
{
  “name”: “Snoopy”,
  “photoUrls”: [
    “https://schulzmuseum.org/wp-content/uploads/2017/06/920608_FlyingAce-200.jpg”
  ]
}

We get a 200 response, and the pet has been added with an id that we can use to retrieve it.  What happens if there are no values in the body of the request?  What happens if one of the required fields is missing?  Now is a good time to experiment by passing in a variety of combinations of fields.  
It’s worth noting at this point that you may get a 500 response for nearly every error condition you provoke.  In a real-world application, you’d get more appropriate response codes with more appropriate error messages. 

Next, it’s time to take another look at passing in multiple URLs and tags.  How many URLs can you pass in before provoking an error?  How many tags can you pass in before you get an error?  
Now we’ll look at the limits of the values we are passing in.  For example, what happens if you create a pet with an id of 0?  What happens if you create one with the id of -100000?  What happens if you send in an id of “FOO” or $%^?  You can test this on all of the ids: the pet’s id, the category id, and the tag id.  How long are the text strings allowed to be?  How short are they allowed to be?  Are there any characters that are not allowed?  You’ll want to test the upper and lower limits of the strings, and verify that any forbidden characters are not allowed.  This is also a good time to test for SQL injection and cross-site scripting.  For example, you could try passing in 
<script>alert(‘XSS’)</script> 
or 
‘ or 1 = 1– 
and see if those are allowed.  (In the case of the Pet Store, these will probably be allowed, but a real application should forbid these or at least render them ineffective.)  
Another thing to test is the enum field for the pet’s status.  The pet’s status should be limited to available, pending, and sold.  What happens if you pass in another word or number or symbol?  What happens if you pass in a valid status with all caps, or with some of the letters capitalized?  A POST request should generally be case-insensitive.  You will also want to test the photo URL, making sure that you can’t pass in malicious scripts, and making sure that you can’t pass in something that isn’t a URL.
Once you have finished testing the body of the request, you can test the headers of the request.  This particular POST request requires a Content-Type header, and it will allow either an application/json header or an application/xml header.  If the header is missing, you’ll get a 415 error.  If you use an application/xml header, you’ll get a 400 error, unless you first change the body of the request to be in XML format.  You could also test to see what happens when you send an xml body with an application/json header.  
Finally, you can test the URL of the request itself, and the request type.  What happens if you make the request an https request?  What happens if you change the POST request to a GET?  
In summary, there are many ways to test POST requests, many of which would not be possible if you were focusing only on the UI.  In addition to testing required and non-required fields and field validation, you can also manipulate the object passed into the database and the headers and URL used to make the request. 
Next week, we’ll move on to PUT requests!  

Testing GET Requests

Last week I introduced the concept of RESTful API requests, and discussed why it’s crucial that we test them in our applications.  This week, we will begin our discussion of RESTful request types with the GET request.  This is usually the easiest request to test, because all we are doing is retrieving data from the database.  We don’t need to worry about whether we are manipulating data correctly; we just need to retrieve it and check that we get a correct response. 

In my opinion, the two best tools to learn about REST requests are Swagger and Postman.  Swagger is an open-source framework that allows developers to create documentation for RESTful APIs.  If your API has a Swagger file, it’s easy to see what kinds of requests your API allows, and what sorts of parameters those requests are expecting.  The developers of Swagger have also created a sample application that you can use to practice making REST requests:  petstore.swagger.io.  This website simulates an online pet store, where users can enter and retrieve information about their pets.



When you go to the petstore.swagger.io website, you can see that there are a variety of requests available for the pet endpoint.  Let’s take a look at the GET /pet/{petId} endpoint.  Click on that request, then click on the “Try it out” button. You will notice that a petId is a required parameter.  Enter “1” into the parameter text field, and click the “Execute” button.  Scroll down to the Response Body section, and you will see that a pet has been returned!  Scroll up a bit and take a look at the Request URL: http://petstore.swagger.io/v2/pet/1. We will use this URL to learn about making requests in Postman.


Postman is the best tool that I have found for testing REST requests. It is available for free at https://www.getpostman.com, and there is also a paid Team version. If you don’t have it already, download Postman and start it up.



Postman should start up with an open tab, set to use a GET request. All you have to do now is enter the request URL that we used before, and click the “Send” button. You should get the same response that you did when you made the request in Swagger.


Now that we understand how GET requests work, let’s think about how to test them! We have obviously tested a Happy Path scenario where we are getting a pet with an id of 1. What happens if we change the id parameter to 2? What happens if we change the id parameter to -1? What if it’s 0? What if it’s “foo”? I should mention here that because the Swagger Pet Store is a test application, you may see results or behavior that would not be wanted in an application. For instance, when I tested with a parameter of -1, I got a result. It’s a fairly common expectation that the ids of data objects not be negative numbers, so this would be a bug in a real application.


Let’s find out what happens when we don’t enter any parameter at all, so our request URL is just http://petstore.swagger.io/v2/pet. We get an xml response that says “unknown”. You may also notice that the status code returned is “405 Method Not Allowed”.




The status codes you get after you make a REST request tell you a bit about the behavior of your application.  We’ll discuss status codes further in a later post, but for now, let’s note that a status code of 200 is good, and a status code that begins with 4 generally indicates that something has gone wrong.  You may get a 404 status when you search for a pet id that doesn’t exist.  This means that the record was not found. 

Let’s return now to the Swagger Pet Store and take a look at another GET request.  This time, we will look at the pets/findByStatus request.  Click on the request, and then click the “Try it out” button.



Note that in order to execute this request, you need to select a status.  Let’s click the “sold” status and then click the “Execute” button.  If you scroll down to the response window, you can see that many pets were returned.  Now scroll up a bit and take a look at the request URL that was used: http://petstore.swagger.io/v2/pet/findByStatus?status=sold.


The question mark in the URL indicates that we are using a query parameter.  This is a little different from the path parameter we saw when we were doing a GET by pet id.  Query parameters always begin with a question mark, and then have the parameter name, an equals sign, and the value of the parameter we want to use.  


Let’s copy this request and run it in Postman.  Simply use the + button near the top of the screen to open a tab and create a new request.  It should be a GET request by default.  Enter the URL and click “Send”.  You should get the same result that you saw when you ran the request in Swagger.  


We have now tested one Happy Path for this request.  You can also run the request using the “available” parameter and the “pending” parameter.  You could run this request: http://petstore.swagger.io/v2/pet/findByStatus?status=pending,sold and get all of the pending pets and all of the sold pets!  What happens if you send a value of “foo” for the status parameter?  You will get an empty set [ ] as a result.  This is different from what we saw when we sent in “foo” as the parameter for the GET pet by pet ID request.  This demonstrates the difference between a path parameter and a query parameter.  When a path parameter does not exist, you will generally get a 400-level response code.  When a query parameter does not exist, you will generally get a 200 response code and an empty set in the response body.  


Now that you have tried out two different GET requests, you can test further by manipulating the request URL in any number of ways.  For example, you could see what happens if you make the request an https request instead of http.  You could find out what happens if you change the “io” in the request to “com”.  You could change the “v2” to “v1”.  You could remove the “/pet” endpoint.  You could try changing the GET request type to a POST or a DELETE type.  Seeing what happens when you manipulate the URL and the request type will give you a sense of how REST requests work, and will also give you ideas for what you could test in an API that you are responsible for. 


I hope that this post has demonstrated just how easy API testing is, and also how versatile it can be.  With API testing, you can test many scenarios that would not be possible to test through the UI.  This is a valuable strategy to use in finding potential design and security flaws earlier in development.  Next week, we’ll move on to POST requests!

Introduction to REST Requests

More and more companies are moving toward a microservices model for their applications.  This means that different sections of their application can have a separate datastore and separate commands for interacting with that datastore.  The advantage to this is that it’s easier to deploy changes to a small component of the application rather than the entire application; it also means that if one microservice goes down, the rest of the application can continue to function.  For example, let’s imagine you have a website for a bike rental service.  The site has a microservice for the reservation system, and a second microservice for the inventory.  If the microservice for the inventory goes down, users will still be able to make reservations for bike rentals, using cached data from the inventory microservice.

Most microservices are using APIs, or Application Programming Interfaces, which are a set of commands for how a service can be used.  And most APIs are using REST requests, or Representational State Transfers, through HTTP to request and send data.

Yet in spite of the common usage of RESTful APIs in today’s applications, many testers do not know just how easy it is to test them!  This post will serve as a gentle introduction to REST requests for use in API testing.

Why would you want to test REST requests, rather than just wait and test through the UI?  Here are a few good reasons:

  • testing REST requests means that you can find bugs earlier in the development process, sometimes even before the UI has been created!
  • malicious users know how to make REST requests, and can use them to exploit security flaws in your application by making requests the UI doesn’t allow
  • it’s easy to automate REST requests, and they run MUCH faster than UI automation (see my earlier blog post for further discussion of API vs. UI automation)
To get started in RESTful testing, first think about what you see in a URL when you navigate to a website.  For example, you might see: https://www.foobank.com/customers/login.  It’s easy to see how this URL is defining what page you are navigating to:
  • the https is specifying that this is a secure request
  • the www.foobank.com is the domain, which says that you want to go to the Foobank website
  • the customers is the first part of the path, which says that you are a customer and therefore want to go the Customers section of the website
  • the login is the last part of the path, which says that you want to go the login screen
One thing that’s not seen in the URL is the type of RESTful request being made.  This is known as an HTTP verb, and they are easy to understand:
  • a POST request adds a new record to the database
  • a GET request retrieves a record from the database
  • a PUT request takes a record from the database and replaces it with a new record
  • a PATCH request modifies an existing record in the database
  • a DELETE request removes a record from the database
In this case, a “record” can be any section of data that is grouped together.  For example, it could be a mailing address for a customer; or it could be all of the contact information for that customer; or it could be every single datapoint associated with that customer.  It’s up to the creators of the API to decide what should make up the record.  
In the next several blog posts, I’ll discuss each of the HTTP verbs in detail and describe how to test them.  I am sure you will be excited to discover just how much you can test without even navigating to your application’s web pages!