Python Programming RESTful API Requests

REST (REpresentational State Transfer)

REST is emerged for standard design for creating web services and web APIs.

REST Characteristics

  • Client and Server: Separation between server (that offers a service) and client (that consumes the service).
  • Stateless protocol: REST uses HTTP protocol, Server does not maintain information about client and client requests must contain required information to the server to process the request.
  • Cacheable indicator: Server must inform to client whether requests can be cached or not.
  • Layered System and Uniform Interface: Standardized and uniform communication between client and server
  • Code on demand: This is optionsal, if needed, server can also provide executable code or scripts to the client to execute it.

HTTP methods

  • GET: This method is used to obtain information about resources or particular resources
    To get all employees information, GET request url may be like below
    http://codingpointer.com/api/employees
    
    To get particular employee information using employee id field
    http://codingpointer.com/api/employees/203
    
  • POST:Creating new resource
    http://codingpointer.com/api/employees
    
    //data (new employee information) will be provided with the request.
    
  • PUT: Updating particular resource
    http://codingpointer.com/api/employees/203
    
    //updated data (employee information 203) will be provided in request.
    
  • DELETE: Deleting particular resource
    http://codingpointer.com/api/employees/203
    //deletes employee #203)
    

Flask microframework

Flask microframework is very powerful python web framework.
Before installing Flask, try to install virtualenv(Virtual Python Environment builder) on your machine.
$yum install virtualenv
virtualenv is a tool to create isolated python virtual environments.
Once installed, run this command to Install setuptools, pip, wheel for flask
$virtualenv flask
Install flask on virtualenv
$flask/bin/pip install flask
Command prompt:
Collecting flask
  Downloading Flask-0.12.2-py2.py3-none-any.whl (83kB)
    100% |████████████████████████████████| 92kB 753kB/s 
Collecting itsdangerous>=0.21 (from flask)
  Downloading itsdangerous-0.24.tar.gz (46kB)
    100% |████████████████████████████████| 51kB 1.8MB/s 
Collecting click>=2.0 (from flask)
  Downloading click-6.7-py2.py3-none-any.whl (71kB)
    100% |████████████████████████████████| 71kB 1.2MB/s 
Collecting Jinja2>=2.4 (from flask)
  Using cached Jinja2-2.9.6-py2.py3-none-any.whl
Collecting Werkzeug>=0.7 (from flask)
  Downloading Werkzeug-0.12.2-py2.py3-none-any.whl (312kB)
    100% |████████████████████████████████| 317kB 1.4MB/s 
Collecting MarkupSafe>=0.23 (from Jinja2>=2.4->flask)
Building wheels for collected packages: itsdangerous
  Running setup.py bdist_wheel for itsdangerous ... done
  Stored in directory: /home/user_name/.cache/pip/wheels/fc/a8/66/24d655233c757e178d45dea2de22a04c6d92766abfb741129a
Successfully built itsdangerous
Installing collected packages: itsdangerous, click, MarkupSafe, Jinja2, Werkzeug, flask
Successfully installed Jinja2-2.9.6 MarkupSafe-1.0 Werkzeug-0.12.2 click-6.7 flask-0.12.2 itsdangerous-0.24

Simple web service using flask framework

# create file webservice.py
#!flask/bin/python                                                              
from flask import Flask                                                         
                                                                                
webservice = Flask(__name__)                                                    
                                                                                
@webservice.route('/')                                                          
def index():                                                                    
    return "Simple Web Service using Flask, Hello Python Flask Framwork!"       
                                                                                
if __name__ == '__main__':                                                      
    webservice.run(debug=True) 
Execution steps:
$ chmod a+x webservice.py
$./webservice.py
Output:
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 652-803-202
Either http://127.0.0.1:5000/ or http://localhost:5000/ url can be used to view the webservice response as "Simple Web Service using Flask, Hello Python Flask Framwork!"

RESTful API Using Python and Flask Framework

Get request for getting all employees information
# Create file rest-service.py
#!flask/bin/python                                                              
from flask import Flask, jsonify, abort                                             
                                                                                
rest_api = Flask(__name__)                                                      
                                                                                
employees = [                                                                   
    {                                                                           
        'id': 1,                                                                
        'name': 'employee 1',                                                   
        'designation': 'supervisor'                                             
    },                                                                          
    {                                                                           
        'id': 2,                                                                
        'name': 'employee 2',                                                   
        'designation': 'labour'                                                 
    }                                                                           
]                                                                               
                                                                                
@rest_api.route('/codingpointer/api/employees', methods=['GET'])                
def get_employees():                                                            
    return jsonify({'employees': employees})   

