Create your own REST testing application

This time i want show you how to create your own REST testing application. For this demonstration i use Python, Tkinter and some Python libraries. At the end of this tutorial you can extend the application with more features like “show headers”, “store requests/responses”, “run automatically” and so on.

Preparation

  • install Python > 2.7 (Tkinter included)
  • install Requests: HTTP for Humans
  • install Python Data Validation for Humans
requests==2.8.1
validators==0.9

Example

# -*- coding: utf-8 -*-
from Tkinter import Tk, FALSE


class BaseTkGui(object):
    """Define basic TK GUI"""

    def __init__(self, window_title, window_resizable):
        """Constructor for Tkinter GUI"""

        self._root = Tk()
        self._root.title(str(window_title))

        if not bool(window_resizable):
            self._root.resizable(width=FALSE, height=FALSE)
        else:
            self._root.columnconfigure(0, weight=1)
            self._root.rowconfigure(0, weight=1)

    def start_app(self):
        """Start TK loop"""

        self._root.mainloop()

    def quit_app(self):
        """Stop and quit application"""

        self._root.quit()
# -*- coding: utf-8 -*-
from Tkinter import (Frame, OptionMenu, Entry, Button, StringVar, Label,
                     W, E, NO, END, SOLID)
from ttk import Treeview, Separator
from ScrolledText import ScrolledText
from BaseGui import BaseTkGui


class ApplicationTkGui(BaseTkGui):
    """Define application TK GUI"""

    OPTIONS = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS']

    def __init__(self, window_title):
        """Constructor for specific application GUI"""

        BaseTkGui.__init__(self, window_title, False)

        self._method = None
        self._url = None
        self._tree = None
        self._status = None
        self._time = None
        self._key = None
        self._value = None
        self._output = None

    def build_frames(self):
        """Add all frames and start mainloop"""

        self.__top_frame()
        self.__middle_frame()
        self.__bottom_frame()

        self.start_app()

    def prepare_req(self):
        """Overwritten method"""

        pass

    def _add_items(self):
        """Add items into TreeView at end"""

        key = str(self._key.get())
        value = str(self._value.get())

        if key and value:
            self._tree.insert("", "end", values=(key, value))
            self._key.delete(0, END)
            self._value.delete(0, END)

        self._tree.bind("<Double-1>", self._delete_item)

    def _delete_item(self, event):
        """Delete items from TreeView by ID"""

        item = self._tree.identify_row(event.y)
        self._tree.delete(item)

    def __top_frame(self):
        """Top frame creator"""

        self._method = StringVar(self._root)
        self._method.set("GET")

        frame = Frame(self._root)
        frame.grid(column=0, row=0, sticky=W+E)
        frame.grid_rowconfigure(0, weight=1)
        frame.grid_columnconfigure(0, weight=1)

        option = OptionMenu(frame, self._method, *self.OPTIONS)
        option.grid(column=0, row=0, padx=5, pady=5)

        self._url = Entry(frame, width=50)
        self._url.grid(column=1, row=0, padx=5, pady=5)
        self._url.configure(borderwidth=1, relief=SOLID)
        self._url.configure(highlightthickness=0)
        self._url.insert(0, 'http://')

        submit = Button(frame, text='Submit', command=self.prepare_req)
        submit.grid(column=3, row=0, padx=5, pady=5)

        Separator(frame).grid(columnspan=4, row=1, sticky=W+E)

    def __middle_frame(self):
        """Middle frame creator"""

        frame = Frame(self._root)
        frame.grid(column=0, row=1, sticky=W+E)
        frame.grid_rowconfigure(0, weight=1)
        frame.grid_columnconfigure(0, weight=1)

        self._tree = Treeview(frame, columns=("Key", "Val"), selectmode='none')
        self._tree.grid(columnspan=5, row=0, padx=5, pady=5, sticky=W+E)
        self._tree.column('#0', stretch=NO, minwidth=0, width=0)
        self._tree.heading('#1', text='Key')
        self._tree.heading('#2', text='Value')
        self._tree.configure(height=5)

        key = Label(frame, text='Key:')
        key.grid(column=0, row=1, padx=5, pady=5, sticky=E)
        self._key = Entry(frame)
        self._key.grid(column=1, row=1, padx=5, pady=5, sticky=W)
        self._key.configure(borderwidth=1, relief=SOLID)
        self._key.configure(highlightthickness=0)

        value = Label(frame, text='Value:')
        value.grid(column=2, row=1, padx=5, pady=5, sticky=E)
        self._value = Entry(frame)
        self._value.grid(column=3, row=1, padx=5, pady=5, sticky=W)
        self._value.configure(borderwidth=1, relief=SOLID)
        self._value.configure(highlightthickness=0)

        add = Button(frame, text='Add new header', command=self._add_items)
        add.grid(column=4, row=1, padx=5, pady=5)

        Separator(frame).grid(columnspan=5, row=2, sticky=W+E)

    def __bottom_frame(self):
        """Bottom frame creator"""
        font_style = ('verdana', 10, 'normal')

        frame = Frame(self._root)
        frame.grid(column=0, row=2, sticky=W+E)
        frame.grid_rowconfigure(0, weight=1)
        frame.grid_columnconfigure(0, weight=1)

        self._status = Label(frame, text='Response Status: -')
        self._status.grid(column=0, row=0, sticky=W)
        self._status.configure(fg='red', font=font_style)

        self._time = Label(frame, text='Time: - ms')
        self._time.grid(column=1, row=0, sticky=E)
        self._time.configure(fg='red', font=font_style)

        self._output = ScrolledText(frame)
        self._output.grid(columnspan=2, row=1, padx=5, pady=5, sticky=W+E)
        self._output.configure(height=12, borderwidth=1, relief=SOLID)
        self._output.configure(highlightthickness=0)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import requests
import validators
from Tkinter import END
from ApplicationGui import ApplicationTkGui


class Application(ApplicationTkGui):
    """Define application behaviors"""

    def __init__(self, window_title):
        """Constructor for application with title"""

        ApplicationTkGui.__init__(self, window_title)

    def run_application(self):
        """Start application"""

        self.build_frames()

    def prepare_req(self):
        """Prepare and validate request"""

        headers = dict()
        method = self._method.get()
        url = self._url.get()
        tree_ids = self._tree.get_children()

        for i in tree_ids:
            row = self._tree.item(i)
            add = row['values']
            headers[add[0]] = add[1]

        if validators.url(url):
            self.__do_request(method, url, headers)

    def __do_request(self, method, url, headers):
        """Do request and print results"""

        self._output.delete(1.0, END)

        ses = requests.Session()
        prepped = requests.Request(method, url, headers).prepare()
        response = ses.send(prepped, verify=False, allow_redirects=True)

        code = response.status_code
        body = response.text
        time_delta = response.elapsed
        duration = time_delta.total_seconds()

        status = 'Response Status: ' + str(code)
        time = 'Time: ' + str(duration) + ' ms'
        text = body[0:900] + ' ...'

        self._status.configure(text=status)
        self._time.configure(text=time)
        self._output.insert(END, text)

if __name__ == '__main__':

    RUN = Application('HTTPTester')
    RUN.run_application()

Run application

# set access permissions
$ chmod u+x ./RESTme.py
 
# start application
$ python -B ./RESTme.py

The application should look like:

RESTme Application