Repository: HTTP-APIs/hydrus
Pull request #48 (2017-07-22 17:09:02)

New tests for Hydrus, dynamic DB Connectivity using App context, chan…
This PR includes:

- New tests for Hydrus, these also include tests for data using GET, POST, PUT, DELETE.
- All tests are passing.
- The database connector is now dynamically added/changed using app contexts.
- Any data added in the tests will not be persistent.
- Small changes to the server API Doc.

Todo:
Need to evaluate wether CRUD tests are now necessary
Add a few more tests for wrong data/request

**Work in progress, please do not merge**



Patch:
diff --git a/hydrus/app.py b/hydrus/app.py
index 1922f2a..c4924e6 100644
--- a/hydrus/app.py
+++ b/hydrus/app.py
@@ -4,26 +4,47 @@ import os
 import json
 from flask import Flask, jsonify, request, abort
 from flask_restful import Api, Resource
-# Will modify docs for each container using docker.
+from hydrus.data.db_models import engine
+from sqlalchemy.orm import sessionmaker
 from hydrus.metadata.doc_gen import doc_gen
-# from hydrus.metadata.drone.server_doc_gen import server_doc
-# from hydrus.metadata.drone.drone_doc_gen import drone_doc
 from hydrus.data import crud
 from flask_cors import CORS
+from contextlib import contextmanager
+from flask import appcontext_pushed
+from flask import g
+import pdb
 
 app = Flask(__name__)
 CORS(app)
 app.url_map.strict_slashes = False
 api = Api(app)
 
-## For vocab path in APIDOC
+
+@contextmanager
+def set_session(application, DB_SESSION):
+    """Set the database session for the app along with context management."""
+    def handler(sender, **kwargs):
+        g.dbsession = DB_SESSION
+    with appcontext_pushed.connected_to(handler, application):
+        yield
+
+
+def get_session():
+    """Get the db session for the app with context management."""
+    session = getattr(g, 'dbsession', None)
+    if session is None:
+        session = sessionmaker(bind=engine)()
+        g.dbsession = session
+    return session
+
+
 HYDRUS_SERVER_URL = os.environ.get("HYDRUS_SERVER_URL", "http://localhost:8080/")
 SERVER_URL = os.environ.get("SERVER_URL", HYDRUS_SERVER_URL)
 
 API_NAME = os.environ.get("API_NAME", "api")
 API_DOC = doc_gen(API_NAME, HYDRUS_SERVER_URL)
-# API_DOC = server_doc(API_NAME, SERVER_URL)
-# API_DOC = drone_doc(API_NAME, SERVER_URL)
+# set_session(app, sessionmaker(bind=engine)())
+
 
 def validObject(object_):
     """Check if the data passed in POST is of valid format or not."""
@@ -65,66 +86,58 @@ class Item(Resource):
 
     def get(self, id_, type_):
         """GET object with id = id_ from the database."""
-        if checkEndpoint("GET", type_):
-            class_type = API_DOC.collections[type_]["collection"].class_.title
-            if checkClassOp(class_type, "GET"):
-                response = crud.get(id_, class_type)
-                # import pdb; pdb.set_trace()
-                if len(response.keys()) == 1:
-                    status_code = int(list(response.keys())[0])
-                    return set_response_headers(jsonify(response), status_code=status_code)
-                else:
-                    response["@id"] = '/'+API_NAME+'/'+type_+'/'+str(id_)
-                    return set_response_headers(jsonify(hydrafy(response)))
+        class_type = API_DOC.collections[type_]["collection"].class_.title
+        if checkClassOp(class_type, "GET"):
+            response = crud.get(id_, class_type, session=get_session())
+            if len(response.keys()) == 1:
+                status_code = int(list(response.keys())[0])
+                return set_response_headers(jsonify(response), status_code=status_code)
+            else:
+                response["@id"] = '/'+API_NAME+'/'+type_+'/'+str(id_)
+                return set_response_headers(jsonify(hydrafy(response)))
         abort(405)
 
     def post(self, id_, type_):
-        """Add object_ to database with optional id_ parameter (The id where the object needs to be inserted)."""
-        if checkEndpoint("POST", type_):
-            class_type = API_DOC.collections[type_]["collection"].class_.title
-            if checkClassOp(class_type, "POST"):
-                object_ = json.loads(request.data.decode('utf-8'))
-                obj_type = getType(class_type, "POST")
-                if validObject(object_):
-                    if object_["@type"] == obj_type:
-                        response = crud.update(object_=object_, id_=id_, type_ = object_["@type"])
-                        object_id = response[list(response.keys())[0]].split(" ")[3]
-                        headers_ = [{"Location": SERVER_URL+API_NAME+"/"+type_+"/"+object_id}]
-                        status_code = int(list(response.keys())[0])
-                        return set_response_headers(jsonify(response), headers=headers_, status_code=status_code)
-                return set_response_headers(jsonify({400: "Data is not valid"}), status_code=400)
+        """Update object of type<type_> at ID<id_> with new object_ using HTTP POST."""
+        class_type = API_DOC.collections[type_]["collection"].class_.title
+        if checkClassOp(class_type, "POST"):
+            object_ = json.loads(request.data.decode('utf-8'))
+            obj_type = getType(class_type, "POST")
+            if validObject(object_):
+                if object_["@type"] == obj_type:
+                    response = crud.update(object_=object_, id_=id_, type_=object_["@type"], session=get_session())
+                    object_id = response[list(response.keys())[0]].split("=")[1]
+                    headers_ = [{"Location": SERVER_URL+API_NAME+"/"+type_+"/"+str(object_id)}]
+                    status_code = int(list(response.keys())[0])
+                    return set_response_headers(jsonify(response), headers=headers_, status_code=status_code)
+            return set_response_headers(jsonify({400: "Data is not valid"}), status_code=400)
         abort(405)
 
     def put(self, id_, type_):
-        """Update object at id=id_ with object_ in database."""
-        if checkEndpoint("PUT", type_):
-            class_type = API_DOC.collections[type_]["collection"].class_.title
-            if checkClassOp(class_type, "PUT"):
-                object_ = json.loads(request.data.decode('utf-8'))
-                obj_type = getType(class_type, "PUT")
-                if validObject(object_):
-                    if object_["@type"] == obj_type:
-                        response = crud.insert(object_=object_, id_=id_)
-                        headers_ = [{"Location": SERVER_URL+API_NAME+"/"+type_+"/"+id_}]
-                        status_code = int(list(response.keys())[0])
-                        return set_response_headers(jsonify(response), headers=headers_, status_code=status_code)
-                return set_response_headers(jsonify({400: "Data is not valid"}), status_code=400)
+        """Add new object_ optional <id_> parameter using HTTP PUT."""
+        class_type = API_DOC.collections[type_]["collection"].class_.title
+        if checkClassOp(class_type, "PUT"):
+            object_ = json.loads(request.data.decode('utf-8'))
+            obj_type = getType(class_type, "PUT")
+            if validObject(object_):
+                if object_["@type"] == obj_type:
+                    response = crud.insert(object_=object_, id_=id_, session=get_session())
+                    headers_ = [{"Location": SERVER_URL+API_NAME+"/"+type_+"/"+str(id_)}]
+                    status_code = int(list(response.keys())[0])
+                    return set_response_headers(jsonify(response), headers=headers_, status_code=status_code)
+            return set_response_headers(jsonify({400: "Data is not valid"}), status_code=400)
         abort(405)
 
     def delete(self, id_, type_):
         """Delete object with id=id_ from database."""
-        if checkEndpoint("DELETE", type_):
-            print("checkEndpoint passed")
-            class_type = API_DOC.collections[type_]["collection"].class_.title
-            if checkClassOp(class_type, "DELETE"):
-                response = crud.delete(id_, class_type)
-                status_code = int(list(response.keys())[0])
-                return set_response_headers(jsonify(response), status_code=status_code)
-        print("checkpoint failed")
+        class_type = API_DOC.collections[type_]["collection"].class_.title
+        if checkClassOp(class_type, "DELETE"):
+            response = crud.delete(id_, class_type, session=get_session())
+            status_code = int(list(response.keys())[0])
+            return set_response_headers(jsonify(response), status_code=status_code)
         abort(405)
 
 
-# Needs to be changed manually
 api.add_resource(Item, "/"+API_NAME+"/<string:type_>/<int:id_>", endpoint="item")
 
 
@@ -137,21 +150,20 @@ class ItemCollection(Resource):
             # Collections
             if type_ in API_DOC.collections:
                 collection = API_DOC.collections[type_]["collection"]
-                response = crud.get_collection(API_NAME, collection.class_.title)
+                response = crud.get_collection(API_NAME, collection.class_.title, session=get_session())
                 if "members" in response:
                     return set_response_headers(jsonify(hydrafy(response)))
                 else:
                     status_code = int(list(response.keys())[0])
-                    response = crud.get_collection(API_NAME, type_)
+                    response = crud.get_collection(API_NAME, type_, session=get_session())
                     return set_response_headers(jsonify(response), status_code=status_code)
 
             # Non Collection classes
             elif type_ in API_DOC.parsed_classes and type_+"Collection" not in API_DOC.collections:
-
                 response = crud.get_single(type_)
                 if len(response.keys()) == 1:
                     status_code = int(list(response.keys())[0])
-                    return set_response_headers(jsonify(response), status_code=status_code)
+                    return set_response_headers(jsonify(response), status_code=status_code, session=get_session())
                 else:
                     return set_response_headers(jsonify(hydrafy(response)))
         abort(405)
@@ -164,11 +176,11 @@ class ItemCollection(Resource):
             if type_ in API_DOC.collections:
                 collection = API_DOC.collections[type_]["collection"]
                 obj_type = collection.class_.title
-                if object_["@type"] == obj_type:
-                    if validObject(object_):
-                        response = crud.insert(object_=object_)
-                        object_id = response[list(response.keys())[0]].split(" ")[3]
-                        headers_ = [{"Location": SERVER_URL+"api/"+type_+"/"+object_id}]
+                if validObject(object_):
+                    if object_["@type"] == obj_type:
+                        response = crud.insert(object_=object_, session=get_session())
+                        object_id = response[list(response.keys())[0]].split('=')[1]
+                        headers_ = [{"Location": SERVER_URL+"api/"+type_+"/"+str(object_id)}]
                         status_code = int(list(response.keys())[0])
                         return set_response_headers(jsonify(response), headers=headers_, status_code=status_code)
                 return set_response_headers(jsonify({400: "Data is not valid"}), status_code=400)
@@ -177,7 +189,7 @@ class ItemCollection(Resource):
                 obj_type = getType(type_, "PUT")
                 if object_["@type"] == obj_type:
                     if validObject(object_):
-                        response = crud.insert_single(object_=object_)
+                        response = crud.insert_single(object_=object_, session=get_session())
                         headers_ = [{"Location": SERVER_URL+API_NAME+"/"+type_+"/"}]
                         status_code = int(list(response.keys())[0])
                         return set_response_headers(jsonify(response), headers=headers_, status_code=status_code)