@rest_api.route('/codingpointer/api/employees/', methods=['GET'])       
def get_employee(id):                                                           
    employee = [employee for employee in employees if employee['id'] == id]     
    if len(employee) == 0:                                                      
        abort(404)                                                              
    return jsonify({'employee': employee[0]})                                     
                                                                                
if __name__ == '__main__':                                                      
    rest_api.run(debug=True)  
Execution steps:
$chmod a+x rest-service.py
$./rest-service.py
To run and test the RESTful service, we can use curl command or just place the url in browser: http://localhost:5000/codingpointer/api/employees
$ curl -i http://localhost:5000/codingpointer/api/employees
Output:
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 205
Server: Werkzeug/0.12.2 Python/2.7.13
Date: Fri, 08 Sep 2017 18:32:08 GMT

{
  "employees": [
    {
      "designation": "supervisor", 
      "id": 1, 
      "name": "employee 1"
    }, 
    {
      "designation": "labour", 
      "id": 2, 
      "name": "employee 2"
    }
  ]
}
To get particular employee information
$ curl -i http://localhost:5000/codingpointer/api/employees/1
Output:
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 97
Server: Werkzeug/0.12.2 Python/2.7.13
Date: Sat, 09 Sep 2017 03:12:12 GMT

{
  "employee": {
    "designation": "supervisor", 
    "id": 1, 
    "name": "employee 1"
  }
}

Employee id is not found

displays below error if employee record is not found for particular employee id
$ curl -i http://localhost:5000/codingpointer/api/employees/3
HTTP/1.0 404 NOT FOUND
Content-Type: text/html
Content-Length: 233
Server: Werkzeug/0.12.2 Python/2.7.13
Date: Sat, 09 Sep 2017 20:02:43 GMT

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server.  If you entered the URL manually please check your spelling and try again.</p>

Creating customized error message

#!flask/bin/python                                                              
from flask import Flask, jsonify,make_response,abort                            
                                                                                
rest_api = Flask(__name__)                                                      
                                                                                
employees = [                                                                   
    {                                                                           
        'id': 1,                                                                
        'name': 'employee 1',                                                   
        'designation': 'supervisor'                                             
    },                                                                          
    {                                                                           
        'id': 2,                                                                
        'name': 'employee 2',                                                   
        'designation': 'labour'                                                 
    }                                                                           
]                                                                               
                                                                                
@rest_api.errorhandler(404)                                                     
def get_not_found(error):                                                       
    return make_response(jsonify({'error': 'Not found'}), 404)                  
                                                                                
@rest_api.route('/codingpointer/api/employees', methods=['GET'])                
def get_employees():                                                            
    return jsonify({'employees': employees})                                    
                                                                                
@rest_api.route('/codingpointer/api/employees/', methods=['GET'])       
def get_employee(id):                                                               
    employee = [employee for employee in employees if employee['id'] == id]     
    if len(employee) == 0:                                                      
        abort(404)                                                              
    return jsonify({'employee': employee[0]})                                   
                                                                                
if __name__ == '__main__':                                                      
    rest_api.run(debug=True)     
Execution step:
$ ./rest-service2.py 
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 742-803-202
127.0.0.1 - - [10/Sep/2017 01:35:26] "GET /codingpointer/api/employees/3 HTTP/1.1" 404 -
Output:
$ curl -i http://localhost:5000/codingpointer/api/employees/3
HTTP/1.0 404 NOT FOUND
Content-Type: application/json
Content-Length: 27
Server: Werkzeug/0.12.2 Python/2.7.13
Date: Sat, 09 Sep 2017 20:05:26 GMT
{
  "error": "Not found"
}

RESTful API POST Method

POST method is used to create or insert a new record in the database.
#!flask/bin/python                                                              
from flask import Flask, jsonify, request                                       
                                                                                
rest_api = Flask(__name__)                                                      
                                                                                
employees = [                                                                   
    {                                                                           
        'id': 1,                                                                
        'name': 'employee 1',                                                   
        'designation': 'supervisor'                                             
    },                                                                          
    {                                                                           
        'id': 2,                                                                
        'name': 'employee 2',                                                   
        'designation': 'labour'                                                 
    }                                                                           
]                                                                               
                                                                                
@rest_api.route('/codingpointer/api/employees', methods=['POST'])               
def create_new_employee():                                                      
    if not request.json or not 'name' in request.json:                          
        abort(400)                                                              
    employee = {                                                                
        'id': employees[-1]['id'] + 1,                                          
        'name': request.json['name'],                                           
        'designation': request.json['designation']                              
    }                                                                           
    employees.append(employee)                                                  
    return jsonify({'employee': employee}), 201                                 
                                                                                
