Skip to content

Commit 897ea39

Browse files
committed
Replaced flasgger. Added connexion
1 parent ec2e9e3 commit 897ea39

File tree

7 files changed

+144
-192
lines changed

7 files changed

+144
-192
lines changed

project/__init__.py

Lines changed: 17 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
import logging
44
import os
55

6-
from flasgger import Swagger
7-
from flask import Flask
6+
import connexion
87
from flask_injector import FlaskInjector
98
from injector import Injector
109

@@ -23,109 +22,39 @@
2322

2423
ENVIRONMENT = os.environ.get("ENVIRONMENT", "default")
2524

26-
SWAGGER_CONFIG = {
27-
"headers": [
28-
],
29-
"specs": [
30-
{
31-
"endpoint": 'apispec_1',
32-
"route": '{application_root}/apispec_1.json',
33-
"rule_filter": lambda rule: True, # all in
34-
"model_filter": lambda tag: True, # all in
35-
}
36-
],
37-
"info": {
38-
"title": "API ",
39-
"description": "API para...",
40-
"contact": {
41-
"responsibleOrganization": "ME",
42-
"responsibleDeveloper": "Me",
43-
"email": "me@me.com",
44-
},
45-
"version": "0.0.1"
46-
},
47-
"securityDefinitions": {
48-
"APIKeyHeader": {"type": "apiKey", "name": "Authorization", "in": "header"},
49-
},
50-
"static_url_path": "{application_root}/flasgger_static",
51-
"swagger_ui": True,
52-
"uiversion": 2,
53-
"specs_route": "/apidocs/",
54-
"basePath": "{application_root}"
55-
}
56-
57-
58-
class PrefixMiddleware(object):
59-
"""Set a prefix path to all routes. This action is needed if you have a stack of microservices and each of them
60-
exist in the same domain but different path. Por example:
61-
* mydomain.com/ms1/
62-
* mydomain.com/ms2/
63-
"""
64-
65-
def __init__(self, app, prefix=''):
66-
self.app = app
67-
self.prefix = prefix
68-
69-
def __call__(self, environ, start_response):
70-
if environ['PATH_INFO'].startswith(self.prefix):
71-
environ['PATH_INFO'] = environ['PATH_INFO'][len(self.prefix):]
72-
environ['SCRIPT_NAME'] = self.prefix
73-
return self.app(environ, start_response)
74-
elif environ['PATH_INFO'].startswith("/healthcheck"):
75-
return self.app(environ, start_response)
76-
else:
77-
start_response('404', [('Content-Type', 'text/plain')])
78-
return ["This url does not belong to the app.".encode()]
79-
8025

8126
def create_app():
8227
"""Initialize the Flask app, register blueprints and intialize all libraries like Swagger, database, the trace system...
8328
return the app and the database objects.
8429
:return:
8530
"""
86-
87-
from project.views import views_bp as views_blueprint
8831
environment = os.environ.get("ENVIRONMENT", "default")
8932

90-
app = Flask(__name__)
91-
app.config.from_object(CONFIG[environment])
92-
app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix=app.config["APPLICATION_ROOT"])
93-
94-
db.init_app(app)
33+
app = connexion.App(__name__, specification_dir='./swagger/')
34+
# app.app.json_encoder = encoder.JSONEncoder
35+
app.add_api('swagger.yaml', arguments={'title': 'Swagger Example Project'})
9536

96-
# Initialize Swagger
97-
SWAGGER_CONFIG["specs"][0]["route"] = SWAGGER_CONFIG["specs"][0]["route"].format(
98-
application_root=app.config["APPLICATION_ROOT"]
99-
)
100-
SWAGGER_CONFIG["static_url_path"] = SWAGGER_CONFIG["static_url_path"].format(
101-
application_root=app.config["APPLICATION_ROOT"]
102-
)
103-
SWAGGER_CONFIG["specs_route"] = SWAGGER_CONFIG["specs_route"].format(
104-
application_root=app.config["APPLICATION_ROOT"]
105-
)
106-
SWAGGER_CONFIG["basePath"] = SWAGGER_CONFIG["basePath"].format(
107-
application_root=app.config["APPLICATION_ROOT"]
108-
)
109-
Swagger(app, config=SWAGGER_CONFIG)
37+
application = app.app
38+
application.config.from_object(CONFIG[environment])
39+
db.init_app(application)
11040