@@ -188,17 +200,11 @@ class ItemCollection(Resource):
         """Update Non Collection class item."""
         if checkEndpoint("POST", type_):
             object_ = json.loads(request.data.decode('utf-8'))
-            # No update operation in Collections
-            # Non Collection classes
             if type_ in API_DOC.parsed_classes and type_+"Collection" not in API_DOC.collections:
-                print("SINGLE COLLECTION TYPE")
                 obj_type = getType(type_, "POST")
-                print("OBJTYPE", obj_type, object_["@type"])
-                if object_["@type"] == obj_type:
-                    if validObject(object_):
-                        print("validObject")
-                        response = crud.update_single(object_=object_)
-                        print(response)
+                if validObject(object_):
+                    if object_["@type"] == obj_type:
+                        response = crud.update_single(object_=object_, session=get_session())
                         headers_ = [{"Location": SERVER_URL+API_NAME+"/"+type_+"/"}]
                         status_code = int(list(response.keys())[0])
                         return set_response_headers(jsonify(response), headers=headers_, status_code=status_code)
@@ -210,7 +216,7 @@ class ItemCollection(Resource):
         if checkEndpoint("DELETE", type_):
             # No Delete Operation for collections
             if type_ in API_DOC.parsed_classes and type_+"Collection" not in API_DOC.collections:
-                response = crud.delete_single(type_)
+                response = crud.delete_single(type_, session=get_session())
                 status_code = int(list(response.keys())[0])
                 return set_response_headers(jsonify(response), status_code=status_code)
         abort(405)
@@ -241,8 +247,7 @@ class Contexts(Resource):
                 return set_response_headers(jsonify(response), status_code=404)
 
 
-api.add_resource(
-    Contexts, "/"+API_NAME+"/contexts/<string:category>.jsonld", endpoint="contexts")
+api.add_resource(Contexts, "/"+API_NAME+"/contexts/<string:category>.jsonld", endpoint="contexts")
 
 
 class Vocab(Resource):
@@ -276,12 +281,8 @@ def checkEndpoint(method, type_):
             for operation in endpoint.supportedOperation:
                 if operation.method == method:
                     return True
-    ## Check non endpoint collection classes
-    for class_ in API_DOC.parsed_classes.keys():
-        if class_ == type_ or class_ == type_.split("Collection")[0]:
-            for operation in API_DOC.parsed_classes[class_]["class"].supportedOperation:
-                if operation.method == method:
-                    return True
+    # NOTE: This is checking the EntryPoint object, no need to check class separately.
+    # Non collection classes will be present as an endpoint in the Entrypoint object
     return False
 
 
@@ -289,7 +290,8 @@ def getType(class_type, method):
     """Return the @type of object allowed for POST/PUT."""
     for supportedOp in API_DOC.parsed_classes[class_type]["class"].supportedOperation:
         if supportedOp.method == method:
-            return supportedOp.expects.split("vocab:")[-1]
+            return supportedOp.expects.replace("vocab:", "")
+    # NOTE: Don't use split, if there are more than one substrings with 'vocab:' not everything will be returned.
 
 
 def checkClassOp(class_type, method):
@@ -301,4 +303,5 @@ def checkClassOp(class_type, method):
 
 
 if __name__ == "__main__":
+    # pdb.set_trace()
     app.run(host='127.0.0.1', debug=True, port=8080)
diff --git a/hydrus/data/crud.py b/hydrus/data/crud.py
index f7fb406..d916556 100644
--- a/hydrus/data/crud.py
+++ b/hydrus/data/crud.py
@@ -124,7 +124,7 @@ def insert(object_, id_=None, session=session):
                     instance_object_result = insert(object_[prop_name], session=session)
                     if 201 in instance_object_result:
                         instance_object_id = int(instance_object_result[list(
-                            instance_object_result)[0]].split(" ")[3])
+                            instance_object_result)[0]].split("=")[1])
                         instance_object = session.query(Instance).filter(
                             Instance.id == instance_object_id).one()
                     else:
@@ -188,7 +188,7 @@ def insert(object_, id_=None, session=session):
 
     session.commit()
     # pdb.set_trace()
-    return {201: "Object with id %s successfully added!" % (instance.id)}
+    return {201: "Object successfully added! ID=%s" % (instance.id)}
 
 
 def delete(id_, type_, session=session):
@@ -233,7 +233,7 @@ def delete(id_, type_, session=session):
 
     session.delete(instance)
     session.commit()
-    return {200: "Object with ID : %s successfully deleted!" % (id_)}
+    return {200: "Object successfully deleted! ID=%s" % (id_)}
 
 
 def update(id_, type_, object_, session=session):
@@ -248,7 +248,7 @@ def update(id_, type_, object_, session=session):
         # Try inserting the new data
         insert_status = insert(object_=object_, id_=id_, session=session)
         if 201 in insert_status:
-            return {200: "Object with ID : %s successfully updated!" % (id_)}
+            return {200: "Object successfully updated! ID=%s" % (id_)}
         else:
             # Add the old object back
             insert(object_=instance, id_=id_, session=session)
diff --git a/hydrus/data/db_models.py b/hydrus/data/db_models.py
index df9f7c0..7740c53 100644
--- a/hydrus/data/db_models.py
+++ b/hydrus/data/db_models.py
@@ -10,9 +10,9 @@ db_path = os.path.join(os.path.dirname(__file__), 'database.db')
 # We'll use sqlite db if no db is provided
 DB_URL = os.environ.get("DB_URL", 'sqlite:///{}'.format(db_path))
 
-engine = create_engine(DB_URL)
+# engine = create_engine(DB_URL)
 
-# engine = create_engine("postgresql://hydra:hailhydra@localhost:5432/hydrus")
+engine = create_engine("postgresql://hydra:hailhydra@localhost:5432/hydrus")
 Base = declarative_base()
 
 
diff --git a/hydrus/data/doc_parse.py b/hydrus/data/doc_parse.py
index 812a7db..7891ee9 100644
--- a/hydrus/data/doc_parse.py
+++ b/hydrus/data/doc_parse.py
@@ -5,7 +5,7 @@ from sqlalchemy import exists
 from hydrus.data.db_models import RDFClass, BaseProperty, engine
 # from hydrus.metadata.drone.server_doc import server_doc
 # from hydrus.metadata.drone.drone_doc import drone_doc
-from hydrus.metadata.doc import doc
+from hydrus.metadata.doc_gen import doc_gen
 
 
 def get_classes(apidoc):
@@ -32,7 +32,7 @@ def get_all_properties(classes):
 
 def insert_classes(classes, session):
     """Insert all the classes as defined in the APIDocumentation into DB."""
-    print(session.query(exists().where(RDFClass.name == "Datastream")).scalar())
+    # print(session.query(exists().where(RDFClass.name == "Datastream")).scalar())
     class_list = [RDFClass(name=class_["label"].strip('.')) for class_ in classes
                   if "label" in class_ and
                   not session.query(exists().where(RDFClass.name == class_["label"].strip('.'))).scalar()]
@@ -40,7 +40,7 @@ def insert_classes(classes, session):
     class_list = class_list + [RDFClass(name=class_["title"].strip('.')) for class_ in classes
                                if "title" in class_ and
                                not session.query(exists().where(RDFClass.name == class_["title"].strip('.'))).scalar()]
-    print(class_list)
+    # print(class_list)
     session.add_all(class_list)
     session.commit()
     return None
@@ -59,8 +59,9 @@ if __name__ == "__main__":
     Session = sessionmaker(bind=engine)
     session = Session()
 
+    doc = doc_gen("test", "test")
     # Extract all classes with supportedProperty from both
-    classes = get_classes(doc)
+    classes = get_classes(doc.generate())
 
     # Extract all properties from both
     # import pdb; pdb.set_trace()
diff --git a/hydrus/hydraspec/doc_writer.py b/hydrus/hydraspec/doc_writer.py
index b9d92b5..84cdfba 100644
--- a/hydrus/hydraspec/doc_writer.py
+++ b/hydrus/hydraspec/doc_writer.py
@@ -176,7 +176,6 @@ class HydraClassOp():
         return op
 
 
-
 class HydraCollection():
     """Class for Hydra Collection."""
 