if __name__ == '__main__':                                                      
    rest_api.run(debug=True)     
Execution steps:
$ chmod a+x rest-service.py
]$ ./rest-service1.py 
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 742-803-202
127.0.0.1 - - [10/Sep/2017 00:11:32] "POST /codingpointer/api/employees HTTP/1.1" 201 -
Output:
$ curl -i -H "Content-Type: application/json" -X POST -d '{"name":"employee 3", "designation":"manager"}' http://localhost:5000/codingpointer/api/employees
HTTP/1.0 201 CREATED
Content-Type: application/json
Content-Length: 94
Server: Werkzeug/0.12.2 Python/2.7.13
Date: Sat, 09 Sep 2017 18:41:32 GMT

{
  "employee": {
    "designation": "manager", 
    "id": 3, 
    "name": "employee 3"
  }
}

RESTful API Error codes

Some Error codes which are mostly used in REST API's
Error Code Description
200 HTTP code 'OK'- Send back status code as OK to the client. Mostly used for PUT and DELETE methods.
201 HTTP code 'Created'- Send back status code as Created to the client.
400 HTTP code 'bad request' - Send back status code as bad request to the client.
404 HTTP code 'Not Found' - Send back status code as Not Found to the client.

RESTful API PUT Method

PUT method is used to update a particular record in the database objects.
#!flask/bin/python                                                              
from flask import Flask, jsonify, request, abort                                
                                                                                
rest_api = Flask(__name__)                                                      
                                                                                
employees = [                                                                   
    {                                                                           
        'id': 1,                                                                
        'name': 'employee 1',                                                   
        'designation': 'supervisor'                                             
    },                                                                          
    {                                                                           
        'id': 2,                                                                
        'name': 'employee 2',                                                   
        'designation': 'labour'                                                 
    }                                                                           
]                                                                               
                                                                                
                                                                                
@rest_api.route('/codingpointer/api/employees/', methods=['PUT'])       
def update_employee(id):                                                        
    employee = [employee for employee in employees if employee['id'] == id]     
    if len(employee) == 0:                                                      
        abort(404)                                                              
    if not request.json:                                                        
        abort(400)                                                              
    employee[0]['designation'] = request.json.get('designation', employee[0]['designation'])
    return jsonify({'employee': employee[0]})                                   
                                                                                
if __name__ == '__main__':                                                      
    rest_api.run(debug=True)  
Execution step:
$ ./rest-service3.py 
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 742-803-202
127.0.0.1 - - [10/Sep/2017 02:14:18] "PUT /codingpointer/api/employees/2 HTTP/1.1" 200 -
Output:
$ curl -i -H "Content-Type: application/json" -X PUT -d '{"designation":"supervisor-II"}' http://localhost:5000/codingpointer/api/employees/2
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 100
Server: Werkzeug/0.12.2 Python/2.7.13
Date: Sat, 09 Sep 2017 20:44:18 GMT

{
  "employee": {
    "designation": "supervisor-II", 
    "id": 2, 
    "name": "employee 2"
  }
}

RESTful API DELETE Method

DELETE method is used to delete a particular record in the database objects.
#!flask/bin/python                                                              
from flask import Flask, jsonify, abort                                         
                                                                                
rest_api = Flask(__name__)                                                      
                                                                                
employees = [                                                                   
    {                                                                           
        'id': 1,                                                                
        'name': 'employee 1',                                                   
        'designation': 'supervisor'                                             
    },                                                                          
    {                                                                           
        'id': 2,                                                                
        'name': 'employee 2',                                                   
        'designation': 'labour'                                                 
    }                                                                           
]                                                                               
                                                                                
                                                                                
@rest_api.route('/codingpointer/api/employees/', methods=['DELETE'])    
def delete_employee(id):                                                        
    employee = [employee for employee in employees if employee['id'] == id]     
    if len(employee) == 0:                                                      
        abort(404)                                                              
    employees.remove(employee[0])                                               
    return jsonify({'result': True})                                            
                                                                                
if __name__ == '__main__':                                                      
    rest_api.run(debug=True) 
Execution steps:
$ ./rest-service4.py 
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 742-803-202
127.0.0.1 - - [10/Sep/2017 02:22:39] "GET /codingpointer/api/employees/2 HTTP/1.1" 405 -
127.0.0.1 - - [10/Sep/2017 02:26:04] "DELETE /codingpointer/api/employees/2 HTTP/1.1" 200 -
Output:
$ curl -i -H "Content-Type: application/json" -X DELETE http://localhost:5000/codingpointer/api/employees/2
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 21
Server: Werkzeug/0.12.2 Python/2.7.13
Date: Sat, 09 Sep 2017 20:56:04 GMT

