Hackernoon logoDocumenting, Encrypting, and Unit Testing My First REST API by@varunsingh

Documenting, Encrypting, and Unit Testing My First REST API

Borum Jot was the first project I tried seriously unit testing my code, encrypting the data, and documenting my back-end. I used PHPUnit, a unit-testing framework, and GuzzleHttp, a PHP HTTP client, to unit test my application. I encrypted my data using defuse/php-encryption. This library, claiming to be secure, did the encryption and decryption for me. To encrypt and decrypt, I needed my own key, which I generated by running composer.
image
Varun Singh Hacker Noon profile picture

@varunsinghVarun Singh

I'm a software developer, hacker, and avid reader interested in all things tech

I added a lot more to my REST API than just the JSON responses. Borum Jot was the first project I tried seriously unit testing my code, encrypting the data, and documenting my back-end. In this article, I will discuss cybersecurity, software testing, and documentation of my REST API.

Encryption

I encrypted my data using defuse/php-encryption. This library, claiming to be secure, unlike other libraries, did the encryption and decryption for me. To encrypt and decrypt, I needed my own key, which I generated by running:

$ composer require defuse/php-encryption
$ vendor/bin/generate-defuse-key

Composer is a package manager for PHP applications. The key is 256 bits long and can be stored either in a file (unsecured) or in the environmental variables. Vercel has a built-in way of storing environmental variables, and was the best place, without extra tools, for me to store the key.

Truthfully, I stored the key in a text file in the

etc
folder in the root directory because I didn't realize I could store it in the
$_ENV
at the time. This is highly insecure, so I am going to move this into a secure environmental variable soon

Then, at each request that updated or created data that I wanted to encrypt - task and note details - I loaded the key and called the encryption function. Similarly, for each request that fetched data that I encrypted, I loaded the key and decrypted before sending the response. This way, the front-ends never had to worry about encryption or decryption because I wrote everything on the backend, once.

Documentation

To document my APIs, I got inspiration from the Stack Exchange API documentation. I used NextJS to make a static documentation site for the entire Borum ecosystem, including Borum Jot. Then, for each page, I specified the request method, request headers, query-string, request body (for POST, PUT, and DELETE requests), and response body.

Here is a given page of my developer documentation website, which is live, hosted by Vercel, and open-source on GitHub:

image

A sample Borum Jot endpoint API reference on my Borum Dev Documentation site

Because I am fluent in JavaScript, I did not have any trouble setting up the documentation site. I have a JSON file with data on each endpoint that I update whenever I update the Borum Jot REST API.

I suggest including the following as a bare minimum when documenting REST or other Web API's:

  • Request Headers, if any
  • Request Query String
  • Request Method
  • Request Body
  • Response Body

Testing

I used PHPUnit, a PHP unit-testing framework, and GuzzleHttp, a PHP HTTP client, to unit test my application. GuzzleHttp acts as a client to the REST API server, making requests and asserting information about the responses.

namespace BorumJot\Tests;

use PHPUnit\Framework\TestCase;
use GuzzleHttp\Client;

class LoginTest extends TestCase {
    private $http;
    public function setUp() : void {
        $this->http = new Client(["base_uri" => "https://api.jot.bforborum.com/api/v1/"]);
    }
    public function testPost() {
        $response = $this->http->post('login');

        $this->assertEquals(200, $response->getStatusCode());

        $contentType = $response->getHeaders()["Content-Type"][0];
        $this->assertEquals("application/json; charset=UTF-8", $contentType);
    }
}

The TestCase is a superclass in PHPUnit that indicates that the class contains test cases. The

setUp()
method is called by PHPUnit before each test. GuzzleHttp's
Client
class's "request-method methods" (like
.get()
and
.post()
) provide information on the response, such as the headers and status code as shown above.

Setting Up Unit Testing

First I had to run

composer install phpunit/phpunit guzzlehttp/guzzle
to install the PHPUnit and GuzzleHttp packages.

I added the following to composer.json into the top-level object.

"scripts": {
   "test": "phpunit tests"
}

This will substitute phpunit tests for composer test. It is a common practice to substitute the unit testing framework command for the package manager's command to have one command prefix to rule them all. However, this is not necessary, for you could simply run phpunit tests.

The last step is to configure phpunit to find the folder with all the unit tests. I put mine in the root directory and called it

tests
, but you can call it and place it anywhere you would like, except maybe in auto-generated folders.

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php">
    <testsuites>
        <testsuite name="Borum Jot REST API Test Suite">
            <directory suffix=".php">./tests/</directory>
        </testsuite>
    </testsuites>
</phpunit>

Replace

./tests/
with the path to the folder with the unit tests. The test suite is an arbitrary name you give to a group of tests to identify it.

And that's how I documented, tested, and encrypted the data of my first REST API. Have you ever documented your own API? What tools did you use? Share your own projects down below!

Tags

Join Hacker Noon

Create your free account to unlock your custom reading experience.