Saturday, July 7, 2018

"Hello World !" with django rest framework

I will share with you the fundamental steps of creating RESTful API with django REST framework. I know there is already Quickstart tutorial on official web site. Nevertheless, when I started to utilize django rest framework, I just wanted more simple tutorial. I know the tutorial is quite simple and well-organized however it uses Serializers and MedelViewSet. Probably, there might be someone who has similar interest. Thus, In this article I won't use them, to make it simple I will use Function Based Views.

0. Environment


# OS
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.13.4
BuildVersion: 17E199

# Python
$ python --version
Python 3.6.1 :: Anaconda 4.4.0 (x86_64)
 
# Django
In [1]: import django

In [2]: django.get_version()
Out[2]: '2.0.6'

# rest_framework
In [1]: import rest_framework

In [2]: rest_framework.VERSION
Out[2]: '3.8.2'


1. Project set up

The following is the process of setting up project and application.
    
# Create project directory called 'projectdir'
$ mkdir projectdir
$ cd $_

# Set up a new project called 'testproject'
# Don't forget trailing '.' character otherwise, extra 'testproject' directory will be created
$ django-admin.py startproject testproject .
$ tree .
.
├── manage.py
└── testproject
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

1 directory, 5 files

# Set up application called 'helloworld'
$ cd testproject/
$ django-admin.py startapp helloworld
$ cd ..
$ tree .
.
├── manage.py
└── testproject
    ├── __init__.py
    ├── helloworld
    │   ├── __init__.py
    │   ├── admin.py
    │   ├── apps.py
    │   ├── migrations
    │   │   └── __init__.py
    │   ├── models.py
    │   ├── tests.py
    │   └── views.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

3 directories, 12 files
$ 
    

2. Migration

After setting up your own project according to above, you have to do migration. Migration is somehow reflecting remediation of your project to database. Before reflecting, we can confirm as is with showmigrations command.
     
$ python ./manage.py showmigrations
admin
 [ ] 0001_initial
 [ ] 0002_logentry_remove_auto_add
auth
 [ ] 0001_initial
 [ ] 0002_alter_permission_name_max_length
 [ ] 0003_alter_user_email_max_length
 [ ] 0004_alter_user_username_opts
 [ ] 0005_alter_user_last_login_null
 [ ] 0006_require_contenttypes_0002
 [ ] 0007_alter_validators_add_error_messages
 [ ] 0008_alter_user_username_max_length
 [ ] 0009_alter_user_last_name_max_length
contenttypes
 [ ] 0001_initial
 [ ] 0002_remove_content_type_name
sessions
 [ ] 0001_initial
$ 

Leading character [] means that these configuration has not been reflected to database. Let's reflect these information to database with migrate command.
    
$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying sessions.0001_initial... OK
$ 
    
Then, you can check whether they were reflected or not :)
    
$ python ./manage.py showmigrations
admin
 [X] 0001_initial
 [X] 0002_logentry_remove_auto_add
auth
 [X] 0001_initial
 [X] 0002_alter_permission_name_max_length
 [X] 0003_alter_user_email_max_length
 [X] 0004_alter_user_username_opts
 [X] 0005_alter_user_last_login_null
 [X] 0006_require_contenttypes_0002
 [X] 0007_alter_validators_add_error_messages
 [X] 0008_alter_user_username_max_length
 [X] 0009_alter_user_last_name_max_length
contenttypes
 [X] 0001_initial
 [X] 0002_remove_content_type_name
sessions
 [X] 0001_initial
$ 
    
We can see leading character has been changed to '[X]'. It means the information has been already reflected to the database .

3. Writing minimum logic

What I have to do is writing logic to respond "Hello World". As I have said, I will use Function Based Views.

Note :
In this example, for simplicity, I will write logic on urls.py. Nevertheless, you won't write there in real project.
    
from rest_framework.response import Response
from rest_framework.decorators import api_view
from django.conf.urls import url, include

@api_view(['GET','POST'])
def hello_world(request):
        if request.method == 'POST':
                return Response({"message": "Got some data!", "data": request.data})
        return Response({"message": "Hello, world!"})

urlpatterns = [
  url(r'^hello/$', hello_world),
]
    

4. Check Functionality

Now we are ready to boot server.
    
$ python ./manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
July 02, 2018 - 13:09:25
Django version 2.0.6, using settings 'testproject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
    
You can check the functionality with 'curl' command.
    
$ curl -X GET http://127.0.0.1:8000/hello/
{"message":"Hello, world!"}
$ 
    
Needless to say, we can respond to 'POST' data.

$ curl -X POST -F "hello=world" http://127.0.0.1:8000/hello/
{"message":"Got some data!","data":{"hello":"world"}}
$ 

5 comments:

  1. Nice. I've also found Flask to be very small and nice to work with.

    ReplyDelete
  2. Awesome example. I found that for my basic rest api the "Set up application called 'helloworld'". step was not nessecary.

    ReplyDelete
  3. Thanks for your example, It was very usefull

    ReplyDelete