diff --git a/hydrus/metadata/doc.py b/hydrus/metadata/doc.py
index d3e873d..35395e5 100644
--- a/hydrus/metadata/doc.py
+++ b/hydrus/metadata/doc.py
@@ -1,4 +1,5 @@
-"""Generated API Documentation for Drone API using drone_doc_gen.py."""
+"""
+Generated API Documentation for Server API using server_doc_gen.py.
 
 doc = {
     "@context": {
@@ -42,68 +43,88 @@ doc = {
         "supportedOperation": "hydra:supportedOperation",
         "supportedProperty": "hydra:supportedProperty",
         "title": "hydra:title",
-        "vocab": "http://localhost/droneapi/vocab#",
+        "vocab": "http://localhost/serverapi/vocab#",
         "writeonly": "hydra:writeonly"
     },
-    "@id": "http://localhost/droneapi/vocab",
+    "@id": "http://localhost/serverapi/vocab",
     "@type": "ApiDocumentation",
-    "description": "API Documentation for the drone side system",
+    "description": "API Documentation for the server side system",
     "possibleStatus": [],
     "supportedClass": [
         {
-            "@id": "vocab:State",
+            "@id": "vocab:Area",
             "@type": "hydra:Class",
-            "description": "Class for drone state objects",
-            "supportedOperation": [],
-            "supportedProperty": [
+            "description": "Class for Area of Interest of the server",
+            "supportedOperation": [
                 {
-                    "@type": "SupportedProperty",
-                    "property": "http://auto.schema.org/speed",
-                    "readonly": "true",
-                    "required": "false",
-                    "title": "Speed",
-                    "writeonly": "false"
+                    "@type": "http://schema.org/UpdateAction",
+                    "expects": "vocab:Area",
+                    "method": "POST",
+                    "possibleStatus": [
+                        {
+                            "description": "Area of interest changed",
+                            "statusCode": 200
+                        }
+                    ],
+                    "returns": "null",
+                    "title": "UpdateArea"
                 },
                 {
-                    "@type": "SupportedProperty",
-                    "property": "http://schema.org/geo",
-                    "readonly": "true",
-                    "required": "false",
-                    "title": "Position",
-                    "writeonly": "false"
-                },
+                    "@type": "hydra:Operation",
+                    "expects": "null",
+                    "method": "GET",
+                    "possibleStatus": [
+                        {
+                            "description": "Area of interest not found",
+                            "statusCode": 404
+                        },
+                        {
+                            "description": "Area of interest returned",
+                            "statusCode": 200
+                        }
+                    ],
+                    "returns": "vocab:Area",
+                    "title": "GetArea"
+                }
+            ],
+            "supportedProperty": [
                 {
                     "@type": "SupportedProperty",
-                    "property": "http://schema.org/Property",
-                    "readonly": "true",
-                    "required": "false",
-                    "title": "Direction",
+                    "property": "http://schema.org/geo",
+                    "readonly": "false",
+                    "required": "true",
+                    "title": "TopLeft",
                     "writeonly": "false"
                 },
                 {
                     "@type": "SupportedProperty",
-                    "property": "http://schema.org/fuelCapacity",
-                    "readonly": "true",
-                    "required": "false",
-                    "title": "Battery",
-                    "writeonly": "true"
-                },
-                {
-                    "@type": "SupportedProperty",
-                    "property": "https://schema.org/status",
-                    "readonly": "true",
-                    "required": "false",
-                    "title": "SensorStatus",
+                    "property": "http://schema.org/geo",
+                    "readonly": "false",
+                    "required": "true",
+                    "title": "BottomRight",
                     "writeonly": "false"
                 }
             ],
-            "title": "State"
+            "title": "Area"
         },
         {
             "@id": "vocab:Drone",
             "@type": "hydra:Class",
             "description": "Class for a drone",
             "supportedOperation": [
+                {
+                    "@type": "http://schema.org/UpdateAction",
+                    "expects": "vocab:Drone",
+                    "method": "POST",
+                    "possibleStatus": [
+                        {
+                            "description": "Drone updated",
+                            "statusCode": 200
+                        }
+                    ],
+                    "returns": "null",
+                    "title": "SubmitDrone"
+                },
                 {
                     "@type": "hydra:Operation",
                     "expects": "null",
@@ -114,25 +135,12 @@ doc = {
                             "statusCode": 404
                         },
                         {
-                            "description": "Drone returned",
+                            "description": "Drone Returned",
                             "statusCode": 200
                         }
                     ],
                     "returns": "vocab:Drone",
                     "title": "GetDrone"
-                },
-                {
-                    "@type": "http://schema.org/UpdateAction",
-                    "expects": "vocab:Drone",
-                    "method": "POST",
-                    "possibleStatus": [
-                        {
-                            "description": "Drone updated",
-                            "statusCode": 200
-                        }
-                    ],
-                    "returns": "null",
-                    "title": "UpdateDrone"
                 }
             ],
             "supportedProperty": [
@@ -175,6 +183,55 @@ doc = {
                     "required": "true",
                     "title": "Sensor",
                     "writeonly": "false"
+                }
+            ],
+            "title": "Drone"
+        },
+        {
+            "@id": "vocab:State",
+            "@type": "hydra:Class",
+            "description": "Class for drone state objects",
+            "supportedOperation": [],
+            "supportedProperty": [
+                {
+                    "@type": "SupportedProperty",
+                    "property": "http://auto.schema.org/speed",
+                    "readonly": "false",
+                    "required": "true",
+                    "title": "Speed",
+                    "writeonly": "false"
+                },
+                {
+                    "@type": "SupportedProperty",
+                    "property": "http://schema.org/geo",
+                    "readonly": "false",
+                    "required": "true",
+                    "title": "Position",
+                    "writeonly": "false"
+                },
+                {
+                    "@type": "SupportedProperty",
+                    "property": "http://schema.org/Property",
+                    "readonly": "false",
+                    "required": "true",
+                    "title": "Direction",
+                    "writeonly": "false"
+                },
+                {
+                    "@type": "SupportedProperty",
+                    "property": "http://schema.org/fuelCapacity",
+                    "readonly": "false",
+                    "required": "true",
+                    "title": "Battery",
+                    "writeonly": "false"
+                },
+                {
+                    "@type": "SupportedProperty",
+                    "property": "https://schema.org/status",
+                    "readonly": "false",
+                    "required": "true",
+                    "title": "SensorStatus",
+                    "writeonly": "false"
                 },
                 {
                     "@type": "SupportedProperty",
@@ -185,12 +242,12 @@ doc = {
                     "writeonly": "false"
                 }
             ],
-            "title": "Drone"
+            "title": "State"
         },
         {
-            "@id": "vocab:Command",
+            "@id": "vocab:Message",
             "@type": "hydra:Class",
-            "description": "Class for drone commands",
+            "description": "Class for messages received by the GUI interface",
             "supportedOperation": [
                 {
                     "@type": "hydra:Operation",
@@ -198,68 +255,34 @@ doc = {
                     "method": "GET",
                     "possibleStatus": [
                         {
-                            "description": "Command not found",
+                            "description": "Message not found",
                             "statusCode": 404
                         },
                         {
-                            "description": "Command Returned",
-                            "statusCode": 200
-                        }
-                    ],
-                    "returns": "vocab:Command",
-                    "title": "GetCommand"
-                },
-                {
-                    "@type": "http://schema.org/AddAction",
-                    "expects": "vocab:Command",
-                    "method": "PUT",
-                    "possibleStatus": [
-                        {
-                            "description": "Command added",
-                            "statusCode": 201
-                        }
-                    ],
-                    "returns": "null",
-                    "title": "AddCommand"
-                },
-                {
-                    "@type": "http://schema.org/DeleteAction",
-                    "expects": "null",
-                    "method": "DELETE",
-                    "possibleStatus": [
-                        {
-                            "description": "Command deleted",
+                            "description": "Message returned",
                             "statusCode": 200
                         }
                     ],
-                    "returns": "null",
-                    "title": "DeleteCommand"
+                    "returns": "vocab:Message",
+                    "title": "GetMessage"
                 }
             ],
             "supportedProperty": [
                 {
                     "@type": "SupportedProperty",
-                    "property": "http://schema.org/identifier",
-                    "readonly": "false",
-                    "required": "true",
-                    "title": "DroneID",
-                    "writeonly": "false"
-                },
-                {
-                    "@type": "SupportedProperty",
-                    "property": "vocab:State",
+                    "property": "http://schema.org/Text",
                     "readonly": "false",
                     "required": "true",
-                    "title": "State",
+                    "title": "MessageString",
                     "writeonly": "false"
                 }
             ],
-            "title": "Command"
+            "title": "Message"
         },
         {
             "@id": "vocab:Datastream",
             "@type": "hydra:Class",
-            "description": "Class for a data entry from drone sensors",
+            "description": "Class for a datastream entry",
             "supportedOperation": [
                 {
                     "@type": "hydra:Operation",
@@ -267,29 +290,16 @@ doc = {
                     "method": "GET",
                     "possibleStatus": [
                         {
-                            "description": "Datastream not found",
+                            "description": "Data not found",
                             "statusCode": 404
                         },
                         {
-                            "description": "Datastream returned",
+                            "description": "Data returned",
                             "statusCode": 200
                         }
                     ],
                     "returns": "vocab:Datastream",
-                    "title": "GetDatastream"
-                },
-                {
-                    "@type": "http://schema.org/UpdateAction",
-                    "expects": "vocab:Datastream",
-                    "method": "POST",
-                    "possibleStatus": [
-                        {
-                            "description": "Datastream updated",
-                            "statusCode": 200
-                        }
-                    ],
-                    "returns": "null",
-                    "title": "UpdateDatastream"
+                    "title": "ReadDatastream"
                 }
             ],
             "supportedProperty": [
@@ -321,75 +331,386 @@ doc = {
             "title": "Datastream"
         },
         {
-            "@id": "http://www.w3.org/ns/hydra/core#Collection",
-            "@type": "hydra:Class",
-            "description": "null",
-            "supportedOperation": [],
-            "supportedProperty": [
-                {
-                    "@type": "SupportedProperty",
-                    "property": "http://www.w3.org/ns/hydra/core#member",
-                    "readonly": "false",
-                    "required": "null",
-                    "title": "members",
-                    "writeonly": "false"
-                }
-            ],
-            "title": "Collection"
-        },
-        {
-            "@id": "http://www.w3.org/ns/hydra/core#Resource",
-            "@type": "hydra:Class",
-            "description": "null",
-            "supportedOperation": [],
-            "supportedProperty": [],
-            "title": "Resource"
-        },
-        {
-            "@id": "vocab:CommandCollection",
+            "@id": "vocab:LogEntry",
             "@type": "hydra:Class",
-            "description": "A collection of command",
-            "label": "CommandCollection",
-            "subClassOf": "http://www.w3.org/ns/hydra/core#Collection",
+            "description": "Class for a log entry",
             "supportedOperation": [
                 {
-                    "@id": "_:command_collection_retrieve",
                     "@type": "hydra:Operation",
-                    "description": "Retrieves all Command entities",
                     "expects": "null",
                     "method": "GET",
-                    "returns": "vocab:CommandCollection",
-                    "statusCodes": []
-                },
-                {
-                    "@id": "_:command_create",
-                    "@type": "http://schema.org/AddAction",
-                    "description": "Create new Command entitity",
-                    "expects": "vocab:Command",
-                    "method": "PUT",
-                    "returns": "vocab:Command",
-                    "statusCodes": [
+                    "possibleStatus": [
                         {
-                            "description": "If the Command entity was created successfully.",
-                            "statusCode": 201
+                            "description": "Log entry not found",
+                            "statusCode": 404
+                        },
+                        {
+                            "description": "Log entry returned",
+                            "statusCode": 200
                         }
-                    ]
+                    ],
+                    "returns": "vocab:LogEntry",
+                    "title": "GetLog"
                 }
             ],
             "supportedProperty": [
                 {
                     "@type": "SupportedProperty",
-                    "description": "The command",
-                    "property": "http://www.w3.org/ns/hydra/core#member",
+                    "property": "http://schema.org/identifier",
+                    "readonly": "true",
+                    "required": "false",
+                    "title": "DroneID",
+                    "writeonly": "true"
+                },
+                {
+                    "@type": "SupportedProperty",
+                    "property": "http://schema.org/UpdateAction",
                     "readonly": "false",
                     "required": "false",
-                    "title": "members",
-                    "writeonly": "false"
-                }
-            ]
-        },
-        {
-            "@id": "vocab:EntryPoint",
+                    "title": "Update",
+                    "writeonly": "true"
+                },
+                {
+                    "@type": "SupportedProperty",
+                    "property": "http://schema.org/ReplyAction",
+                    "readonly": "false",
+                    "required": "false",
+                    "title": "Get",
+                    "writeonly": "true"
+                },
+                {
+                    "@type": "SupportedProperty",
+                    "property": "http://schema.org/SendAction",
+                    "readonly": "false",
+                    "required": "false",
+                    "title": "Send",
+                    "writeonly": "true"
+                },
+                {
+                    "@type": "SupportedProperty",
+                    "property": "vocab:State",
+                    "readonly": "false",
+                    "required": "false",
+                    "title": "State",
+                    "writeonly": "true"
+                },
+                {
+                    "@type": "SupportedProperty",
+                    "property": "vocab:Datastream",
+                    "readonly": "false",
+                    "required": "false",
+                    "title": "Data",
+                    "writeonly": "true"
+                },
+                {
+                    "@type": "SupportedProperty",
+                    "property": "vocab:Command",
+                    "readonly": "false",
+                    "required": "false",
+                    "title": "Command",
+                    "writeonly": "true"
+                }
+            ],
+            "title": "LogEntry"
+        },
+        {
+            "@id": "vocab:Command",
+            "@type": "hydra:Class",
+            "description": "Class for drone commands",
+            "supportedOperation": [
+                {
+                    "@type": "hydra:Operation",
+                    "expects": "null",
+                    "method": "GET",
+                    "possibleStatus": [
+                        {
+                            "description": "Command not found",
+                            "statusCode": 404
+                        },
+                        {
+                            "description": "Command Returned",
+                            "statusCode": 200
+                        }
+                    ],
+                    "returns": "vocab:Command",
+                    "title": "GetCommand"
+                },
+                {
+                    "@type": "http://schema.org/AddAction",
+                    "expects": "vocab:Command",
+                    "method": "PUT",
+                    "possibleStatus": [
+                        {
+                            "description": "Command added",
+                            "statusCode": 201
+                        }
+                    ],
+                    "returns": "null",
+                    "title": "AddCommand"
+                }
+            ],
+            "supportedProperty": [
+                {
+                    "@type": "SupportedProperty",
+                    "property": "http://schema.org/identifier",
+                    "readonly": "false",
+                    "required": "true",
+                    "title": "DroneID",
+                    "writeonly": "false"
+                },
+                {
+                    "@type": "SupportedProperty",
+                    "property": "vocab:State",
+                    "readonly": "false",
+                    "required": "true",
+                    "title": "State",
+                    "writeonly": "false"
+                }
+            ],
+            "title": "Command"
+        },
+        {
+            "@id": "http://www.w3.org/ns/hydra/core#Resource",
+            "@type": "hydra:Class",
+            "description": "null",
+            "supportedOperation": [],
+            "supportedProperty": [],
+            "title": "Resource"
+        },
+        {
+            "@id": "http://www.w3.org/ns/hydra/core#Collection",
+            "@type": "hydra:Class",
+            "description": "null",
+            "supportedOperation": [],
+            "supportedProperty": [
+                {
+                    "@type": "SupportedProperty",
+                    "property": "http://www.w3.org/ns/hydra/core#member",
+                    "readonly": "false",
+                    "required": "null",
+                    "title": "members",
+                    "writeonly": "false"
+                }
+            ],
+            "title": "Collection"
+        },
+        {
+            "@id": "vocab:CommandCollection",
+            "@type": "hydra:Class",
+            "description": "A collection of command",
+            "label": "CommandCollection",
+            "subClassOf": "http://www.w3.org/ns/hydra/core#Collection",
+            "supportedOperation": [
+                {
+                    "@id": "_:command_collection_retrieve",
+                    "@type": "hydra:Operation",
+                    "description": "Retrieves all Command entities",
+                    "expects": "null",
+                    "method": "GET",
+                    "returns": "vocab:CommandCollection",
+                    "statusCodes": []
+                },
+                {
+                    "@id": "_:command_create",
+                    "@type": "http://schema.org/AddAction",
+                    "description": "Create new Command entitity",
+                    "expects": "vocab:Command",
+                    "method": "PUT",
+                    "returns": "vocab:Command",
+                    "statusCodes": [
+                        {
+                            "description": "If the Command entity was created successfully.",
+                            "statusCode": 201
+                        }
+                    ]
+                }
+            ],
+            "supportedProperty": [
+                {
+                    "@type": "SupportedProperty",
+                    "description": "The command",
+                    "property": "http://www.w3.org/ns/hydra/core#member",
+                    "readonly": "false",
+                    "required": "false",
+                    "title": "members",
+                    "writeonly": "false"
+                }
+            ]
+        },
+        {
+            "@id": "vocab:LogEntryCollection",
+            "@type": "hydra:Class",
+            "description": "A collection of logentry",
+            "label": "LogEntryCollection",
+            "subClassOf": "http://www.w3.org/ns/hydra/core#Collection",
+            "supportedOperation": [
+                {
+                    "@id": "_:logentry_collection_retrieve",
+                    "@type": "hydra:Operation",
+                    "description": "Retrieves all LogEntry entities",
+                    "expects": "null",
+                    "method": "GET",
+                    "returns": "vocab:LogEntryCollection",
+                    "statusCodes": []
+                },
+                {
+                    "@id": "_:logentry_create",
+                    "@type": "http://schema.org/AddAction",
+                    "description": "Create new LogEntry entitity",
+                    "expects": "vocab:LogEntry",
+                    "method": "PUT",
+                    "returns": "vocab:LogEntry",
+                    "statusCodes": [
+                        {
+                            "description": "If the LogEntry entity was created successfully.",
+                            "statusCode": 201
+                        }
+                    ]
+                }
+            ],
+            "supportedProperty": [
+                {
+                    "@type": "SupportedProperty",
+                    "description": "The logentry",
+                    "property": "http://www.w3.org/ns/hydra/core#member",
+                    "readonly": "false",
+                    "required": "false",
+                    "title": "members",
+                    "writeonly": "false"
+                }
+            ]
+        },
+        {
+            "@id": "vocab:DroneCollection",
+            "@type": "hydra:Class",
+            "description": "A collection of drone",
+            "label": "DroneCollection",
+            "subClassOf": "http://www.w3.org/ns/hydra/core#Collection",
+            "supportedOperation": [
+                {
+                    "@id": "_:drone_collection_retrieve",
+                    "@type": "hydra:Operation",
+                    "description": "Retrieves all Drone entities",
+                    "expects": "null",
+                    "method": "GET",
+                    "returns": "vocab:DroneCollection",
+                    "statusCodes": []
+                },
+                {
+                    "@id": "_:drone_create",
+                    "@type": "http://schema.org/AddAction",
+                    "description": "Create new Drone entitity",
+                    "expects": "vocab:Drone",
+                    "method": "PUT",
+                    "returns": "vocab:Drone",
+                    "statusCodes": [
+                        {
+                            "description": "If the Drone entity was created successfully.",
+                            "statusCode": 201
+                        }
+                    ]
+                }
+            ],
+            "supportedProperty": [
+                {
+                    "@type": "SupportedProperty",
+                    "description": "The drone",
+                    "property": "http://www.w3.org/ns/hydra/core#member",
+                    "readonly": "false",
+                    "required": "false",
+                    "title": "members",
+                    "writeonly": "false"
+                }
+            ]
+        },
+        {
+            "@id": "vocab:MessageCollection",
+            "@type": "hydra:Class",
+            "description": "A collection of message",
+            "label": "MessageCollection",
+            "subClassOf": "http://www.w3.org/ns/hydra/core#Collection",
+            "supportedOperation": [
+                {
+                    "@id": "_:message_collection_retrieve",
+                    "@type": "hydra:Operation",
+                    "description": "Retrieves all Message entities",
+                    "expects": "null",
+                    "method": "GET",
+                    "returns": "vocab:MessageCollection",
+                    "statusCodes": []
+                },
+                {
+                    "@id": "_:message_create",
+                    "@type": "http://schema.org/AddAction",
+                    "description": "Create new Message entitity",
+                    "expects": "vocab:Message",
+                    "method": "PUT",
+                    "returns": "vocab:Message",
+                    "statusCodes": [
+                        {
+                            "description": "If the Message entity was created successfully.",
+                            "statusCode": 201
+                        }
+                    ]
+                }
+            ],
+            "supportedProperty": [
+                {
+                    "@type": "SupportedProperty",
+                    "description": "The message",
+                    "property": "http://www.w3.org/ns/hydra/core#member",
+                    "readonly": "false",
+                    "required": "false",
+                    "title": "members",
+                    "writeonly": "false"
+                }
+            ]
+        },
+        {
+            "@id": "vocab:DatastreamCollection",
+            "@type": "hydra:Class",
+            "description": "A collection of datastream",
+            "label": "DatastreamCollection",
+            "subClassOf": "http://www.w3.org/ns/hydra/core#Collection",
+            "supportedOperation": [
+                {
+                    "@id": "_:datastream_collection_retrieve",
+                    "@type": "hydra:Operation",
+                    "description": "Retrieves all Datastream entities",
+                    "expects": "null",
+                    "method": "GET",
+                    "returns": "vocab:DatastreamCollection",
+                    "statusCodes": []
+                },
+                {
+                    "@id": "_:datastream_create",
+                    "@type": "http://schema.org/AddAction",
+                    "description": "Create new Datastream entitity",
+                    "expects": "vocab:Datastream",
+                    "method": "PUT",
+                    "returns": "vocab:Datastream",
+                    "statusCodes": [
+                        {
+                            "description": "If the Datastream entity was created successfully.",
+                            "statusCode": 201
+                        }
+                    ]
+                }
+            ],
+            "supportedProperty": [
+                {
+                    "@type": "SupportedProperty",
+                    "description": "The datastream",
+                    "property": "http://www.w3.org/ns/hydra/core#member",
+                    "readonly": "false",
+                    "required": "false",
+                    "title": "members",
+                    "writeonly": "false"
+                }
+            ]
+        },
+        {
+            "@id": "vocab:EntryPoint",
             "@type": "hydra:Class",
             "description": "The main entry point or homepage of the API.",
             "supportedOperation": [
@@ -405,47 +726,87 @@ doc = {
             ],
             "supportedProperty": [
                 {
-                    "hydra:description": "The Drone Class",
-                    "hydra:title": "drone",
+                    "hydra:description": "The Area Class",
+                    "hydra:title": "area",
                     "property": {
-                        "@id": "vocab:EntryPoint/Drone",
+                        "@id": "vocab:EntryPoint/Area",
                         "@type": "hydra:Link",
-                        "description": "Class for a drone",
+                        "description": "Class for Area of Interest of the server",
                         "domain": "vocab:EntryPoint",
-                        "label": "Drone",
-                        "range": "vocab:Drone",
+                        "label": "Area",
+                        "range": "vocab:Area",
                         "supportedOperation": [
                             {
-                                "@id": "_:getdrone",
+                                "@id": "_:updatearea",
+                                "@type": "hydra:Operation",
+                                "description": "null",
+                                "expects": "vocab:Area",
+                                "label": "UpdateArea",
+                                "method": "POST",
+                                "returns": "null",
+                                "statusCodes": [
+                                    {
+                                        "description": "Area of interest changed",
+                                        "statusCode": 200
+                                    }
+                                ]
+                            },
+                            {
+                                "@id": "_:getarea",
                                 "@type": "hydra:Operation",
                                 "description": "null",
                                 "expects": "null",
-                                "label": "GetDrone",
+                                "label": "GetArea",
                                 "method": "GET",
-                                "returns": "vocab:Drone",
+                                "returns": "vocab:Area",
                                 "statusCodes": [
                                     {
-                                        "description": "Drone not found",
+                                        "description": "Area of interest not found",
                                         "statusCode": 404
                                     },
                                     {
-                                        "description": "Drone returned",
+                                        "description": "Area of interest returned",
                                         "statusCode": 200
                                     }
                                 ]
-                            },
+                            }
+                        ]
+                    },
+                    "readonly": "true",
+                    "required": "null",
+                    "writeonly": "false"
+                },
+                {
+                    "hydra:description": "The CommandCollection collection",
+                    "hydra:title": "commandcollection",
+                    "property": {
+                        "@id": "vocab:EntryPoint/CommandCollection",
+                        "@type": "hydra:Link",
+                        "description": "The CommandCollection collection",
+                        "domain": "vocab:EntryPoint",
+                        "label": "CommandCollection",
+                        "range": "vocab:CommandCollection",
+                        "supportedOperation": [
                             {
-                                "@id": "_:updatedrone",
+                                "@id": "_:_:command_collection_retrieve",
                                 "@type": "hydra:Operation",
-                                "description": "null",
-                                "expects": "vocab:Drone",
-                                "label": "UpdateDrone",
-                                "method": "POST",
-                                "returns": "null",
+                                "description": "Retrieves all Command entities",
+                                "expects": "null",
+                                "method": "GET",
+                                "returns": "vocab:CommandCollection",
+                                "statusCodes": []
+                            },
+                            {
+                                "@id": "_:_:command_create",
+                                "@type": "http://schema.org/AddAction",
+                                "description": "Create new Command entitity",
+                                "expects": "vocab:Command",
+                                "method": "PUT",
+                                "returns": "vocab:Command",
                                 "statusCodes": [
                                     {
-                                        "description": "Drone updated",
-                                        "statusCode": 200
+                                        "description": "If the Command entity was created successfully.",
+                                        "statusCode": 201
                                     }
                                 ]
                             }
@@ -456,47 +817,116 @@ doc = {
                     "writeonly": "false"
                 },
                 {
-                    "hydra:description": "The Datastream Class",
-                    "hydra:title": "datastream",
+                    "hydra:description": "The LogEntryCollection collection",
+                    "hydra:title": "logentrycollection",
                     "property": {
-                        "@id": "vocab:EntryPoint/Datastream",
+                        "@id": "vocab:EntryPoint/LogEntryCollection",
                         "@type": "hydra:Link",
-                        "description": "Class for a data entry from drone sensors",
+                        "description": "The LogEntryCollection collection",
                         "domain": "vocab:EntryPoint",
-                        "label": "Datastream",
-                        "range": "vocab:Datastream",
+                        "label": "LogEntryCollection",
+                        "range": "vocab:LogEntryCollection",
                         "supportedOperation": [
                             {
-                                "@id": "_:getdatastream",
+                                "@id": "_:_:logentry_collection_retrieve",
                                 "@type": "hydra:Operation",
-                                "description": "null",
+                                "description": "Retrieves all LogEntry entities",
                                 "expects": "null",
-                                "label": "GetDatastream",
                                 "method": "GET",
-                                "returns": "vocab:Datastream",
+                                "returns": "vocab:LogEntryCollection",
+                                "statusCodes": []
+                            },
+                            {
+                                "@id": "_:_:logentry_create",
+                                "@type": "http://schema.org/AddAction",
+                                "description": "Create new LogEntry entitity",
+                                "expects": "vocab:LogEntry",
+                                "method": "PUT",
+                                "returns": "vocab:LogEntry",
                                 "statusCodes": [
                                     {
-                                        "description": "Datastream not found",
-                                        "statusCode": 404
-                                    },
-                                    {
-                                        "description": "Datastream returned",
-                                        "statusCode": 200
+                                        "description": "If the LogEntry entity was created successfully.",
+                                        "statusCode": 201
                                     }
                                 ]
+                            }
+                        ]
+                    },
+                    "readonly": "true",
+                    "required": "null",
+                    "writeonly": "false"
+                },
+                {
+                    "hydra:description": "The DroneCollection collection",
+                    "hydra:title": "dronecollection",
+                    "property": {
+                        "@id": "vocab:EntryPoint/DroneCollection",
+                        "@type": "hydra:Link",
+                        "description": "The DroneCollection collection",
+                        "domain": "vocab:EntryPoint",
+                        "label": "DroneCollection",
+                        "range": "vocab:DroneCollection",
+                        "supportedOperation": [
+                            {
+                                "@id": "_:_:drone_collection_retrieve",
+                                "@type": "hydra:Operation",
+                                "description": "Retrieves all Drone entities",
+                                "expects": "null",
+                                "method": "GET",
+                                "returns": "vocab:DroneCollection",
+                                "statusCodes": []
                             },
                             {
-                                "@id": "_:updatedatastream",
+                                "@id": "_:_:drone_create",
+                                "@type": "http://schema.org/AddAction",
+                                "description": "Create new Drone entitity",
+                                "expects": "vocab:Drone",
+                                "method": "PUT",
+                                "returns": "vocab:Drone",
+                                "statusCodes": [
+                                    {
+                                        "description": "If the Drone entity was created successfully.",
+                                        "statusCode": 201
+                                    }
+                                ]
+                            }
+                        ]
+                    },
+                    "readonly": "true",
+                    "required": "null",
+                    "writeonly": "false"
+                },
+                {
+                    "hydra:description": "The MessageCollection collection",
+                    "hydra:title": "messagecollection",
+                    "property": {
+                        "@id": "vocab:EntryPoint/MessageCollection",
+                        "@type": "hydra:Link",
+                        "description": "The MessageCollection collection",
+                        "domain": "vocab:EntryPoint",
+                        "label": "MessageCollection",
+                        "range": "vocab:MessageCollection",
+                        "supportedOperation": [
+                            {
+                                "@id": "_:_:message_collection_retrieve",
                                 "@type": "hydra:Operation",
-                                "description": "null",
-                                "expects": "vocab:Datastream",
-                                "label": "UpdateDatastream",
-                                "method": "POST",
-                                "returns": "null",
+                                "description": "Retrieves all Message entities",
+                                "expects": "null",
+                                "method": "GET",
+                                "returns": "vocab:MessageCollection",
+                                "statusCodes": []
+                            },
+                            {
+                                "@id": "_:_:message_create",
+                                "@type": "http://schema.org/AddAction",
+                                "description": "Create new Message entitity",
+                                "expects": "vocab:Message",
+                                "method": "PUT",
+                                "returns": "vocab:Message",
                                 "statusCodes": [
                                     {
-                                        "description": "Datastream updated",
-                                        "statusCode": 200
+                                        "description": "If the Message entity was created successfully.",
+                                        "statusCode": 201
                                     }
                                 ]
                             }
@@ -507,35 +937,35 @@ doc = {
                     "writeonly": "false"
                 },
                 {
-                    "hydra:description": "The CommandCollection collection",
-                    "hydra:title": "commandcollection",
+                    "hydra:description": "The DatastreamCollection collection",
+                    "hydra:title": "datastreamcollection",
                     "property": {
-                        "@id": "vocab:EntryPoint/CommandCollection",
+                        "@id": "vocab:EntryPoint/DatastreamCollection",
                         "@type": "hydra:Link",
-                        "description": "The CommandCollection collection",
+                        "description": "The DatastreamCollection collection",
                         "domain": "vocab:EntryPoint",
-                        "label": "CommandCollection",
-                        "range": "vocab:CommandCollection",
+                        "label": "DatastreamCollection",
+                        "range": "vocab:DatastreamCollection",
                         "supportedOperation": [
                             {
-                                "@id": "_:_:command_collection_retrieve",
+                                "@id": "_:_:datastream_collection_retrieve",
                                 "@type": "hydra:Operation",
-                                "description": "Retrieves all Command entities",
+                                "description": "Retrieves all Datastream entities",
                                 "expects": "null",
                                 "method": "GET",
-                                "returns": "vocab:CommandCollection",
+                                "returns": "vocab:DatastreamCollection",
                                 "statusCodes": []
                             },
                             {
-                                "@id": "_:_:command_create",
+                                "@id": "_:_:datastream_create",
                                 "@type": "http://schema.org/AddAction",
-                                "description": "Create new Command entitity",
-                                "expects": "vocab:Command",
+                                "description": "Create new Datastream entitity",
+                                "expects": "vocab:Datastream",
                                 "method": "PUT",
-                                "returns": "vocab:Command",
+                                "returns": "vocab:Datastream",
                                 "statusCodes": [
                                     {
-                                        "description": "If the Command entity was created successfully.",
+                                        "description": "If the Datastream entity was created successfully.",
                                         "statusCode": 201
                                     }
                                 ]
@@ -551,3 +981,4 @@ doc = {
         }
     ]
 }
+"""
\ No newline at end of file
diff --git a/hydrus/metadata/doc_gen.py b/hydrus/metadata/doc_gen.py
index a0425dd..7b79501 100644
--- a/hydrus/metadata/doc_gen.py
+++ b/hydrus/metadata/doc_gen.py
@@ -1,58 +1,59 @@
-"""API Doc generator for the drone side API."""
+"""API Doc generator for the server side API."""
 
 from hydrus.hydraspec.doc_writer import HydraDoc, HydraClass, HydraClassProp, HydraClassOp
 import json
 
 
 def doc_gen(API, BASE_URL):
