Prerequisites

1. REST API vs SOAP API

So you are here to know what are the difference between API webservices?

Let's go with simple what are cons/pros of each solution!

1.A REST API Pros and Cons

PROS:
  • Lower amount of data needed to deliver actual content
  • Available two types of data formats (at least that's what I know of : JSON and XML)
  • Thanks to usage of JSON data format - simplified access to data within i.e. javascript/Android Applications etc.
  • Supports CRUD operations (Create, Read, Update, Delete) - that are correlated with HTTP convension (Create -> PUT/POST, Read -> Get, Update -> PUT/POST/PATCH, Delete-> DELETE)
CONS:
  • REST API formally does not have any type of WSDL and therefore you don't have any formal endpoints definition (only as description i.e. using other services)

1.B SOAP API Pros and Cons

PROS:
  • Contains formal scheme defining endpoints within WSDL
  • Output of endpoints data is formalized in WSDL and therefore you can check for expected output from that endpoints.
CONS:
  • Only XML with WSDL scheme
  • Lack or small amount of support for SOAP-XML at Android Community
  • Large amount of data to deliver actual content

2. Why do you want to use REST API ?

REST API is used from Client's perspective rather for faster data access with low amount of data delivered.

In my humble opinion that's why Android Community does not give such great support for SOAP.

Also that's your answer: If you are planning to use this webservice as an Endpoint for other Clients (Mobile Device, other web-applications i.e. based on javascript engine), than REST API is webservice for you!

But If you don't mind more amount of data and a little bit more complex data binding (parsing/sending/reading) but better formalization of data, than you obviously choose SOAP API.

One of the most important elements that makes SOAP API great is it's WSDL which helps to correlate how endpoints looks like, what data ought to be inside of them - which in later phase - helps you to more properly bind data and be sure that only this type of data should come out them.

Initial Database for REST API in Biking Endorphines project.

1. Test Database assumptions.

What I love about django is it's ORM(Object-Relational-Mapping). It offers you usage of old-school traditional database-in-file SQLite, but also other Database engines like i.e. Postgres.

You can easily switch between them, only thing that needs to be moved is data itself. But since it's a ORM you can manipulate database and create Test-data.

For our Biking Endorphines project, expected is to create tables with data like below:

  • User - just usual stuff like:

    (some already exists as part of bmi-checker functionality.)

    • id,
    • name,
    • surname,
    • weight,
    • height
  • Biking Route with Points :

    Route:

    • id,
    • route_name,(for easier search)
    • avg_route (predefined avg for this route, not related to user

    User-Route:

    • id_user,
    • id_route

    Point:

    • id,
    • id_route,
    • point, (lat, long)
    • elevation,

2. Type of database.

For now I'll use SQLite - a default database delivered with django instance.

I will probably move to my favourite database - PostgreSQL in future.

There is also a plan to create article about PostgreSQL in docker - So keep in touch :)

3. Database scheme.

So I've created a class-based ORM scheme within django. Here is how it looks like after python manage.py dbshell >.schema :

CREATE TABLE "django_migrations" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "app" varchar(255) NOT NULL, "name" varchar(255) NOT NULL, "applied" datetime NOT NULL);
CREATE TABLE "auth_group" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(80) NOT NULL UNIQUE);
CREATE TABLE "auth_group_permissions" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "group_id" integer NOT NULL REFERENCES "auth_group" ("id"), "permission_id" integer NOT NULL REFERENCES "auth_permission" ("id"));
CREATE TABLE "auth_user_groups" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "user_id" integer NOT NULL REFERENCES "auth_user" ("id"), "group_id" integer NOT NULL REFERENCES "auth_group" ("id"));
CREATE TABLE "auth_user_user_permissions" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "user_id" integer NOT NULL REFERENCES "auth_user" ("id"), "permission_id" integer NOT NULL REFERENCES "auth_permission" ("id"));
CREATE UNIQUE INDEX "auth_group_permissions_group_id_0cd325b0_uniq" ON "auth_group_permissions" ("group_id", "permission_id");
CREATE INDEX "auth_group_permissions_0e939a4f" ON "auth_group_permissions" ("group_id");
CREATE INDEX "auth_group_permissions_8373b171" ON "auth_group_permissions" ("permission_id");
CREATE UNIQUE INDEX "auth_user_groups_user_id_94350c0c_uniq" ON "auth_user_groups" ("user_id", "group_id");
CREATE INDEX "auth_user_groups_e8701ad4" ON "auth_user_groups" ("user_id");
CREATE INDEX "auth_user_groups_0e939a4f" ON "auth_user_groups" ("group_id");
CREATE UNIQUE INDEX "auth_user_user_permissions_user_id_14a6b632_uniq" ON "auth_user_user_permissions" ("user_id", "permission_id");
CREATE INDEX "auth_user_user_permissions_e8701ad4" ON "auth_user_user_permissions" ("user_id");
CREATE INDEX "auth_user_user_permissions_8373b171" ON "auth_user_user_permissions" ("permission_id");
CREATE TABLE "django_admin_log" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "object_id" text NULL, "object_repr" varchar(200) NOT NULL, "action_flag" smallint unsigned NOT NULL, "change_message" text NOT NULL, "content_type_id" integer NULL REFERENCES "django_content_type" ("id"), "user_id" integer NOT NULL REFERENCES "auth_user" ("id"), "action_time" datetime NOT NULL);
CREATE INDEX "django_admin_log_417f1b1c" ON "django_admin_log" ("content_type_id");
CREATE INDEX "django_admin_log_e8701ad4" ON "django_admin_log" ("user_id");
CREATE TABLE "django_content_type" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "app_label" varchar(100) NOT NULL, "model" varchar(100) NOT NULL);
CREATE UNIQUE INDEX "django_content_type_app_label_76bd3d3b_uniq" ON "django_content_type" ("app_label", "model");
CREATE TABLE "auth_permission" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "content_type_id" integer NOT NULL REFERENCES "django_content_type" ("id"), "codename" varchar(100) NOT NULL, "name" varchar(255) NOT NULL);
CREATE UNIQUE INDEX "auth_permission_content_type_id_01ab375a_uniq" ON "auth_permission" ("content_type_id", "codename");
CREATE INDEX "auth_permission_417f1b1c" ON "auth_permission" ("content_type_id");
CREATE TABLE "auth_user" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "password" varchar(128) NOT NULL, "last_login" datetime NULL, "is_superuser" bool NOT NULL, "first_name" varchar(30) NOT NULL, "last_name" varchar(30) NOT NULL, "email" varchar(254) NOT NULL, "is_staff" bool NOT NULL, "is_active" bool NOT NULL, "date_joined" datetime NOT NULL, "username" varchar(150) NOT NULL UNIQUE);
CREATE TABLE "django_session" ("session_key" varchar(40) NOT NULL PRIMARY KEY, "session_data" text NOT NULL, "expire_date" datetime NOT NULL);
CREATE INDEX "django_session_de54fa62" ON "django_session" ("expire_date");
CREATE TABLE "web_point" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "lat" real NOT NULL, "lon" real NOT NULL, "elevation" real NOT NULL);
CREATE TABLE "web_route" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "route_name" varchar(100) NOT NULL, "avg_route" real NOT NULL);
CREATE TABLE "web_routepoint" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "id_point_id" integer NOT NULL REFERENCES "web_point" ("id"), "id_route_id" integer NOT NULL REFERENCES "web_route" ("id"));
CREATE TABLE "web_user" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(50) NOT NULL, "height" integer NOT NULL, "weight" integer NOT NULL, "surname" varchar(100) NOT NULL);
CREATE INDEX "web_routepoint_aa34cbab" ON "web_routepoint" ("id_point_id");
CREATE INDEX "web_routepoint_c5012f0d" ON "web_routepoint" ("id_route_id");
CREATE TABLE "web_userroute" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "id_route_id" integer NOT NULL REFERENCES "web_route" ("id"), "id_user_id" integer NOT NULL REFERENCES "web_user" ("id"));
CREATE INDEX "web_userroute_c5012f0d" ON "web_userroute" ("id_route_id");
CREATE INDEX "web_userroute_3002e0f2" ON "web_userroute" ("id_user_id");

