API Browsing and Docs

To view live data for the Radiam API, point your web browser to your locally installed instance and append /api to the end of the URL.

For example: https://localhost:8100/api/

You can then log in using your admin credentials.

To view the API docs, append /docs to the above URL.

For example: https://localhost:8100/api/docs/

API Throttling

Based upon:

There are two main configurations for throttling at the moment which are both located in configuration file under the “REST_FRAMEWORK” object. DEFAULT_THROTTLE_CLASSES which specifies the classes that are involved in the throttling and the defaults can be overridden to get different results. Currently we are just using two different rates, for authenticated and anonymous users.


The other is DEFAULT_THROTTLE_RATES which controls when users get throttled. Can be in second, minute, hour, and day.

        'anon': '10/hour',
        'user': '1000/hour'

The Django REST Framework throttling supports using scopes to define unique throttling rates for different parts of the REST API in case we need them. Just requires a particular object to be specified in each view and then have that scope defined.

Throttling depends on both Permissions and on Caching.

Example normal response from users endpoint:


Example throttled header response:

HTTP/1.1 429 Too Many Requests
Date: Tue, 20 Nov 2018 21:56:00 GMT
Server: WSGIServer/0.2 CPython/3.7.1
Content-Type: application/json
Retry-After: 3501
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN
Content-Length: 71

Example throttled response:

{"detail":"Request was throttled. Expected available in 3600 seconds."}

API Caching

Based upon:

Default caching not recommended for production. Memcaching is used by very large orgs for performance improvements. We could move to database caching if we want to use our database for that purpose.

There are two suggested implementations for memory caching, memcached and pylibmc. Although pylibmc looks more active it appears to have a race condition problem: and is used as a secondary example after memcached.

Configuration for caching is in a CACHES object in settings.yml.

    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': 'api_memcached_1:11211',

There is a memcached service running in its own docker container. This is currently only setup to use a single container but we could setup a cluster of them going forward. A cluster is specified by a comma separated list. We might load balance them using docker swarm / kubernetes if necessary.

Flushing The Cache

echo "from django.core.cache import cache; cache._cache.flush_all()" | ./ shell [--settings=myapp.settings_live]

API Permissions

Based upon:


        # Uncomment to only allow authenticated access
        # 'rest_framework.permissions.IsAuthenticated'

Can set permissions based upon view or view set:

from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
    permission_classes = (IsAuthenticated&IsAdminUser,)
    def get(self, request, format=None):
        content = {
            'status': 'request was permitted'
        return Response(content)

The full list of options for permissions can be seen in the above Django page.



  • Located in the /tests module of a Django app
  • Tests are currently organized according to Model
  • Tests should adhere to the ‘Arrange, Act, Assert’ pattern
  • Feel free to modify or add tests/assertions that they deem valuable
  • Test running examples:
docker exec -it api_web_1 /bin/bash
# Run all test suites
python test -v3 radiamsec.radiamusers
# Run individual test suites
python test -v3 radiamsec.radiamusers.tests.TestResearchGroupAPI
# run individual test method in a particular suite
python test -v3 radiamsec.radiamusers.tests.TestResearchGroupAPI.test_create_researchgroup_blank_description


  • Django creates a test database for each test run and destroys it upon the test run’s completion
  • Data is loaded into this test database via test fixtures, specified in your test files. These are JSON representations of the initial models that a test database should contain as a precondition for a test suite.
  • Fixtures are located in the /fixtures module of an individual Django app (ie: /radiamsec/radiamusers/fixtures)
  • Example generation of fixtures:
docker exec -it api_radiamapi_1 bash
python dumpdata radiamusers.user --indent=4 > ./radiamsec/radiamusers/fixtures/users.json

Loading data into the main Database via data fixture:

  • Used as an alternative for the ‘oneshot.yml’ script for loading initial data into the database for development.
docker exec -it api_radiamapi_1 bash
python loaddata radiamsec/radiamusers/fixtures/<yourfixtures>.json


Email can be sent from Radiam by either configuring an SMTP backend in

# SMTP settings
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'smtppassword'

OR by configuring the SendGrid backend with an API Key:

# SendGrid Mail Service
EMAIL_BACKEND = 'sgbackend.SendGridBackend'

Developers may want to use the console email backend, which simply prints out the Email content to the console/application logs.

# Send emails to the console/application logs for dev purposes
# EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'  # During development only

Developers can also specify DEV_EMAIL_ADDRESSES = [ ] if they want to send to emails other than the one specified in the attribute for dev/testing/debugging purposes:

# Dev email addresses
DEV_EMAIL_ADDRESSES = ['[email protected]','[email protected]']

Token Authentication

JWT Tokens


In see the above link for what settings are possible.

Currently using public key encyrption by loading the private and public keys from files. Can change once we have secrets in place.

Request token:

curl \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{"username": "admin", "password": "password"}' \



Use Token:

curl \
  -H "Authorization: Bearer LONG_ACCESS_TOKEN_STRING" \

Which is: curl -H "Authorization: Bearer TOKEN" http://localhost:8000/users/

Verify Token:

curl \
  -v \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"token":"LONG_ACCESS_TOKEN_STRING"}' \

Refresh Token:

curl \
  -v \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"refresh":"LONG_REFRESH_TOKEN_STRING"}' \


Register App: http://localhost:8000/api/oauth/applications

Get Token: curl -X POST -d "grant_type=password&username=<user_name>&password=<password>" -u"<client_id>:<client_secret>" http://localhost:8000/api/oauth/token/

Use Token:

# Retrieve users
curl -H "Authorization: Bearer <your_access_token>" http://localhost:8000/users/
curl -H "Authorization: Bearer <your_access_token>" http://localhost:8000/users/1/
# Retrieve groups
curl -H "Authorization: Bearer <your_access_token>" http://localhost:8000/groups/
# Insert a new user
curl -H "Authorization: Bearer <your_access_token>" -X POST -d"username=foo&password=bar" http://localhost:8000/users/