-    """Generate API Doc for drone."""
+    """Generate API Doc for server."""
     # Main API Doc
     api_doc = HydraDoc(API,
-                       "API Doc for the drone side API",
-                       "API Documentation for the drone side system",
+                       "API Doc for the server side API",
+                       "API Documentation for the server side system",
                        API,
                        BASE_URL)
 
     # State Class
-    # NOTE: Each drone will have only one State Class, this can't be deleted. Only read and update.
     state = HydraClass("State", "State", "Class for drone state objects")
     # Properties
-    state.add_supported_prop(HydraClassProp("http://auto.schema.org/speed", "Speed", True, False, False))
-    state.add_supported_prop(HydraClassProp("http://schema.org/geo", "Position", True, False, False))
-    state.add_supported_prop(HydraClassProp("http://schema.org/Property", "Direction", True, False, False))
-    state.add_supported_prop(HydraClassProp("http://schema.org/fuelCapacity", "Battery", True, True, False))
-    state.add_supported_prop(HydraClassProp("https://schema.org/status", "SensorStatus", True, False, False))
+    state.add_supported_prop(HydraClassProp("http://auto.schema.org/speed", "Speed", False, False, True))
+    state.add_supported_prop(HydraClassProp("http://schema.org/geo", "Position", False, False, True))
+    state.add_supported_prop(HydraClassProp("http://schema.org/Property", "Direction", False, False, True))
+    state.add_supported_prop(HydraClassProp("http://schema.org/fuelCapacity", "Battery", False, False, True))
+    state.add_supported_prop(HydraClassProp("https://schema.org/status", "SensorStatus", False, False, True))
+    state.add_supported_prop(HydraClassProp("http://schema.org/identifier", "DroneID", False, False, True))
 
     # Drone Class