Initial plans for REST API for Biking Endorphines.

I'm planning to create REST-API. Below you can see what 2 endpoints will be created:

1. Gather user data with /user/get

2. Gather Biking routes and points with /route/{id} and /point/{id}

Final result

class User(models.Model):
    """
    User model for obtaining personal information about biking riders
    """
    name = models.CharField(max_length=50)
    surname = models.CharField(max_length=100, default="")
    weight = models.IntegerField(default=0)
    height = models.IntegerField(default=0)

    def __unicode__(self):
        """
        Returns User information when using str/printing
        """
        return self.name

    def bmi(self):
        """
        Body Mass Index calculator simplified to number
        """
        return (self.weight / (self.height * self.height)) * 10000


class Route(models.Model):
    """
    Route model. Defines Route by name, avg_route.
    """
    route_name = models.CharField(max_length=100)
    avg_route = models.FloatField(default=0.0)

    def __unicode__(self):
        "Returns Route name "
        return self.route_name


class UserRoute(models.Model):
    """
    User's routes
    """
    id_user = models.ForeignKey(User, on_delete=models.CASCADE)
    id_route = models.ForeignKey(Route, on_delete=models.CASCADE)

    def __unicode__(self):
        "Returns User id"
        return self.id_user


class Point(models.Model):
    """
    Points similar to gpx-data
    """
    lat = models.FloatField(default=0.0)
    lon = models.FloatField(default=0.0)
    elevation = models.FloatField(default=0.0)

    def __unicode__(self):
        "Returns Point unicode"
        return str(self.lat) + "" + str(self.lon)


class RoutePoint(models.Model):
    """
    Route Points relations
    """
    id_route = models.ForeignKey(Route, on_delete=models.CASCADE)
    id_point = models.ForeignKey(Point, on_delete=models.CASCADE)

    def __unicode__(self):
        "Returns Route-Point relationship unicode"
        return self.id_route

Code commits done for this post:

Tools and applications used:

Acknowledgements

Accomplished:

1. Python backend - initial REST-API.

What's next

1. REST-API for Test-Database.

2. Making API documentation - research for best API documentation!

3. How to secure biking-endorphines REST-API.

4. Badge Gathering source-code and tests.



Comments

comments powered by Disqus