I Built My First Python Application — Here’s How I Did It

Conor Graham
#HackTheHub
Published in
7 min readSep 27, 2018

By David Craven — Graduate Data Analyst

Having learnt the basic concepts of Python, I built my first application several weeks ago. The process of learning a new programming language was very enjoyable, especially a language which offers much contrast to what I’ve been exposed to previously, such as Java and C#. I thought that I should share my code as well as some explanation into the various components I used, to help other beginners get a grasp on learning Python.

What does the application do?

The application allows a user to query the freely available REST API at http://postcodes.io(no API key needed) and return details for a given UK postcode. In this application I will be making use of only three API methods, which are listed below.

GET /postcodes/{POSTCODE}
GET /postcodes/{POSTCODE}/validate
GET /postcodes/{POSTCODE}/nearest

Entering a valid postcode using the GET request returns the full addresses for the postcode entered. (http://api.postcodes.io/postcodes/BT71NN)

Querying the API

My first approach to recreate this request was to query the Postcode API within my Python terminal, passing through the static value ‘BT71NN’ to the variable postcode and printing the result.

import requests main_api = "https://api.postcodes.io/postcodes/";
postcode = "BT71NN"
url = (main_api + postcode)
json_data = requests.get(url).json()print(json_data)

The above code returns the same data previously seen from the postcode.io site.

This is the JSON response from the URL that was queried, in the form of a Python dictionary as represented by the curly brackets { } with items being separated by a comma.

A dictionary is a collection of data which is;

  • Unordered — Unlike a list, elements in a dictionary are not stored in a specific order.
  • Mutable — We can add new items or change the value of existing items using the assignment operator ( = ).
  • Indexed — Values in a dictionary are indexed by keys and separated by colons ( : ).

Getting the data out

As the data is contained within a dictionary we need to use a key, which in this case is ‘result’ along with the value to be returned. In this example, we will pull the values ‘country’ and ‘admin_district’ for the postcode that was input by the user.

print("Country: %s, Region: %s." % 
(json_data['result']['country'],
json_data['result']['admin_district']))

Alternatively, if the data was contained within a List we would use a integer index to extract the specific data required i.e [0]. The %s is called a string format operator which converts a specified value to a string.

In relation to the third method used, nearest, we can use a For Loop to iterate over the list of results and print them separately.

for val in json_data['result']:
print("\tPostcode: %s, Country: %s, Region: %s." %
(val['postcode']
,val['country']
,val['region']))

Defining Functions

In this application I have defined 3 functions for each method used. A function is a block of code which only runs when it’s called, allowing parameters to be passed into the function.

To define a function, we use the def keyword, followed by the function name. Within the parentheses of the function we write the argument, which is postcode.

def get_details(postcode):
validate_url=main_api+postcode+'/validate'
def validate(postcode):
postcode_url=main_api+postcode
def get_nearest(postcode):
nearest_url=main_api+postcode+'/nearest'

The “main_api” variable contains the base URL which we require to query the Postcode API. For each function the inputted postcode will be dynamically added to this variable as well as any other necessary text needed for the specific request method.

A new request is made possible by importing the requests module at the start of the application. To get the content of a response as a python object, we use the .json() method on the response, converting it to JSON format.

import requestsjson_data = requests.get(validate_url).json()
json_data = requests.get(postcode_url).json()
json_data = requests.get(nearest_url).json()

We need to get the response from the URL and store the data returned. For each function the variable containing the data is called “json_data”.

Status Codes

The request made to the postcode.io API will return a response, with each response returning an appropriate HTTP status code.

  • 200 — This status code means that the request was received and is being processed.
  • 404 — This status code indicates that the client was able to communicate with the API, but it could not find what was requested. The ‘404’ status code is returned on http://api.postcodes.io/ when no postcode entry is supplied.

From querying the API there are only two possible results when validating a postcode; Trueor False.

Error Handling

The ability to handle errors within any code is always best practice and should be used where possible. To check the status of the request, we can use a simple IF statement to check if the status is equal to the integer value ‘200’.

if(json_data['status'] is 200):   # <Code block>else:  raise ValueError('No response from the endpoint.')

The ELSE condition will be used to raise a ValueError, which is a built in exception within Python, raised when an operation or function receives an argument that has the right type but an inappropriate value.

We are able to introduce some error handling to check if the postcode exists by raising a ValueError if the result is equal to False, otherwise returning a True value.

if(json_data['status'] is 200):   if (json_data['result'] is False):

raise ValueError('The postcode %s is not valid.' % postcode)
else:
return True
else: raise ValueError('No response from the endpoint.')

By nesting the IF statements we can perform a check that reviews the status code of the request and whether the postcode is valid; otherwise it returns the appropriate error message.

For each function I have added a Try : Except, meaning that if an error occurred within the try block code, its execution is stopped, reverted and transferred down to the except block. In this case the value False is returned, terminating the application.

try:# <Code block>
except Exception as e: print(e) return False

Main Code

The “main_api” variable contains the base URL which we require to query the Postcode API. As previously seen in my first code attempt the postcode variable is dynamically changed from the static value of “BT71NN” to the value inputted by the user on the console.

while True:# Main URL to query
main_api = 'https://api.postcodes.io/postcodes/';
# Prompt for user to enter a postcode
postcode = input('Enter Postcode: ')
# Step 1 : Validate the postcode if(validate(postcode)):

# Step 2 : Get the country and admin district
get_details(postcode)

# Step 3 : Get the nearest postcodes
get_nearest(postcode)

Full Code

This code can be copied freely and used for learning purposes.

"""
Created on 31/07/2018
Author: David Craven
"""
# Allows HTTP requests to be sent
import requests
# Function get details - GET /postcodes/{POSTCODE}
def get_details(postcode):
# Return true if everything is ok, return false if an error occurred
try:
# Create the url for this function
postcode_url=main_api+postcode
# Get the response from the URL
json_data = requests.get(postcode_url).json()
# Check the status of request
if(json_data['status'] is 200):
# Get the country and the region
print("Country: %s, Region: %s." % (json_data['result']['country']
,json_data['result']['admin_district']))
return True
else:
# If we don't have status 200, something went wrong
raise ValueError('No response from the endpoint.')
except Exception as e:
print(e)

# Function validate - GET /postcodes/{POSTCODE}/validate
def validate(postcode):
# Return true if valid, return false if invalid or if an error has occurred
try:
# Create the url for this function
validate_url=main_api+postcode+'/validate'
# Get the response from the URL
json_data = requests.get(validate_url).json()
# Check the status of request
if(json_data['status'] is 200):
# Check if the postcode exists
if (json_data['result'] is False):
# Raise the error if the postcode does not exist
raise ValueError('The postcode %s is not valid.' % postcode)
else:
return True
else:
# If we don't have status 200, something went wrong
raise ValueError('No response from the endpoint.')
except Exception as e:
print(e)
return False
# Function get nearest - GET /postcodes/{POSTCODE}/nearest
def get_nearest(postcode):
# Return true if everything is ok, return false if an error occurred
try:
# Create the url for this function
nearest_url=main_api+postcode+'/nearest'
# Get the response from the URL
json_data = requests.get(nearest_url).json()
# Check the status of request
if(json_data['status'] is 200):
# Iterate over the list of results
print("Nearest postcodes:")
for val in json_data['result']:
print("\tPostcode: %s, Country: %s, Region: %s." % (val['postcode']
,val['country']
,val['region']))
return True
else:
# If we don't have status 200, something went wrong
raise ValueError('No response from the endpoint.')
except Exception as e:
print(e)
return False
#### Main code ###

while True:
# Main URL to query
main_api = 'https://api.postcodes.io/postcodes/';
# Prompt for user to enter a postcode
postcode = input('Enter Postcode: ')
# Step 1 : Validate the postcode
if(validate(postcode)):

# Step 2 : Get the country and region
get_details(postcode)

# Step 3 : Get the nearest postcodes
get_nearest(postcode)

If you liked this post then make sure to check out our other articles in our publication here

--

--