-    # NOTE: The actual changes to the drone are to be made at the /api/Drone URI.
-    # GET will return current State. POST will update the State.
-    drone = HydraClass("Drone", "Drone", "Class for a drone", endpoint=True)
+    drone = HydraClass("Drone", "Drone", "Class for a drone")
     # Properties
-    drone.add_supported_prop(HydraClassProp("vocab:State", "DroneState", False, False , True))
-    drone.add_supported_prop(HydraClassProp("http://schema.org/name", "name", False, False , True))
-    drone.add_supported_prop(HydraClassProp("http://schema.org/model", "model", False, False , True))
-    drone.add_supported_prop(HydraClassProp("http://auto.schema.org/speed", "MaxSpeed", False, False , True))
-    drone.add_supported_prop(HydraClassProp("http://schema.org/device", "Sensor", False, False , True))
-    drone.add_supported_prop(HydraClassProp("http://schema.org/identifier", "DroneID", False, False , True))
+    drone.add_supported_prop(HydraClassProp("vocab:State", "DroneState", False, False, True))
+    drone.add_supported_prop(HydraClassProp("http://schema.org/name", "name", False, False, True))
+    drone.add_supported_prop(HydraClassProp("http://schema.org/model", "model", False, False, True))
+    drone.add_supported_prop(HydraClassProp("http://auto.schema.org/speed", "MaxSpeed", False, False, True))
+    drone.add_supported_prop(HydraClassProp("http://schema.org/device", "Sensor", False, False, True))
     # Operations
