From 2d0265d6137fb5c0276ebe179bb17bb96097322f Mon Sep 17 00:00:00 2001 From: TimMcCauley Date: Tue, 3 Apr 2018 09:28:12 +0200 Subject: [PATCH 1/2] adds query info to response, closes #22 --- manage.py | 3 - openpoiservice/server/__init__.py | 4 +- openpoiservice/server/api/pois_post.yml | 150 +++++++++++++-------- openpoiservice/server/api/query_builder.py | 19 +-- openpoiservice/server/api/query_info.py | 27 ++++ openpoiservice/server/api/views.py | 19 ++- requirements.txt | 1 + 7 files changed, 147 insertions(+), 76 deletions(-) create mode 100644 openpoiservice/server/api/query_info.py diff --git a/manage.py b/manage.py index de6cc7b..a8c4619 100755 --- a/manage.py +++ b/manage.py @@ -4,11 +4,8 @@ from flask.cli import FlaskGroup from openpoiservice.server import create_app, db from openpoiservice.server.db_import import parser -from openpoiservice.server import ops_settings import os -from timeit import Timer import logging -import glob logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) diff --git a/openpoiservice/server/__init__.py b/openpoiservice/server/__init__.py index c23b6df..ea4607b 100755 --- a/openpoiservice/server/__init__.py +++ b/openpoiservice/server/__init__.py @@ -3,6 +3,7 @@ from flask import Flask, jsonify, g from flask_sqlalchemy import SQLAlchemy from flasgger import Swagger +from flask_cors import CORS from openpoiservice.server.categories.categories import CategoryTools from openpoiservice.server.api import api_exceptions import yaml @@ -33,6 +34,7 @@ def create_app(script_info=None): app = Flask( __name__ ) + cors = CORS(app, resources={r"/pois/*": {"origins": "*"}}) app.config['SWAGGER'] = { 'title': 'Openpoiservice', @@ -53,7 +55,7 @@ def create_app(script_info=None): from openpoiservice.server.api.views import main_blueprint app.register_blueprint(main_blueprint) - Swagger(app) + Swagger(app, template_file='api/pois_post.yml') if "DEVELOPMENT" in os.environ: @app.before_request diff --git a/openpoiservice/server/api/pois_post.yml b/openpoiservice/server/api/pois_post.yml index 904964b..6405dd2 100644 --- a/openpoiservice/server/api/pois_post.yml +++ b/openpoiservice/server/api/pois_post.yml @@ -1,50 +1,80 @@ +swagger: "2.0" tags: - - Places -summary: openpoiservice (POST) -description: | +- name: "Pois" +info: + description: | Returns points of interest in the area surrounding a geometry (geometry and/or bbox). + version: "0.1" + title: "Openpoiservice" + contact: + email: "support@openrouteservice.org" + license: + name: "MIT" + url: "https://github.com/swagger-api/swagger-ui/blob/master/LICENSE" consumes: - - application/json +- "application/json" +schemes: +- "https" produces: - - application/json -parameters: - - name: body - in: body - required: True - description: body for a post request - schema: - $ref: '#/definitions/LocationsBodyPois' - # this does not work yet.. - # https://swagger.io/docs/specification/describing-request-body/ - # oneOf: - #- $ref: '#/definitions/LocationsBodyPois' - #- $ref: '#/definitions/LocationsBodyStats' - #- $ref: '#/definitions/LocationsBodyList' - -responses: - 200: - description: Standard response for successfully processed requests. - schema: - $ref: '#/definitions/LocationsPoiResponse' - # oneOf: - #- $ref: '#/definitions/LocationsPoiResponse' - #- $ref: '#/definitions/LocationsStatsResponse' - #- $ref: '#/definitions/LocationsListResponse' - 400: - description: Unable to parse JSON request. - 401: - description: Required parameter is missing. - 402: - description: Invalid parameter format. - 403: - description: Invalid parameter value. - 404: - description: Parameter value exceeds the maximum allowed limit. - 499: - description: Unknown internal error. +- "application/json" +host: "api.openrouteservice.org" +security: +- UserSecurity: [api_key] +paths: + "/pois": + post: + parameters: + - name: "api_key" + in: "query" + description: | + Insert your API Key here. + type: "string" + required: true + default: "your-api-key" + - in: body + name: "body" + required: true + description: body for a post request + schema: + $ref: '#/definitions/LocationsBodyPois' + # this does not work yet.. + # https://swagger.io/docs/specification/describing-request-body/ + # oneOf: + #- $ref: '#/definitions/LocationsBodyPois' + #- $ref: '#/definitions/LocationsBodyStats' + #- $ref: '#/definitions/LocationsBodyList' + responses: + 200: + description: Standard response for successfully processed requests. + schema: + $ref: '#/definitions/LocationsPoiResponse' + # oneOf: + #- $ref: '#/definitions/LocationsPoiResponse' + #- $ref: '#/definitions/LocationsStatsResponse' + #- $ref: '#/definitions/LocationsListResponse' + 400: + description: Unable to parse JSON request. + 401: + description: Required parameter is missing. + 402: + description: Invalid parameter format. + 403: + description: Invalid parameter value. + 404: + description: Parameter value exceeds the maximum allowed limit. + 499: + description: Unknown internal error. +securityDefinitions: + UserSecurity: + name: "api_key" + description: | + Add your API Key as the value of the api_key parameter to your request. + type: "apiKey" + in: "query" definitions: LocationsBodyPois: + example: "{1: 1}" type: object required: - request @@ -157,12 +187,12 @@ definitions: - distance bbox: type: array - items: - type: array - minItems: 2 - maxItems: 2 - items: - type: float + #items: + # type: array + # minItems: 2 + # maxItems: 2 + # items: + # type: float minItems: 2 maxItems: 2 example: [[53.075051,8.798952],[53.080785,8.907160]] @@ -177,20 +207,20 @@ definitions: }' # SHARED CUSTOM PROPERTIES name: - description: Name to filter the POIs by using sql like. - type: list + description: Filter by name of the poi object. + type: array example: ["Tankstelle",...] wheelchair: - description: Filter returned features by wheelchair tag entries. - type: list + description: Filter example. + type: array example: ["yes", "no", "limited", "designated"] smoking: - description: Filter returned features by smoking tag entries. - type: list + description: Filter example. + type: array example: ["dedicated","yes","no","separated","isolated","outside"] fee: - description: Filter returned features by fee tag entries. - type: list + description: Filter example. + type: array example: ["yes", "no"] # List response object @@ -201,13 +231,13 @@ definitions: # Poi response object LocationsPoiResponse: - type: object + type: "object" properties: type: - type: string - default: FeatureCollection + type: "string" + default: "FeatureCollection" features: - type: array + type: "array" items: $ref: "#/definitions/location_features" title: "Openpoiservice poi response" @@ -285,7 +315,9 @@ definitions: location_features_properties: properties: osm_id: - type: "string" + type: "number" + osm_type: + type: "number" category_id: type: "string" name: diff --git a/openpoiservice/server/api/query_builder.py b/openpoiservice/server/api/query_builder.py index 0546c41..971e8a1 100644 --- a/openpoiservice/server/api/query_builder.py +++ b/openpoiservice/server/api/query_builder.py @@ -93,7 +93,7 @@ def request_pois(self): sortby_group.append(bbox_query.c.category) pois_query = db.session \ - .query(bbox_query.c.osm_id, bbox_query.c.category, + .query(bbox_query.c.osm_id, bbox_query.c.osm_type, bbox_query.c.category, bbox_query.c.geom.ST_Distance(type_coerce(geom, Geography)), bbox_query.c.t_osm_id, bbox_query.c.key, bbox_query.c.value, bbox_query.c.geom) \ .order_by(*sortby_group) \ @@ -216,19 +216,20 @@ def generate_geojson_features(cls, query, limit): osm_ids_list = [] for q in query: - + print(q) if q[0] not in features: - point = wkb.loads(str(q[6]), hex=True) + point = wkb.loads(str(q[7]), hex=True) geojson_point = geojson.Point((point.x, point.y)) features[q[0]] = { "properties": { - "distance": q[2], + "distance": q[3], "osm_id": q[0], - "category_id": q[1], - "category_name": categories_tools.category_ids_index[q[1]]['poi_name'], - "category_group": categories_tools.category_ids_index[q[1]]['poi_group'], - q[4]: q[5] + "osm_type": q[1], + "category_id": q[2], + "category_name": categories_tools.category_ids_index[q[2]]['poi_name'], + "category_group": categories_tools.category_ids_index[q[2]]['poi_group'], + q[5]: q[6] }, "geometry": geojson_point, @@ -238,7 +239,7 @@ def generate_geojson_features(cls, query, limit): else: - features[q[0]][q[4]] = q[5] + features[q[0]][q[5]] = q[6] geojson_features = [] # keep order!!! diff --git a/openpoiservice/server/api/query_info.py b/openpoiservice/server/api/query_info.py new file mode 100644 index 0000000..23769d2 --- /dev/null +++ b/openpoiservice/server/api/query_info.py @@ -0,0 +1,27 @@ +# openpoiservice/server/query_info.py +import time +import logging + +logger = logging.getLogger(__name__) + + +class QueryInfo(object): + """ Class that creates the query.""" + + def __init__(self, payload): + """ + Initializes the query builder. + + :param payload: processed GET or POST parameters + :type payload: dict + """ + + self.attribution = "openrouteservice.org | OpenStreetMap contributors" + self.version = "0.1" + self.timestamp = int(time.time()) + self.query = payload + + + + + diff --git a/openpoiservice/server/api/views.py b/openpoiservice/server/api/views.py index ddffb50..df7f1e1 100755 --- a/openpoiservice/server/api/views.py +++ b/openpoiservice/server/api/views.py @@ -8,9 +8,11 @@ from openpoiservice.server import api_exceptions, ops_settings from openpoiservice.server.api.query_builder import QueryBuilder from openpoiservice.server.utils.geometries import parse_geometry, validate_limit, transform_geom -from flasgger.utils import swag_from +from openpoiservice.server.api.query_info import QueryInfo import geojson import json +import copy + # from flasgger import validate @@ -72,7 +74,6 @@ def custom_schema(): @main_blueprint.route('/pois', methods=['POST']) -@swag_from('pois_post.yml', methods=['POST']) def places(): """ Function called when user posts or gets to /places. @@ -84,9 +85,12 @@ def places(): if request.method == 'POST': - if request.headers['Content-Type'] == 'application/json' and request.is_json: + if 'application/json' in request.headers['Content-Type'] and request.is_json: all_args = request.get_json(silent=True) + + raw_request = copy.deepcopy(all_args) + if all_args is None: raise api_exceptions.InvalidUsage('Invalid JSON object in request', status_code=400) @@ -111,8 +115,15 @@ def places(): # check restrictions and parse geometry all_args['geometry'] = parse_geometries(all_args['geometry']) + + features = request_pois(all_args) + + query_info = QueryInfo(raw_request).__dict__ + + features["information"] = query_info + # query pois - return Response(json.dumps(request_pois(all_args)), mimetype='application/json') + return Response(json.dumps(features), mimetype='application/json') # cant use jsonify directly for tests, error since upgrade python36, wtf? # return jsonify(request_pois(all_args)) diff --git a/requirements.txt b/requirements.txt index f5ee57b..860b962 100755 --- a/requirements.txt +++ b/requirements.txt @@ -13,4 +13,5 @@ flasgger==0.8.1 pyproj==1.9.5.1 scrapy==1.5.0 gunicorn==19.7.1 +flask-cors==3.0.3 git+https://github.com/lechup/imposm-parser.git@python3 \ No newline at end of file From 142fe2dff58b0bfc2c2e174d2d949ef84331e157 Mon Sep 17 00:00:00 2001 From: TimMcCauley Date: Tue, 3 Apr 2018 09:32:17 +0200 Subject: [PATCH 2/2] . --- openpoiservice/server/api/query_builder.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpoiservice/server/api/query_builder.py b/openpoiservice/server/api/query_builder.py index 971e8a1..a98a16f 100644 --- a/openpoiservice/server/api/query_builder.py +++ b/openpoiservice/server/api/query_builder.py @@ -216,7 +216,6 @@ def generate_geojson_features(cls, query, limit): osm_ids_list = [] for q in query: - print(q) if q[0] not in features: point = wkb.loads(str(q[7]), hex=True) geojson_point = geojson.Point((point.x, point.y))