11141
# Initialize Blueprints
112-
app.register_blueprint(views_blueprint)
113-
app.register_blueprint(healthcheck_blueprint)
42+
application.register_blueprint(healthcheck_blueprint)
11443

11544
# Inject Modules
116-
# Inject Modules
117-
if not app.config["TESTING"] and not app.config["DEBUG"]:
45+
if not application.config["TESTING"] and not application.config["DEBUG"]:
11846
log_handler = logging.StreamHandler()
11947
formatter = CustomJsonFormatter('(timestamp) (level) (name) (module) (funcName) (lineno) (message)')
120-
formatter.add_service_name(app.config["APP_NAME"])
121-
tracer = TracerModule(app)
48+
formatter.add_service_name(application.config["APP_NAME"])
49+
tracer = TracerModule(application)
12250
injector = Injector([tracer])
123-
FlaskInjector(app=app, injector=injector)
51+
FlaskInjector(app=application, injector=injector)
12452
formatter.add_trace_span(tracer.tracer)
12553
log_handler.setFormatter(formatter)
126-
app.logger.addHandler(log_handler)
127-
app.logger.setLevel(logging.INFO)
54+
application.logger.addHandler(log_handler)
55+
application.logger.setLevel(logging.INFO)
12856

129-
with app.test_request_context():
57+
with application.test_request_context():
13058
db.create_all()
131-
return app, db
59+
60+
return application, db

project/swagger/swagger.yaml

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
---
2+
swagger: "2.0"
3+
info:
4+
description: "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters."
5+
version: "1.0.0"
6+
title: "Swagger Petstore"
7+
termsOfService: "http://swagger.io/terms/"
8+
contact:
9+
email: "apiteam@swagger.io"
10+
license:
11+
name: "Apache 2.0"
12+
url: "http://www.apache.org/licenses/LICENSE-2.0.html"
13+
basePath: "/template"
14+
tags:
15+
- name: "colors"
16+
description: "Everything about your colors"
17+
externalDocs:
18+
description: "Find out more"
19+
url: "http://swagger.io"
20+
- name: "store"
21+
description: "Example endpoint list of colors"
22+
- name: "user"
23+
description: "Operations about user"
24+
externalDocs:
25+
description: "Find out more about our store"
26+
url: "http://swagger.io"
27+
schemes:
28+
- "http"
29+
paths:
30+
/:
31+
post:
32+
tags:
33+
- "colors"
34+
summary: "Example endpoint return create a color"
35+
description: ""
36+
operationId: "create_view"
37+
consumes:
38+
- "application/json"
39+
produces:
40+
- "application/json"
41+
parameters:
42+
- in: "body"
43+
name: "name"
44+
description: "Pet object that needs to be added to the store"
45+
required: true
46+
schema:
47+
$ref: "#/definitions/Color"
48+
responses:
49+
200:
50+
description: "The color created"
51+
schema:
52+
$ref: '#/definitions/Color'
53+
405:
54+
description: "Invalid input"
55+
x-swagger-router-controller: "project.views.views"
56+
get:
57+
tags:
58+
- "colors"
59+
summary: "Example endpoint return a list of colors by palette"
60+
description: ""
61+
operationId: "list_view"
62+
consumes:
63+
- "application/json"
64+
produces:
65+
- "application/json"
66+
responses:
67+
200:
68+
description: "A list of colors (may be filtered by palette)"
69+
schema:
70+
$ref: '#/definitions/Color'
71+
400:
72+
description: "Invalid ID supplied"
73+
404:
74+
description: "Pet not found"
75+
405:
76+
description: "Validation exception"
77+
x-swagger-router-controller: "project.views.views"
78+
definitions:
79+
Color:
80+
type: "object"
81+
properties:
82+
id:
83+
type: "string"
84+
timestamp:
85+
type: "string"
86+
name:
87+
type: "string"
88+
externalDocs:
89+
description: "Find out more about Swagger"
90+
url: "http://swagger.io"

project/tests/test_views.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ def test_list_view(self):
3636

3737
def test_create_view(self):
3838
name = "blue"
39-
response = self.client.post('{base_url}/'.format(base_url=self.base_url), data={"name": name})
39+
response = self.client.post('{base_url}/'.format(
40+
base_url=self.base_url),
41+
data=json.dumps(dict(name=name)),
42+
content_type='application/json'
43+
)
4044
self.assertEqual(response.status_code, 200)
4145
self.assertEqual(_format_response(response.data)["name"], name)