+    # Drones will submit their state to the server at certain intervals or when some event happens
+    drone.add_supported_op(HydraClassOp("SubmitDrone",
+                                        "POST",
+                                        "vocab:Drone",
+                                        None,
+                                        [{"statusCode": 200, "description": "Drone updated"}]))
+    drone.add_supported_op(HydraClassOp("CreateDrone",
+                                        "PUT",
+                                        "vocab:Drone",
+                                        None,
+                                        [{"statusCode": 200, "description": "Drone added"}]))
     drone.add_supported_op(HydraClassOp("GetDrone",
                                         "GET",
                                         None,
                                         "vocab:Drone",
                                         [{"statusCode": 404, "description": "Drone not found"},
-                                         {"statusCode": 200, "description": "Drone returned"}]))
-    # When new commands are issued, mechanics will need to change the state of the drone
-    drone.add_supported_op(HydraClassOp("UpdateDrone",
-                                        "POST",
-                                        "vocab:Drone",
-                                        None,
-                                        [{"statusCode": 200, "description": "Drone updated"}]))
+                                         {"statusCode": 200, "description": "Drone Returned"}]))
 
-    # Command Class
     # NOTE: Commands are stored in a collection. You may GET a command or you may DELETE it, there is not UPDATE.
     command = HydraClass("Command", "Command", "Class for drone commands")
-    command.add_supported_prop(HydraClassProp("http://schema.org/identifier", "DroneID", False, False , True))
-    command.add_supported_prop(HydraClassProp("vocab:State", "State", False, False , True))
+    command.add_supported_prop(HydraClassProp("http://schema.org/identifier", "DroneID", False, False, True))
+    command.add_supported_prop(HydraClassProp("vocab:State", "State", False, False, True))
     # Used by mechanics to get newly added commands
     command.add_supported_op(HydraClassOp("GetCommand",
                                           "GET",
@@ -66,50 +67,114 @@ def doc_gen(API, BASE_URL):
                                           "vocab:Command",
                                           None,
                                           [{"statusCode": 201, "description": "Command added"}]))
-    # Used by mechanics to delete command after it has been executed
+
     command.add_supported_op(HydraClassOp("DeleteCommand",
                                           "DELETE",
                                           None,
                                           None,
-                                          [{"statusCode": 200, "description": "Command deleted"}]))
+                                          [{"statusCode": 201, "description": "Command deleted"}]))
 
-    # Data class
-    # NOTE: This is for the Data to be captured/generated. The mechanics module will enter random data and POST it.
-    # The server will read[GET] the data when it needs it. No need for collections. Only one instance showing current reading of sensor
-    # The URI is /api/Data
-    datastream = HydraClass("Datastream", "Datastream", "Class for a data entry from drone sensors", endpoint=True)
-    datastream.add_supported_prop(HydraClassProp("http://schema.org/QuantitativeValue", "Temperature", False, False , True))
-    datastream.add_supported_prop(HydraClassProp("http://schema.org/identifier", "DroneID", False, False , True))
-    datastream.add_supported_prop(HydraClassProp("http://schema.org/geo", "Position", False, False , True))
-    datastream.add_supported_op(HydraClassOp("GetDatastream",
-                                       "GET",
-                                       None,
-                                       "vocab:Datastream",
-                                       [{"statusCode": 404, "description": "Datastream not found"},
-                                        {"statusCode": 200, "description": "Datastream returned"}]))
+    # Logs to be accessed mostly by the GUI. Mechanics should add logs for every event.
+    log = HydraClass("LogEntry", "LogEntry", "Class for a log entry")
+    # Subject
+    log.add_supported_prop(HydraClassProp("http://schema.org/identifier", "DroneID", True, True, False))
+    # Predicate
+    log.add_supported_prop(HydraClassProp("http://schema.org/UpdateAction", "Update", False, True, False))
+    log.add_supported_prop(HydraClassProp("http://schema.org/ReplyAction", "Get", False, True, False))
+    log.add_supported_prop(HydraClassProp("http://schema.org/SendAction", "Send", False, True, False))
+    # Objects
+    log.add_supported_prop(HydraClassProp("vocab:State", "State", False, True, False))
+    log.add_supported_prop(HydraClassProp("vocab:Datastream", "Data", False, True, False))
+    log.add_supported_prop(HydraClassProp("vocab:Command", "Command", False, True, False))
+    # GUI will get a certain log entry.
+    log.add_supported_op(HydraClassOp("GetLog",
+                                      "GET",
+                                      None,
+                                      "vocab:LogEntry",
+                                      [{"statusCode": 404, "description": "Log entry not found"},
+                                       {"statusCode": 200, "description": "Log entry returned"}]))
+    log.add_supported_op(HydraClassOp("AddLog",
+                                      "PUT",
+                                      "vocab:LogEntry",
+                                      None,
+                                      [{"statusCode": 201, "description": "Log entry created"}]))
+
+    # Data is stored as a collection. Each data object can be read.
+    # New data added to the collection
+    datastream = HydraClass("Datastream", "Datastream", "Class for a datastream entry")
+    datastream.add_supported_prop(HydraClassProp("http://schema.org/QuantitativeValue", "Temperature", False, False, True))
+    datastream.add_supported_prop(HydraClassProp("http://schema.org/identifier", "DroneID", False, False, True))
+    datastream.add_supported_prop(HydraClassProp("http://schema.org/geo", "Position", False, False, True))
+    datastream.add_supported_op(HydraClassOp("ReadDatastream",
+                                             "GET",
+                                             None,
+                                             "vocab:Datastream",
+                                             [{"statusCode": 404, "description": "Data not found"},
+                                              {"statusCode": 200, "description": "Data returned"}]))
     datastream.add_supported_op(HydraClassOp("UpdateDatastream",
+                                             "POST",
+                                             "vocab:Datastream",
+                                             None,
+                                             [{"statusCode": 200, "description": "Data updated"}]))
+    datastream.add_supported_op(HydraClassOp("DeleteDatastream",
+                                             "DELETE",
+                                             None,
+                                             None,
+                                             [{"statusCode": 200, "description": "Data deleted"}]))
+
+    # Single object representing the area of interest. No collections.
+    area = HydraClass("Area", "Area", "Class for Area of Interest of the server", endpoint=True)
+    # Using two positions to have a bounding box
+    area.add_supported_prop(HydraClassProp("http://schema.org/geo", "TopLeft", False, False, True))
+    area.add_supported_prop(HydraClassProp("http://schema.org/geo", "BottomRight", False, False, True))
+    # Allowing updation of the area of interest
+    area.add_supported_op(HydraClassOp("UpdateArea",
                                        "POST",
-                                       "vocab:Datastream",
+                                       "vocab:Area",
+                                       None,
+                                       [{"statusCode": 200, "description": "Area of interest changed"}]))
+    area.add_supported_op(HydraClassOp("GetArea",
+                                       "GET",
                                        None,
-                                       [{"statusCode": 200, "description": "Datastream updated"}]))
+                                       "vocab:Area",
+                                       [{"statusCode": 404, "description": "Area of interest not found"},
+                                        {"statusCode": 200, "description": "Area of interest returned"}]))
+
+    message = HydraClass("Message", "Message", "Class for messages received by the GUI interface")
+    message.add_supported_prop(HydraClassProp("http://schema.org/Text", "MessageString", False, False, True))
+    message.add_supported_op(HydraClassOp("GetMessage",
+                                          "GET",
+                                          None,
+                                          "vocab:Message",
+                                          [{"statusCode": 404, "description": "Message not found"},
+                                           {"statusCode": 200, "description": "Message returned"}]))
+    message.add_supported_op(HydraClassOp("DeleteMessage",
+                                          "DELETE",
+                                          None,
+                                          None,
+                                          [{"statusCode": 200, "description": "Message deleted"}]))
 
+    api_doc.add_supported_class(drone, collection=True)
     api_doc.add_supported_class(state, collection=False)
-    api_doc.add_supported_class(drone, collection=False)
+    api_doc.add_supported_class(datastream, collection=True)
+    api_doc.add_supported_class(log, collection=True)
+    api_doc.add_supported_class(area, collection=False)
     api_doc.add_supported_class(command, collection=True)
-    api_doc.add_supported_class(datastream, collection=False)
+    api_doc.add_supported_class(message, collection=True)
 
-    api_doc.add_baseCollection()
     api_doc.add_baseResource()
+    api_doc.add_baseCollection()
     api_doc.gen_EntryPoint()
     return api_doc
 
 
 if __name__ == "__main__":
-    dump = json.dumps(drone_doc("droneapi", "http://localhost/").generate(), indent=4, sort_keys=True)
-    doc = '''"""Generated API Documentation for Drone API using drone_doc_gen.py."""\n\ndoc = %s''' % dump
+    dump = json.dumps(doc_gen("serverapi", "http://localhost/").generate(), indent=4, sort_keys=True)
+    doc = '''"""\nGenerated API Documentation for Server API using server_doc_gen.py.\n\ndoc = %s''' % dump
+    doc = doc + '\n"""'
     doc = doc.replace('true', '"true"')
     doc = doc.replace('false', '"false"')
     doc = doc.replace('null', '"null"')
-    f = open("drone_doc.py", "w")
+    f = open("doc.py", "w")
     f.write(doc)
     f.close()
