REST API Guide
In this guide, you'll create tests for an example REST API written with Flask.
App
Here we have a simple API that connects to a Postgres database and has one endpoint, which creates members given a member name as JSON.
app.py
from flask import Flask, request, jsonify
from sqlalchemy import create_engine
app = Flask(__name__)
engine = create_engine("postgresql://postgres:admin@db:5432/postgres")
@app.route("/members", methods=["POST"])
def members():
body = request.json
with engine.connect() as connection:
row = list(
connection.execute(
"INSERT INTO members (name) VALUES (%s) RETURNING *", body["name"]
)
)[0]
return jsonify({"id": row.id, "name": row.name})
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=8080)
requirements.txt
flask
psycopg2
sqlalchemy
Environment
Next, we'll need to set up our environment using Docker compose. Docker compose will handle creating the Docker image from a Dockerfile and starting the API as well as the Postgres database. We'll also want to create our schema for the database using a migration manager like 'Flyway'
V1__Initial.sql
CREATE TABLE members (
id SERIAL PRIMARY KEY,
name TEXT
)
Dockerfile
FROM python:3.8-buster
WORKDIR /app
RUN apt-get update
RUN apt-get install -y libpq-dev python-dev
ADD requirements.txt .
RUN pip install -r requirements.txt
ADD app.py .
ENTRYPOINT ["python", "app.py"]
docker-compose.yml
version: '3'
services:
db:
image: postgres:12-alpine
environment:
- POSTGRES_PASSWORD=admin
ports:
- 5432:5432
flyway:
image: flyway/flyway:6-alpine
command: -url=jdbc:postgresql://db:5432/ -schemas=public -user=postgres -password=admin -connectRetries=60 migrate
volumes:
- .:/flyway/sql
depends_on:
- db
api:
build: .
ports:
- 8080:8080
depends_on:
- db
- flyway
Ensure that the API is built and run successfully with docker-compose up or by
running make run if using the provided Makefile in the guide
Tests
Next, we'll want to create tests for our app. Create a file called
test.cicada.yaml to house the tests in and add a test that creates 100 members
through the API endpoint:
test.cicada.yaml
description: Example test
tests:
- name: add_members
description: add 100 new members
runner: rest-runner
actions:
- type: POST
executionsPerCycle: 100
params:
url: "http://api:8080/members"
body:
name: jeff
Next, add the following to docker-compose.yml to start Cicada and start
docker-compose again:
docker-compose.yml
version: '3'
services:
...
cicada:
image: cicadatesting/cicada-2-engine
environment:
- CONTAINER_NETWORK=rest_api_default
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- .:/tests
- ./reports:/reports
depends_on:
- api
The test should now create 100 users.
Let's add a SQL runner to our test. In this example, we are going to change the
name of all the members in the database. In test.cicada.yaml:
test.cicada.yaml
tests:
...
- name: update_ages
description: update ages of new members
runner: sql-runner
dependencies:
- add_members
config:
connectionString: postgresql://postgres:admin@db:5432/postgres
actions:
- type: SQLQuery
params:
query: "delete from members where name='jeff2'"
- type: SQLQuery
template: >
params:
{% set ids = [] %}
{% for member in state['add_members']['actions']['POST0']['results'] if member is not none %}
{% do ids.append(member['body']['id']) %}
{% endfor %}
query: "update members set name='jeff2' where id in ({{ ids|join(',') }})"
After updating test.cicada.yaml, run docker-compose again. You should be able
to verify in the database that the name of all the members is now jeff2.
Finally, we'll want to automate the verification of all the changed members. Add the following to the test file:
test.cicada.yaml
tests:
...
- name: update_ages
...
asserts:
- type: EqualsRows
params:
method: SQLQuery
actionParams:
query: "select count(*) as cnt from members where name='jeff2'"
expected:
rows:
- cnt: 100
This will perform a SQL query which will check that 100 users exist in the
database with name=jeff2
Run the docker-compose one last time. This test should finish and you will be
able to see the test results in reports/report.md
Congratulations! You were able to create and test a REST API!