project/views/__init__.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,2 @@
11
# coding=utf-8
2-
from __future__ import unicode_literals, print_function, absolute_import, division
3-
4-
from flask import Blueprint
5-
6-
views_bp = Blueprint('views', __name__, static_url_path='/static')
7-
8-
from project.views import views
2+
from __future__ import unicode_literals, print_function, absolute_import, division

project/views/views.py

Lines changed: 10 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,31 @@
11
# encoding: utf-8
22
from __future__ import absolute_import, print_function, unicode_literals
3-
3+
import connexion
44
from flask import request, jsonify, current_app
55

66
from pyms.models import db
77
from project.models.models import Colors
8-
from project.views import views_bp
98

109

11-
@views_bp.route('/', methods=['GET'])
1210
def list_view():
1311
"""Example endpoint return a list of colors by palette
14-
---
15-
tags:
16-
- colors
17-
operationId: get_colors
18-
consumes:
19-
- application/json
20-
produces:
21-
- application/json
22-
schemes: ['http']
23-
deprecated: false
24-
externalDocs:
25-
description: Project repository
26-
url: http://github.com/rochacbruno/flasgger
27-
definitions:
28-
Color:
29-
type: object
30-
properties:
31-
id:
32-
type: string
33-
timestamp:
34-
type: datetime
35-
name:
36-
type: string
37-
responses:
38-
200:
39-
description: A list of colors (may be filtered by palette)
40-
schema:
41-
$ref: '#/definitions/Color'
42-
examples:
43-
[{
44-
"id": "2c951676-...",
45-
"name": "blue",
46-
"timestamp": [
47-
"2018-03-24",
48-
"15:49:24"
49-
]
50-
},
51-
{
52-
"id": "2c951676-...",
53-
"name": "geen",
54-
"timestamp": [
55-
"2018-03-24",
56-
"15:49:24"
57-
]
58-
}]
5912
"""
6013
current_app.logger.info("Return all color list")
6114
query = Colors.query.all()
6215

6316
return jsonify([i.serialize for i in query])
6417

6518

66-
@views_bp.route('/', methods=['POST'])
6719
def create_view():
6820
"""Example endpoint return create a color
69-
---
70-
tags:
71-
- colors
72-
operationId: get_colors
73-
consumes:
74-
- multipart/form-data
75-
produces:
76-
- application/json
77-
schemes: ['http']
78-
deprecated: false
79-
parameters:
80-
- name: name
81-
in: formData
82-
type: string
83-
required: true
84-
description: Color name
85-
definitions:
86-
Color:
87-
type: object
88-
properties:
89-
id:
90-
type: string
91-
timestamp:
92-
type: datetime
93-
name:
94-
type: string
95-
responses:
96-
200:
97-
description: The color created
98-
schema:
99-
$ref: '#/definitions/Color'
100-
examples:
101-
{
102-
"id": "2c951676-7e6b-4720-971d-9c62e461c74d",
103-
"name": "blue",
104-
"timestamp": [
105-
"2018-03-24",
106-
"15:49:24"
107-
]
108-
}
10921
"""
22+
# import ipdb; ipdb.set_trace()
11023
current_app.logger.info("Create color")
111-
color = Colors(name=request.form["name"])
112-
db.session.add(color)
113-
db.session.commit()
114-
115-
return jsonify(color.serialize)
24+
if connexion.request.is_json:
25+
data = connexion.request.get_json()
26+
color = Colors(name=data["name"])
27+
db.session.add(color)
28+
db.session.commit()
29+
30+
return jsonify(color.serialize)
31+
return jsonify({})

pyms/utils/encoder.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from connexion.apps.flask_app import FlaskJSONEncoder
2+
import six
3+
4+
from swagger_server.models.base_model_ import Model
5+
6+
7+
class JSONEncoder(FlaskJSONEncoder):
8+
include_nulls = False
9+
10+
def default(self, o):
11+
if isinstance(o, Model):
12+
dikt = {}
13+
for attr, _ in six.iteritems(o.swagger_types):
14+
value = getattr(o, attr)
15+
if value is None and not self.include_nulls:
16+
continue
17+
attr = o.attribute_map[attr]
18+
dikt[attr] = value
19+
return dikt
20+
return FlaskJSONEncoder.default(self, o)

0 commit comments

Comments
 (0)