{
  "result": true
}

Secure RESTful API's

Simplest method to secure RESTful API is to ensure clients to provide username and password.
In HTTP context, two authentication types are Basic and Digest.

Install Flask-HTTPAuth

$ flask/bin/pip install flask-httpauth

Basic HTTP authentication in REST API

#!flask/bin/python                                                              
from flask import Flask, jsonify,make_response                                  
                                                                                
rest_api = Flask(__name__)                                                      
                                                                                
employees = [                                                                   
    {                                                                           
        'id': 1,                                                                
        'name': 'employee 1',                                                   
        'designation': 'supervisor'                                             
    },                                                                          
    {                                                                           
        'id': 2,                                                                
        'name': 'employee 2',                                                   
        'designation': 'labour'                                                 
    }                                                                           
]                                                                               
                                                                                
@rest_api.route('/codingpointer/api/employees', methods=['GET'])                
def get_employees():                                                            
    return jsonify({'employees': employees})                                    
                                                                                
@rest_api.route('/codingpointer/api/employees/', methods=['GET'])       
def get_task(id):                                                               
    employee = [employee for employee in employees if employee['id'] == id]     
    if len(employee) == 0:                                                      
        abort(404)                                                              
    return jsonify({'employee': employee[0]})                                   
                                                                                
if __name__ == '__main__':                                                      
    rest_api.run(debug=True)    
Execution step:
$ ./rest-service5.py 
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 742-803-202
Invalid Credentials Output:
$ curl -i -u 'test-user:test-passwd1' http://localhost:5000/codingpointer/api/employees/2
HTTP/1.0 401 UNAUTHORIZED
Content-Type: application/json
WWW-Authenticate: Basic realm="Authentication Required"
Content-Length: 37
Server: Werkzeug/0.12.2 Python/2.7.13
Date: Sat, 09 Sep 2017 21:23:58 GMT

{
  "error": "Unauthorized access"
}
Valid Credentials Output:
$ curl -i -u 'test-user:test-passwd' http://localhost:5000/codingpointer/api/employees/2
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 93
Server: Werkzeug/0.12.2 Python/2.7.13
Date: Sat, 09 Sep 2017 21:24:02 GMT

{
  "employee": {
    "designation": "labour", 
    "id": 2, 
    "name": "employee 2"
  }
}

REST API POST request to get the access token

import requests, urllib                                                         
import json                                                                     
                                                                                
url="https://api.test.com/oauth/access_token"                            
                                                                                
CONSUMER_KEY="consumer_key"     
CONSUMER_SECRET="consumer_secret_key"  
                                                                                
headers={ 'User-Agent' : 'OAuth gem v0.4.4',                                    
 'Connection' : 'close',                                                        
 'Content-type' : 'application/x-www-form-urlencoded',                          
 'Content-Length' : '175' }                                                     
                                                                                
data={'grant_type' : 'client_credentials',                                      
        'client_id': CONSUMER_KEY ,                                             
        'client_secret' : CONSUMER_SECRET                                       
}                                                                               
                                                                                
response = requests.post(url, headers=headers, data=urllib.urlencode(data))     
                                                                                
print "Post Request to : " +url                                                 
print response                                                                  
print "Response Message: "+response.text  
 

REST API POST Request to get data

import requests, urllib, json                                                   
                                                                                
url="https://api.testapi.com/method"                             
                                                                                
ACCESS_TOKEN="access_token"                         
                                                                                
headers={ 'User-Agent' : 'OAuth gem v0.4.4',                                    
 'Authorization' : ACCESS_TOKEN                                       
 }                                                                              
                                                                                
input_data={ 'param1': 22}                                                       
                                                                                
response = requests.post(url, data=json.dumps(data),headers=headers)           
                                                                                
print "Get Request to : " + url                                                  
#print response                                                                 
#print "Response Message: "+response.text                                       
                                                                                
json_data=response.json()                                                       
                                                                                
print json_data                                                                 
#for person in json_data['data']:                                               
# for key, value in json_data.iteritems():                                         
 #       print key, 'is:', value                                                
#print "\n"   

Privacy Policy  |  Copyright@2017 - All Rights Reserved.  |  Contact us   |  Report website issues in Github   |  Facebook page   |  Google+ page

Free online programming tutorials

Email Facebook Google LinkedIn Twitter
^