Friday, 10 April 2015

A RESTFul with Openshft, Python + Flask and AeroGear

As a new year's resolution I have  started to learn Python. So I have read an introduction to this programming language. Then as next step I have created a RESTful API app. I have found tons of documents but, however, it take a lot of time and effort... 

The aim

 

 Build a RESTFul API to store and retrive  data. It use  MongoDB and AeroGear to send a notification (when new object is stored).

 

Tools

 

  1.   openshift, as hosting platform.
  2.    Python + Flask, to build the RESTFul API. 
  3.    AeroGear used to push notification. 

Notification 

 

The notifications are send with AeroGear. So I have used one of the openshift gears to hosting this service.  I also  have built an Android App to receive the notification (using Android SDK, AeroGear library for Android and the Google Api to manage  push notifications).

RESTFull API 

 

To build the Flask app I have followed this tutorial and add some code.
This is the required library, in my setup.py:

      install_requires=['Flask==0.10.1', 'MarkupSafe' ,
                        'Flask-SQLAlchemy==0.16','Flask-HTTPAuth==2.2.0',
                        'jsonschema>= 2.3.0','requests'],
Then, as  simple auth method (the same in the tutorial):
@auth.get_password
def get_password(username):
  if username == "myUserName":
    return "myPwd"
  return None

@auth.error_handler
def unauthorized():
  return make_response(jsonify({"error": "Unauthorized access"}), 401)
To initialize MongoDB it's necessary to use the environment variables (OPENSHIFT_MONGODB_DB_URL,OPENSHIFT_APP_NAME), as in the getData  method:

@app.route("/api/getMyData/", methods=['GET'])
def getData():  
  conn = pymongo.Connection(os.environ['OPENSHIFT_MONGODB_DB_URL'])
  db = conn[os.environ['OPENSHIFT_APP_NAME']]
  result = db.mydata.find()
  return str(json.dumps({'results':list(result)},default=json_util.default))
The last, and more complicated method is:
@app.route("/api/setMyData/", methods=['POST'])
@auth.login_required
def createData(): 
  myJson = request.json
  with open(os.path.join(os.path.dirname(__file__),"myData.json"),'r') as f:
    schema = f.read()
  try:
    jsonschema.validate(myJson, json.loads(schema))
  except jsonschema.ValidationError as e:
    return "problem with json schema"    
  conn = pymongo.Connection(os.environ['OPENSHIFT_MONGODB_DB_URL'])
  db = conn[os.environ['OPENSHIFT_APP_NAME']]
  mydata = db['mydata']
  mydata.insert(myJson)
  headers={"Accept":u"application/json", "Content-type": u"application/json"}
  url="https://myOpenshift/ag-push/rest/sender/"
  resp = requests.post(url, data=json.dumps({
    "message": {
    "alert": "My first notification!",
    "action-category": "cat1",
    "sound": "default",
    "badge": 2,
    "content-available": true,
    "user-data": {
      "key": "value",
      "key2": "other value"
 },
    "simple-push": "version=1.2"
      },
    "config": {
      "ttl": 3600
      }}), auth=requests.auth.HTTPBasicAuth("theAeroGearID", "AeroGearAuth"),headers=headers)
  return str(resp)
This method required some extra imports: jsonschema, requests, json.

 At line 4 i get the json from a curl rerquest :
curl -i -H "Content-Type: application/json" -X POST 
--data '{"idStation": 2,"name": "test","lat": 43,
"lng": 11,"z": 200,"stationOwner": "daniele","lastUpdate": "today"}'
 http://myopenschifturl/api/setMyData -u myUserName:myPwd
From line 5 to 8, my json schema is read (from myData.json file) and is verified if  actual json has this schema. To read the file it's necessary to use the variable os.path.dirname(__file__) as the root.

Then if the json is valid, it's stored into the database.  My app manages geographic data, so to use these it's necessary to modify the json, and put latitude and longitude in a loc variable. In order to use it in geographical operation  enable it with   db.points.create_index([('loc', GEO2D)]).

 The last step is  send notification to Aerogear. It's mandatory put the data into json.dumps() to avoid trouble to encoding. theAeroGearID and AeroGearAuth are available in the AeroGear dashboard into application. In the last line I have put the whole signature identifier for HTTPBasicAuth because Flask has it's own HTTPBasicAuth.

No comments:

Post a Comment