Skip to content
This repository has been archived by the owner on Mar 24, 2022. It is now read-only.

Commit

Permalink
✨ using Flask-RESTPlus
Browse files Browse the repository at this point in the history
- added Swagger documentation
- changed base URL to /api/itineraries
- added documentation to / URL
- moved calculation to reiseplan.py
  • Loading branch information
nlohmann committed Apr 18, 2017
1 parent 51cd4e4 commit 77db106
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 57 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
venv

*.pyc
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ Dies startet einen lokalen Server auf <http://127.0.0.1:8000>.

## Nutzung

Für eine sechsstellige-Auftragsnummer `TYFMQE` sieht können mit `http://127.0.0.1:8000/TYFMQE` die Reisedaten abgerufen werden. Diese sehen in etwa so aus:
Unter <http://127.0.0.1:8000/> gibt es eine Dokumentation der API.

Für eine sechsstellige-Auftragsnummer `TYFMQE` können mit `http://127.0.0.1:8000/api/itineraries/TYFMQE` die Reisedaten abgerufen werden. Diese sehen in etwa so aus:

```js
{
Expand Down
7 changes: 7 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from flask import Flask
from flask_compress import Compress
from flask_cache import Cache
from flask_restplus import Api

# create Flask app
app = Flask(__name__)
Expand All @@ -17,5 +18,11 @@
# add caching
cache = Cache(app, config={'CACHE_TYPE': 'simple'})

# create a Flask-RESTPlus API
api = Api(app, version='0.0.2', catch_all_404s=True, prefix='/api',
title='Deutsche Bahn Reiseplan', description=u'API for the itineraries of the Deutsche Bahn',
terms_url='https://www.bahn.de/p/view/home/agb/nutzungsbedingungen.shtml',
contact='Niels Lohmann', contact_email='[email protected]', contact_url='http://nlohmann.me')

# load views
from app import views
40 changes: 40 additions & 0 deletions app/reiseplan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# coding=utf-8

import json
import requests


def reiseplan(auftragsnummer):
"""
Retrieve itinerary from a given reference number
:param auftragsnummer: Deutsche Bahn reference number (6 alphanumeric characters)
:return: itinerary as dictionary or None
"""
url = 'https://fahrkarten.bahn.de/privatkunde/start/start.post'
params = {
'lang': 'de',
'scope': 'reiseplan',
'atnr': auftragsnummer,
'country': 'DEU'
}

res = requests.get(url, params=params).text

date_str = None
for line in res.split('\n'):
# search for the date
if 'activeConnectionTriggerDate' in line:
# the date is not part of the JSON payload, so we need to get it individually
date_str = line[line.find('"') + 1:line.rfind('"')]

# search for the JSON payload
if line.startswith('jsonObjC0_0'):
# parse the JSON variable
result = json.loads(line[line.find('=') + 1:line.rfind(';')])

# add the date and the reference number
result['date'] = date_str
result['referenceNumber'] = auftragsnummer
return result

return None
74 changes: 18 additions & 56 deletions app/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,59 +5,21 @@
# Copyright (c) 2017 Niels Lohmann <http://nlohmann.me>. #
########################################################################

from app import app, cache
from flask import jsonify
import requests
import json


def reiseplan(auftragsnummer):
"""
Retrieve itinerary from a given reference number
:param auftragsnummer: Deutsche Bahn reference number (6 alphanumeric characters)
:return: itinerary as dictionary or None
"""
url = 'https://fahrkarten.bahn.de/privatkunde/start/start.post'
params = {
'lang': 'de',
'scope': 'reiseplan',
'atnr': auftragsnummer,
'country': 'DEU'
}

res = requests.get(url, params=params).text

date_str = None
for line in res.split('\n'):
# search for the date
if 'activeConnectionTriggerDate' in line:
# the date is not part of the JSON payload, so we need to get it individually
date_str = line[line.find('"') + 1:line.rfind('"')]

# search for the JSON payload
if line.startswith('jsonObjC0_0'):
# parse the JSON variable
result = json.loads(line[line.find('=') + 1:line.rfind(';')])

# add the date and the reference number
result['date'] = date_str
result['referenceNumber'] = auftragsnummer
return result

return None


@app.errorhandler(404)
def page_not_found(e):
return jsonify(error=404, text=str(e)), 404


@app.route('/<auftragsnummer>')
@cache.cached(timeout=3600)
def return_reiseplan(auftragsnummer):
res = reiseplan(auftragsnummer)

if res:
return jsonify(res)
else:
return page_not_found("no itinerary found for '%s'" % auftragsnummer)
from flask_restplus import Resource
from app import cache, api
from app.reiseplan import reiseplan

ns = api.namespace('itineraries', description='Operations related to itineraries')

@ns.route('/<auftragsnummer>')
@api.doc(params={'auftragsnummer': 'a 6-character reference number'})
class ReferenceNumber(Resource):
@api.doc(responses={200: 'success', 404: 'itinerary not found'})
@cache.cached(timeout=3600)
def get(self, auftragsnummer):
"""returns an itinerary"""
rp = reiseplan(auftragsnummer)
if rp:
return rp
else:
api.abort(404, error='itinerary not found', referenceNumber=auftragsnummer)
5 changes: 5 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
aniso8601==1.2.0
appdirs==1.4.3
click==6.7
Flask==0.12.1
Flask-Cache==0.13.1
Flask-Compress==1.4.0
flask-restplus==0.10.1
gunicorn==19.7.1
itsdangerous==0.24
Jinja2==2.9.6
jsonschema==2.6.0
MarkupSafe==1.0
packaging==16.8
pyparsing==2.2.0
python-dateutil==2.6.0
pytz==2017.2
requests==2.13.0
six==1.10.0
Werkzeug==0.12.1

0 comments on commit 77db106

Please sign in to comment.