1
0
mirror of https://github.com/daniviga/bite.git synced 2024-12-23 00:31:25 +01:00

API improvements (#22)

* Add swagger ui

* API improvements

* Fix nginx and pre-compile python to speedup start

* Add flake8 testing
This commit is contained in:
Daniele Viganò 2020-06-26 19:27:47 +02:00 committed by GitHub
parent b15b88aab4
commit 165ae3d3c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 93 additions and 22 deletions

View File

@ -42,6 +42,11 @@ jobs:
- docker-compose -f docker/docker-compose.yml up -d
script:
- docker-compose -f docker/docker-compose.yml exec bite python manage.py test
- stage: django
install:
- pip3 -q install flake8
script:
- flake8 bite --exclude migrations,settings.py
- <<: *iot-simulator
env: IOT_TL=http
- <<: *iot-simulator

View File

@ -26,16 +26,3 @@ from api.serializers import DeviceSerializer
class APISubscribe(ModelViewSet):
queryset = Device.objects.all()
serializer_class = DeviceSerializer
# def post(self, request):
# serializer = DeviceSerializer(data=request.data)
# if serializer.is_valid():
# serializer.save()
# return Response(serializer.data, status=status.HTTP_201_CREATED)
# return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# def get(self, request):
# devices = Device.objects.all()
# import pdb; pdb.set_trace()
# serializer = DeviceSerializer(devices)
# return Response(serializer.serial)

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<title>Swagger</title>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="//unpkg.com/swagger-ui-dist@3/swagger-ui.css" />
</head>
<body>
<div id="swagger-ui"></div>
<script src="//unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"></script>
<script>
const ui = SwaggerUIBundle({
url: "{% url schema_url %}",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
],
layout: "BaseLayout"
})
</script>
</body>
</html>

View File

@ -34,6 +34,7 @@ Including another URLconf
"""
from django.contrib import admin
from django.conf import settings
from django.urls import include, path
from api import urls as api_urls
@ -45,3 +46,19 @@ urlpatterns = [
path('api/', include(api_urls)),
path('telemetry/', include(telemetry_urls)),
]
if settings.DEBUG:
from django.views.generic import TemplateView
from rest_framework.schemas import get_schema_view
urlpatterns += [
path('swagger/', TemplateView.as_view(
template_name='swagger.html',
extra_context={'schema_url': 'openapi-schema'}
), name='swagger'),
path('openapi', get_schema_view(
title="BITE - A Basic/IoT/Example",
description="BITE API for IoT",
version="1.0.0"
), name='openapi-schema'),
]

View File

@ -22,6 +22,17 @@ from api.models import Device
from telemetry.models import Telemetry
class TelemetryStatsSerializer(serializers.Serializer):
count_samples = serializers.IntegerField()
first_sample = serializers.DateTimeField()
last_sample = serializers.DateTimeField()
class TelemetrySummarySerializer(serializers.Serializer):
device = serializers.CharField()
stats = TelemetryStatsSerializer()
class TelemetrySerializer(serializers.ModelSerializer):
device = serializers.SlugRelatedField(
slug_field='serial',

View File

@ -33,14 +33,15 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.urls import path
from telemetry.views import TelemetryView, TelemetryLatest, TelemetryRange
from telemetry.views import (TelemetryView, TelemetrySummaryView,
TelemetryLatest, TelemetryRange)
urlpatterns = [
path('',
TelemetryView.as_view({'post': 'create'}),
name='telemetry'),
path('<str:device>/',
TelemetryView.as_view({'get': 'list'}),
TelemetrySummaryView.as_view(),
name='device-telemetry'),
path('<str:device>/last/',
TelemetryLatest.as_view({'get': 'retrieve'}),

View File

@ -19,10 +19,12 @@
from datetime import datetime
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from telemetry.models import Telemetry
from telemetry.serializers import TelemetrySerializer
from telemetry.serializers import (TelemetrySerializer,
TelemetrySummarySerializer)
from rest_framework.response import Response
@ -39,15 +41,36 @@ class TelemetryView(ModelViewSet):
return Response(serializer.data)
class TelemetrySummaryView(APIView):
def get(self, request, device, format=None):
count = Telemetry.objects.filter(device__serial=device).count()
if count == 0:
raise Http404
first = Telemetry.objects.filter(
device__serial=device).order_by('-time')[:1][0]
last = Telemetry.objects.filter(
device__serial=device).order_by('time')[:1][0]
data = {
'device': device,
'stats': {
'count_samples': count,
'first_sample': first.time,
'last_sample': last.time}
}
serializer = TelemetrySummarySerializer(data)
return Response(serializer.data)
class TelemetryRange(ModelViewSet):
queryset = Telemetry.objects.all()
serializer_class = TelemetrySerializer
lookup_field = 'device'
def list(self, request, device, time_from, time_to=None):
time_to = datetime.now() if time_to is None else time_to
queryset = Telemetry.objects.filter(
device__serial=device,
time__range=[time_from, datetime.now()])
time__range=[time_from, time_to])
if not queryset:
raise Http404
serializer = TelemetrySerializer(queryset, many=True)
@ -61,7 +84,7 @@ class TelemetryLatest(ModelViewSet):
def retrieve(self, request, device=None):
queryset = Telemetry.objects.filter(
device__serial=device).order_by('-time')
device__serial=device).order_by('-time')[:1]
if not queryset:
raise Http404
serializer = TelemetrySerializer(queryset[0])

View File

@ -35,6 +35,7 @@ COPY --chown=1000:1000 bite /srv/app/bite
COPY --chown=1000:1000 requirements.txt /srv/app/bite/requirements.txt
RUN pip3 install -r /srv/app/bite/requirements.txt \
&& python3 -m compileall -q /srv/app/bite \
&& mkdir -p /srv/appdata/bite/static \
&& chown -R 1000:1000 /srv/appdata/bite

View File

@ -48,13 +48,13 @@ http {
'' close;
}
upstream bite {
upstream django {
# We point to the Docker 'service' instead of directly to the container
# Docker does then a DNS round-robin internally
server bite:8000;
}
upstream broker {
upstream mqtt {
# We point to the Docker 'service' instead of directly to the container
# Docker does then a DNS round-robin internally
server broker:9001;
@ -69,7 +69,7 @@ http {
keepalive_timeout 60 60;
location / {
proxy_pass http://bite;
proxy_pass http://django;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
@ -85,7 +85,7 @@ http {
}
location /mqtt {
proxy_pass http://broker;
proxy_pass http://mqtt;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

View File

@ -4,5 +4,7 @@ django-health-check
psycopg2-binary
paho-mqtt==1.5.0
asyncio-mqtt==0.5.0
PyYAML
uritemplate
pygments
gunicorn