diff --git a/hydrus/vocab.py b/hydrus/vocab.py
deleted file mode 100644
index 1ad09eb..0000000
--- a/hydrus/vocab.py
+++ /dev/null
@@ -1,112 +0,0 @@
-"""Vocab and object preprocessors for Hydrus."""
-
-
-def validObject(object_):
-    """Check if the data passed in POST is of valid format or not."""
-    if "name" in object_:
-        if "@type" in object_:
-            # if "object" in object_:
-            return True
-    return False
-
-
-def struct_object(object_, type_):
-    """Restructure objects submitted by Hydra Console."""
-    if validObject(object_):
-        return object_
-    else:
-        obj_temp = {
-            "name": None,
-            "@type": "",
-            "object": {
-            }}
-
-        obj_temp["@type"] = object_.pop("@type")
-
-        try:
-            obj_temp["name"] = object_.pop("name")
-        except:
-            pass
-
-        try:
-            obj_temp["@context"] = object_.pop("@context")
-        except:
-            pass
-        for prop in object_.keys():
-            obj_temp["object"][prop] = object_[prop]
-        return obj_temp
-
-
-def get_supported_properties(parsed_classes, category, vocab):
-    """Filter supported properties with their title (title, property) for a specific class from the parsed classes."""
-    obj = None
-    for object_ in parsed_classes:
-        if object_["title"] == category:
-            obj = object_
-    # print(obj, category)
-
-    supported_props = []
-    if obj is not None:
-        # Get object class and title
-        supported_props.append((obj["title"], obj["@id"]))
-        # Get supported properties
-        for obj_ in obj["supportedProperty"]:
-            try:
-                prop = (obj_["title"], obj_["property"])
-
-            except KeyError:
-                prop = (obj_["property"].split(
-                    "subsystems:")[-1], obj_["property"])
-
-            if prop not in supported_props:
-                supported_props.append(prop)
-    return supported_props
-
-
-def gen_context(parsed_classes, server_url, category, vocab):
-    """Generate dynamic contexts for every item."""
-    SERVER_URL = server_url
-    PARSED_CLASSES = parsed_classes
-    VOCAB = vocab
-    context_template = {
-        "@context": {
-            "name": "http://schema.org/name",
-            "object": "http://schema.org/object",
-            "hydra": "http://www.w3.org/ns/hydra/core#",
-            "vocab": SERVER_URL + "api/vocab#",
-        }
-    }
-
-    # Get supported properties
-    supported_props = get_supported_properties(PARSED_CLASSES, category, VOCAB)
-    for title, value in supported_props:
-        context_template["@context"][title] = value
-
-    return context_template
-
-
-def gen_collection_context(server_url, type_):
-    """Generate context for Collection objects."""
-    SERVER_URL = server_url
-    COLLECTION_TYPE = type_.split("Collection")[0]
-
-    template = {
-        "@context": {
-            "hydra": "http://www.w3.org/ns/hydra/core#",
-            "vocab": SERVER_URL + "api/vocab#",
-            COLLECTION_TYPE + "Collection": "vocab:%sCollection" % (COLLECTION_TYPE,),
-            COLLECTION_TYPE: "vocab:%s" % (COLLECTION_TYPE,),
-            "members": "http://www.w3.org/ns/hydra/core#member"
-        }
-    }
-
-    return template
-
-
-def hydrafy(parsed_classes, object_, collection=False):
-    """Add hydra context to objects."""
-    if collection:
-        object_["@context"] = "/api/contexts/" + object_["@type"] + ".jsonld"
-    else:
-        object_["@context"] = "/api/contexts/" + object_["@type"] + ".jsonld"
-    return object_


Test patch:
diff --git a/hydrus/tests/dummy_data.py b/hydrus/tests/dummy_data.py
new file mode 100644
index 0000000..6639f57
--- /dev/null
+++ b/hydrus/tests/dummy_data.py
@@ -0,0 +1,20 @@
+"""Creates a dummy object for a given class based on the API Documentation."""
+
+import random
+import string
+import pdb
+
+
+def gen_dummy_object(class_, doc):
+    """Create a dummy object based on the definitions in the API Doc."""
+    object_ = {
+        "@type": class_
+    }
+    if class_ in doc.parsed_classes:
+        for prop in doc.parsed_classes[class_]["class"].supportedProperty:
+            if "vocab:" in prop.prop:
+                prop_class = doc.parsed_classes[prop.prop.replace("vocab:", "")]["class"]
+                object_[prop.title] = gen_dummy_object(prop_class, doc)
+            else:
+                object_[prop.title] = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
+        return object_
diff --git a/hydrus/tests/test_app.py b/hydrus/tests/test_app.py
index 16089c6..8da557e 100644
--- a/hydrus/tests/test_app.py
+++ b/hydrus/tests/test_app.py
@@ -1,110 +1,325 @@
+"""Test for checking if the response format is proper. Run test_crud before running this."""
 # -*- coding: utf-8 -*-
-"""Test for checking if the response format is proper. Run test_crud before running this"""
 
 import unittest
-import tempfile
+import random
+import string
 import os
-import hydrus.app as views
 import json
-from hydrus.app import API_NAME, SERVER_URL
+import pdb
+from hydrus.app import API_NAME, SERVER_URL, API_DOC, app, set_session
+from hydrus.data import doc_parse
+from hydrus.metadata.doc_gen import doc_gen
+from sqlalchemy import create_engine
+from sqlalchemy.orm import sessionmaker
+from hydrus.data.db_models import Base
 
 
+def gen_dummy_object(class_, doc):
+    """Create a dummy object based on the definitions in the API Doc."""
+    object_ = {
+        "@type": class_
+    }
+    if class_ in doc.parsed_classes:
+        for prop in doc.parsed_classes[class_]["class"].supportedProperty:
+            if "vocab:" in prop.prop:
+                prop_class = prop.prop.replace("vocab:", "")
+                object_[prop.title] = gen_dummy_object(prop_class, doc)
+            else:
+                object_[prop.title] = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
+        return object_
+
 
 class ViewsTestCase(unittest.TestCase):
     """Test Class for the app."""
 
-    def setUp(self):
-        """Temporary database setup to store responses."""
-        self.db_fd, views.app.config['DATABASE'] = tempfile.mkstemp()
-        views.app.config['TESTING'] = True
-        self.app = views.app.test_client()
+    @classmethod
+    def setUpClass(self):
+        """Database setup before the tests."""
+        print("Creating a temporary datatbsse...")
+        engine = create_engine('sqlite:///:memory:')
+        Base.metadata.create_all(engine)
+        Session = sessionmaker(bind=engine)
+        session = Session()
+        self.session = session
+        doc = doc_gen("test", "test")
+        test_classes = doc_parse.get_classes(doc.generate())
+        test_properties = doc_parse.get_all_properties(test_classes)
+        doc_parse.insert_classes(test_classes, self.session)
+        doc_parse.insert_properties(test_properties, self.session)
+        print("Classes and properties added successfully.")
+        print("Setup done, running tests...")
 
-    def tearDown(self):
+    @classmethod
+    def tearDownClass(self):
         """Tear down temporary database."""
-        os.close(self.db_fd)
-        os.unlink(views.app.config['DATABASE'])
+        self.session.close()
 
     def test_Index(self):
         """Test for the index."""
-        response_get = self.app.get("/"+API_NAME)
-        self.endpoints = json.loads(response_get.data.decode('utf-8'))
-        response_post = self.app.post("/"+API_NAME, data={})
-        response_delete = self.app.delete("/"+API_NAME)
-        assert "@context" in self.endpoints
-        assert self.endpoints["@id"] == "/"+API_NAME
-        assert self.endpoints["@type"] == "EntryPoint"
-        assert response_get.status_code == 200
-        assert response_post.status_code == 405
-        assert response_delete.status_code == 405
+        with set_session(app, self.session):
+            with app.test_client() as client:
+                response_get = client.get("/"+API_NAME)
+                endpoints = json.loads(response_get.data.decode('utf-8'))
+                response_post = client.post("/"+API_NAME, data=dict(foo="bar"))
+                response_put = client.put("/"+API_NAME, data=dict(foo="bar"))
+                response_delete = client.delete("/"+API_NAME)
+                assert "@context" in endpoints
+                assert endpoints["@id"] == "/"+API_NAME
+                assert endpoints["@type"] == "EntryPoint"
+                assert response_get.status_code == 200
+                assert response_post.status_code == 405
+                assert response_put.status_code == 405
+                assert response_delete.status_code == 405
 
     def test_EntryPoint_context(self):
         """Test for the EntryPoint context."""
-        response_get = self.app.get("/"+API_NAME +"/contexts/EntryPoint.jsonld")
-        response_get_data = json.loads(response_get.data.decode('utf-8'))
-        response_post = self.app.post("/"+API_NAME +"/contexts/EntryPoint.jsonld", data={})
-        response_delete = self.app.delete("/"+API_NAME +"/contexts/EntryPoint.jsonld")
-        assert response_get.status_code == 200
-        assert "@context" in response_get_data
-        assert response_post.status_code == 405
-        assert response_delete.status_code == 405
+        with set_session(app, self.session):
+            with app.test_client() as client:
+                response_get = client.get("/"+API_NAME + "/contexts/EntryPoint.jsonld")
+                response_get_data = json.loads(response_get.data.decode('utf-8'))
+                response_post = client.post("/"+API_NAME + "/contexts/EntryPoint.jsonld", data={})
+                response_delete = client.delete("/"+API_NAME + "/contexts/EntryPoint.jsonld")
+                assert response_get.status_code == 200
+                assert "@context" in response_get_data
+                assert response_post.status_code == 405
+                assert response_delete.status_code == 405
 
     def test_Vocab(self):
         """Test the vocab."""
-        response_get = self.app.get("/"+API_NAME +"/vocab#")
-        response_get_data = json.loads(response_get.data.decode('utf-8'))
-        assert "@context" in response_get_data
-        # print(response_get_data["@id"], SERVER_URL+API_NAME +"/vocab#")
-        assert response_get_data["@type"] == "ApiDocumentation"
-        assert response_get_data["@id"] == SERVER_URL+API_NAME +"/vocab"
-        assert response_get.status_code == 200
-
-        response_delete = self.app.delete("/"+API_NAME +"/vocab#")
-        assert response_delete.status_code == 405
-
-        response_put = self.app.put("/"+API_NAME +"/vocab#", data=json.dumps(dict(foo = 'bar')))
-        assert response_put.status_code == 405
-
-    def test_Endpoints_Collections(self):
-        """Test all endpoints to get the collection."""
-        index = self.app.get("/"+API_NAME)
-        assert index.status_code == 200
-        endpoints = json.loads(index.data.decode('utf-8'))
-        for endpoint in endpoints:
-            if endpoint not in ["@id", "@context", "@type"] and "Collection" in endpoints[endpoint]:
-                response_get = self.app.get(endpoints[endpoint])
-                response_post = self.app.post(endpoints[endpoint], data=json.dumps(dict(foo = 'bar')))
-                response_delete = self.app.delete(endpoints[endpoint])
-                assert response_get.status_code == 200
-                assert response_post.status_code == 201
-                assert response_delete.status_code == 405
+        with set_session(app, self.session):
+            with app.test_client() as client:
+                response_get = client.get("/"+API_NAME + "/vocab#")
                 response_get_data = json.loads(response_get.data.decode('utf-8'))
                 assert "@context" in response_get_data
