"""
cars api is a sample web application developed by
Qxf2 Services to help testers learn API automation.
This REST application written in Python was built
solely to help QA learn to write API automation.
The application has endpoints for you to practice
automating GET, POST, PUT and DELETE methods.
It includes endpoints that use URL parameters,
jSON payloads, returns different response codes, etc.
We have also included permissioning and authentication
too to help you write role based API tests.
IMPORTANT DISCLAIMER: The code here does not reflect
Qxf2's coding standards and practices.
Source: https://github.com/qxf2/cars-api
"""
import os
import sys
import logging
import random
import flask
from functools import wraps
from flask import Flask, request, jsonify, abort, render_template
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from api.authentication_helper import AuthenticationHelper
from data.cars import Cars
from data.users import Users
app = Flask(__name__)
# write logs for app filehandler of logging module
# is not creating log directory if dir does not exist
if not os.path.exists('log'):
os.makedirs('log')
file_handler = logging.FileHandler('log/app.log')
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)
CARS_LIST = Cars().get_cars()
USER_LIST = Users().get_users()
REGISTERED_CARS = []
[docs]def requires_auth(f):
"""
verify given user authentication details
:param f:
:return:
"""
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
auth_flag = True
if not auth:
auth_flag = False
return AuthenticationHelper.authenticate_error(auth_flag)
elif not AuthenticationHelper.check_auth(auth.username, auth.password, USER_LIST):
return AuthenticationHelper.authenticate_error(auth_flag)
return f(*args, **kwargs)
return decorated
[docs]def requires_perm():
"""
check if the authenticated user has a admin permission
:return:
"""
auth = request.authorization
perm_flag = False
for user in USER_LIST:
if user['name'] == auth.username and user['perm'] == 'admin':
perm_flag = True
return perm_flag
return perm_flag
[docs]@app.route("/", methods=["GET"])
def index_page():
"""
this will help test GET without url params
:return:
"""
return render_template('index.html')
[docs]@app.route("/cars", methods=["GET"])
@requires_auth
def get_cars():
"""
this will help test GET without url params
:return:
"""
return flask.jsonify({"cars_list": CARS_LIST,
'successful': True})
[docs]@app.route("/cars/<name>", methods=["GET"])
@requires_auth
def get_car_details(name):
"""
this will help test GET with url params
:param name:
:return:
"""
car = [car for car in CARS_LIST if car['name'] == name]
if len(car) == 0:
resp = jsonify({'message': 'No car found',
'successful': False}), 200
else:
resp = jsonify({'car': car[0],
'successful': True}), 200
return resp
[docs]@app.route("/cars/find", methods=["GET"])
@requires_auth
def get_car():
"""
this will help test GET with url params
:return:
"""
car_name = request.args.get('car_name')
brand = request.args.get('brand')
if car_name != "" and \
car_name is not None and \
brand != "" and brand is not None:
car = [car for car in CARS_LIST if car['name'] == car_name]
if len(car) == 0:
resp = jsonify({'message': 'No car found',
'successful': False}), 200
else:
resp = jsonify({'car': car[0], 'successful': True}), 200
else:
resp = jsonify(
{'message': 'Not enough url_params',
'successful': False})
return resp
[docs]@app.route("/cars/add", methods=["POST"])
@requires_auth
def add_car():
"""
this will help test POST without url params
:return:
"""
if not request.json or 'name' not in request.json:
resp = jsonify({'message': 'Not a json',
'successful': False, }), 400
car = {
'name': request.json['name'],
'brand': request.json['brand'],
'price_range': request.json['price_range'],
'car_type': request.json['car_type']
}
CARS_LIST.append(car)
resp = jsonify({'car': car, 'successful': True}), 200
return resp
[docs]@app.route("/cars/update/<name>", methods=["PUT"])
@requires_auth
def update_car(name):
"""
this will help test PUT
:param name:
:return:
"""
resp = {}
car = [car for car in CARS_LIST if car['name'] == name]
if len(car) != 0:
if not request.json or 'name' not in request.json:
resp['message'], resp['successful'] = 'Not a json'
status_code = 404
else:
car[0]['name'] = request.json['name']
car[0]['brand'] = request.json['brand']
car[0]['price_range'] = request.json['price_range']
car[0]['car_type'] = request.json['car_type']
resp['car'], resp['successful'] = car[0], True
status_code = 200
else:
resp['message'], resp['successful'] = 'No car found', False
status_code = 404
return jsonify({'response': resp}), status_code
[docs]@app.route("/cars/remove/<name>", methods=["DELETE"])
@requires_auth
def remove_car(name):
"""
this will help test DELETE
:param name:
:return:
"""
car = [car for car in CARS_LIST if car['name'] == name]
if len(car) == 0:
abort(404)
CARS_LIST.remove(car[0])
return jsonify({'car': car[0], 'successful': True}), 200
[docs]@app.route('/register/car', methods=['POST'])
@requires_auth
def register_car():
"""
this will help test GET and POST with dynamic numbers in url
:return:
"""
car_name = request.args.get('car_name')
brand = request.args.get('brand')
if car_name != "" and car_name is not None and brand != "" and brand is not None:
car = [car for car in CARS_LIST if car['name'] == car_name]
customer_details = {
'customer_name': request.json['customer_name'],
'city': request.json['city']
}
registered_car = {'car': car[0], 'customer_details': request.json,
'registration_token': random.randrange(0, 4), 'successful': True}
REGISTERED_CARS.append(registered_car)
return jsonify({'registered_car': registered_car})
[docs]@app.route('/register/', methods=['GET'])
@requires_auth
def get_registered_cars():
"""
this will help test GET without url_params
:return:
"""
return jsonify({'registered': REGISTERED_CARS,
'successful': True})
[docs]@app.route('/register/car/delete/', methods=['DELETE'])
@requires_auth
def delete_registered_cars():
"""
this will help test delete
:return:
"""
del REGISTERED_CARS[0]
return jsonify({'successful': True}), 200
[docs]@app.route('/cars/filter/<car_type>', methods=['GET'])
@requires_auth
def filter_cars(car_type):
"""
get cars of the given car type
:param car_type:
:return:
"""
filtered_list = [car for car in CARS_LIST if car['car_type'] == car_type]
return jsonify({'cars': filtered_list})
[docs]@app.route('/users', methods=["GET"])
@requires_auth
def get_user_list():
"""
return user list if the given
authenticated user has admin permission
:return:
"""
if requires_perm() is True:
return jsonify({'user_list': USER_LIST,
'successful': True}), 200
return jsonify({'message': 'You are not '
'permitted to access this resource',
'successful': False}), 403
if __name__ == "__main__":
app.run(host="127.0.0.1", port=5000, debug=True)