-                assert "@id" in response_get_data
-                assert "@type" in response_get_data
-                assert "members" in response_get_data
+                # print(response_get_data["@id"], SERVER_URL+API_NAME +"/vocab#")
+                assert response_get_data["@type"] == "ApiDocumentation"
+                assert response_get_data["@id"] == SERVER_URL+API_NAME+"/vocab"
+                assert response_get.status_code == 200
+
+                response_delete = client.delete("/"+API_NAME+"/vocab#")
+                assert response_delete.status_code == 405
+
+                response_put = client.put("/"+API_NAME+"/vocab#", data=json.dumps(dict(foo='bar')))
+                assert response_put.status_code == 405
+
+                response_post = client.post("/"+API_NAME+"/vocab#", data=json.dumps(dict(foo='bar')))
+                assert response_post.status_code == 405
+
+    def test_Collections_GET(self):
+        """Test GET on collection endpoints."""
+        with set_session(app, self.session):
+            with app.test_client() as client:
+                index = client.get("/"+API_NAME)
+                assert index.status_code == 200
+                endpoints = json.loads(index.data.decode('utf-8'))
+                for endpoint in endpoints:
+                    if endpoint in API_DOC.collections:
+                        response_get = client.get(endpoints[endpoint])
+                        assert response_get.status_code == 200
+                        response_get_data = json.loads(response_get.data.decode('utf-8'))
+                        assert "@context" in response_get_data
+                        assert "@id" in response_get_data
+                        assert "@type" in response_get_data
+                        assert "members" in response_get_data
+
+    def test_Collections_PUT(self):
+        """Test insert data to the collection."""
+        with set_session(app, self.session):
+            with app.test_client() as client:
+                index = client.get("/"+API_NAME)
+                assert index.status_code == 200
+                endpoints = json.loads(index.data.decode('utf-8'))
+                for collection_name in endpoints:
+                    if collection_name in API_DOC.collections:
+                        collection = API_DOC.collections[collection_name]["collection"]
+                        dummy_object = gen_dummy_object(collection.class_.title, API_DOC)
+                        good_response_put = client.put(endpoints[collection_name], data=json.dumps(dummy_object))
+                        assert good_response_put.status_code == 201
+
+    def test_object_POST(self):
+        """Test replace of a given object using ID."""
+        with set_session(app, self.session):
+            with app.test_client() as client:
+                index = client.get("/"+API_NAME)
+                assert index.status_code == 200
+                endpoints = json.loads(index.data.decode('utf-8'))
+                for collection_name in endpoints:
+                    if collection_name in API_DOC.collections:
+                        collection = API_DOC.collections[collection_name]["collection"]
+                        class_ = API_DOC.parsed_classes[collection.class_.title]["class"]
+                        class_methods = [x.method for x in class_.supportedOperation]
+                        dummy_object = gen_dummy_object(collection.class_.title, API_DOC)
+                        initial_put_response = client.put(endpoints[collection_name], data=json.dumps(dummy_object))
+                        assert initial_put_response.status_code == 201
+                        response = json.loads(initial_put_response.data.decode('utf-8'))
+                        id_ = response["201"].split('=')[1]
+                        if "POST" in class_methods:
+                            dummy_object = gen_dummy_object(collection.class_.title, API_DOC)
+                            post_replace_response = client.post(endpoints[collection_name]+'/'+str(id_), data=json.dumps(dummy_object))
+                            assert post_replace_response.status_code == 200
+
+    def test_object_DELETE(self):
+        """Test DELETE of a given object using ID."""
+        with set_session(app, self.session):
+            with app.test_client() as client:
+                index = client.get("/"+API_NAME)
+                assert index.status_code == 200
+                endpoints = json.loads(index.data.decode('utf-8'))
+                for collection_name in endpoints:
+                    if collection_name in API_DOC.collections:
+                        collection = API_DOC.collections[collection_name]["collection"]
+                        class_ = API_DOC.parsed_classes[collection.class_.title]["class"]
+                        class_methods = [x.method for x in class_.supportedOperation]
+                        dummy_object = gen_dummy_object(collection.class_.title, API_DOC)
+                        initial_put_response = client.put(endpoints[collection_name], data=json.dumps(dummy_object))
+                        assert initial_put_response.status_code == 201
+                        response = json.loads(initial_put_response.data.decode('utf-8'))
+                        id_ = response["201"].split('=')[1]
+                        if "DELETE" in class_methods:
+                            delete_response = client.delete(endpoints[collection_name]+'/'+str(id_))
+                            assert delete_response.status_code == 200
 
     def test_Endpoints_Contexts(self):
         """Test all endpoints contexts are generated properly."""
-        index = self.app.get("/"+API_NAME)
-        assert index.status_code == 200
-        endpoints = json.loads(index.data.decode('utf-8'))
-        for endpoint in endpoints:
-            if endpoint not in ["@id", "@context", "@type"] and "Collection" in endpoints[endpoint]:
-                response_get = self.app.get(endpoints[endpoint])
-                # print(response_get.data.decode('utf-8'))
-                context = json.loads(response_get.data.decode('utf-8'))["@context"]
-                response_context = self.app.get(context)
-                response_context_data = json.loads(response_context.data.decode('utf-8'))
-                assert response_context.status_code == 200
-                assert "@context" in response_context_data
+        with set_session(app, self.session):
+            with app.test_client() as client:
+                index = client.get("/"+API_NAME)
+                assert index.status_code == 200
+                endpoints = json.loads(index.data.decode('utf-8'))
+                for collection_name in endpoints:
+                    if collection_name in API_DOC.collections:
+                        response_get = client.get(endpoints[collection_name])
+                        assert response_get.status_code == 200
+                        context = json.loads(response_get.data.decode('utf-8'))["@context"]
+                        response_context = client.get(context)
+                        response_context_data = json.loads(response_context.data.decode('utf-8'))
+                        assert response_context.status_code == 200
+                        assert "@context" in response_context_data
+
+    def test_object_PUT(self):
+        """Create object at a specific ID where allowed."""
+        with set_session(app, self.session):
+            with app.test_client() as client:
+                index = client.get("/"+API_NAME)
+                assert index.status_code == 200
+                endpoints = json.loads(index.data.decode('utf-8'))
+                for collection_name in endpoints:
+                    if collection_name in API_DOC.collections:
+                        collection = API_DOC.collections[collection_name]["collection"]
+                        class_ = API_DOC.parsed_classes[collection.class_.title]["class"]
+                        class_methods = [x.method for x in class_.supportedOperation]
+                        dummy_object = gen_dummy_object(collection.class_.title, API_DOC)
+                        if "PUT" in class_methods:
+                            dummy_object = gen_dummy_object(collection.class_.title, API_DOC)
+                            put_response = client.put(endpoints[collection_name], data=json.dumps(dummy_object))
+                            assert put_response.status_code == 201
+
+    def test_endpointClass_PUT(self):
+        """Create non collection Class using PUT."""
+        with set_session(app, self.session):
+            with app.test_client() as client:
+                index = client.get("/"+API_NAME)
+                assert index.status_code == 200
+                endpoints = json.loads(index.data.decode('utf-8'))
+                for class_name in endpoints:
+                    if class_name not in API_DOC.collections and class_name not in ["@context", "@id", "@type"]:
+                        class_ = API_DOC.parsed_classes[class_name]["class"]
+                        class_methods = [x.method for x in class_.supportedOperation]
+                        if "PUT" in class_methods:
+                            dummy_object = gen_dummy_object(class_.title, API_DOC)
+                            put_response = client.put(endpoints[class_name], data=json.dumps(dummy_object))
+                            assert put_response.status_code == 201
+
+    def test_endpointClass_POST(self):
+        """Update non collection Class using PUT."""
+        with set_session(app, self.session):
+            with app.test_client() as client:
+                index = client.get("/"+API_NAME)
+                assert index.status_code == 200
+                endpoints = json.loads(index.data.decode('utf-8'))
+                for class_name in endpoints:
+                    if class_name not in API_DOC.collections and class_name not in ["@context", "@id", "@type"]:
+                        class_ = API_DOC.parsed_classes[class_name]["class"]
+                        class_methods = [x.method for x in class_.supportedOperation]
+                        if "POST" in class_methods:
+                            dummy_object = gen_dummy_object(class_.title, API_DOC)
+                            put_response = client.post(endpoints[class_name], data=json.dumps(dummy_object))
+                            assert put_response.status_code == 201
+
+    def test_endpointClass_DELETE(self):
+        """Update non collection Class using PUT."""
+        with set_session(app, self.session):
+            with app.test_client() as client:
+                index = client.get("/"+API_NAME)
+                assert index.status_code == 200
+                endpoints = json.loads(index.data.decode('utf-8'))
+                for class_name in endpoints:
+                    if class_name not in API_DOC.collections and class_name not in ["@context", "@id", "@type"]:
+                        class_ = API_DOC.parsed_classes[class_name]["class"]
+                        class_methods = [x.method for x in class_.supportedOperation]
+                        if "DELETE" in class_methods:
+                            put_response = client.delete(endpoints[class_name])
+                            assert put_response.status_code == 200
+
+    def test_endpointClass_DELETE(self):
+        """Update non collection Class using PUT."""
+        with set_session(app, self.session):
+            with app.test_client() as client:
+                index = client.get("/"+API_NAME)
+                assert index.status_code == 200
+                endpoints = json.loads(index.data.decode('utf-8'))
+                for class_name in endpoints:
+                    if class_name not in API_DOC.collections and class_name not in ["@context", "@id", "@type"]:
+                        class_ = API_DOC.parsed_classes[class_name]["class"]
+                        class_methods = [x.method for x in class_.supportedOperation]
+                        if "GET" in class_methods:
+                            response_get = client.get(endpoints[class_name])
+                            assert response_get.status_code in [200, 404]
+                            if response_get.status_code == 200:
+                                response_get_data = json.loads(response_get.data.decode('utf-8'))
+                                assert "@context" in response_get_data
+                                assert "@id" in response_get_data
+                                assert "@type" in response_get_data
+
+    def test_bad_objects(self):
+        """Checks if bad objects are added or not."""
+        with set_session(app, self.session):
+            with app.test_client() as client:
+                index = client.get("/"+API_NAME)
+                assert index.status_code == 200
+                endpoints = json.loads(index.data.decode('utf-8'))
+                for collection_name in endpoints:
+                    if collection_name in API_DOC.collections:
+                        bad_response_put = client.put(endpoints[collection_name], data=json.dumps(dict(foo='bar')))
+                        assert bad_response_put.status_code == 400
+
+    def test_bad_requests(self):
+        """Checks if bad requests are handled or not."""
+        with set_session(app, self.session):
+            with app.test_client() as client:
+                index = client.get("/"+API_NAME)
+                assert index.status_code == 200
+                endpoints = json.loads(index.data.decode('utf-8'))
+                for collection_name in endpoints:
+                    if collection_name in API_DOC.collections:
+                        collection = API_DOC.collections[collection_name]["collection"]
+                        class_ = API_DOC.parsed_classes[collection.class_.title]["class"]
+                        class_methods = [x.method for x in class_.supportedOperation]
+                        dummy_object = gen_dummy_object(collection.class_.title, API_DOC)
+                        initial_put_response = client.put(endpoints[collection_name], data=json.dumps(dummy_object))
+                        assert initial_put_response.status_code == 201
+                        response = json.loads(initial_put_response.data.decode('utf-8'))
+                        id_ = response["201"].split('=')[1]
+                        if "POST" not in class_methods:
+                            dummy_object = gen_dummy_object(collection.class_.title, API_DOC)
+                            post_replace_response = client.post(endpoints[collection_name]+'/'+str(id_), data=json.dumps(dummy_object))
+                            assert post_replace_response.status_code == 405
 
 
 if __name__ == '__main__':
     message = """
     Running tests for the app. Checking if all responses are in proper order.
-    NOTE: This doesn't ensure that data is entered or deleted in a proper manner.
-    It only checks the format of the reponses.
-    If you want to check data entry, please run test_crud.py
     """
     print(message)
     unittest.main()