Browse Source

Add bottle_fake_api example

Guénaël Muller 6 years ago
parent
commit
d62624d13f
2 changed files with 175 additions and 0 deletions
  1. 121 0
      example/fake_api/bottle_api.py
  2. 54 0
      example/fake_api/schema.py

+ 121 - 0
example/fake_api/bottle_api.py View File

@@ -0,0 +1,121 @@
1
+# -*- coding: utf-8 -*-
2
+import json
3
+from http import HTTPStatus
4
+
5
+import bottle
6
+import time
7
+from datetime import datetime
8
+import hapic
9
+from example.fake_api.schema import *
10
+from hapic.data import HapicData
11
+
12
+
13
+class NoContentException(Exception):
14
+    pass
15
+
16
+
17
+class Controllers(object):
18
+    @hapic.with_api_doc()
19
+    @hapic.output_body(AboutResponseSchema())
20
+    def about(self):
21
+        """
22
+        General information about this API.
23
+        """
24
+        return {
25
+            'version': '1.2.3',
26
+            'datetime': datetime.now(),
27
+        }
28
+
29
+    @hapic.with_api_doc()
30
+    @hapic.output_body(ListsUserSchema())
31
+    def get_users(self):
32
+        """
33
+        Obtain users list.
34
+        """
35
+        return {
36
+            'item_nb': 1,
37
+            'items': [
38
+                {
39
+                    'id': 4,
40
+                    'username': 'some_user',
41
+                    'display_name': 'Damien Accorsi',
42
+                    'company': 'Algoo',
43
+                },
44
+            ],
45
+            'pagination': {
46
+                'first_id': 0,
47
+                'last_id': 5,
48
+                'current_id': 0,
49
+            }
50
+        }
51
+
52
+    @hapic.with_api_doc()
53
+    @hapic.input_path(UserPathSchema())
54
+    @hapic.output_body(UserSchema())
55
+    def get_user(self, id, hapic_data: HapicData):
56
+        """
57
+        Obtain one user
58
+        """
59
+        return {
60
+             'id': 4,
61
+             'username': 'some_user',
62
+             'email_address': 'some.user@hapic.com',
63
+             'first_name': 'Damien',
64
+             'last_name': 'Accorsi',
65
+             'display_name': 'Damien Accorsi',
66
+             'company': 'Algoo',
67
+        }
68
+
69
+    @hapic.with_api_doc()
70
+    # TODO - G.M - 2017-12-5 - Support input_forms ?
71
+    # TODO - G.M - 2017-12-5 - Support exclude, only ?
72
+    @hapic.input_body(UserSchema(exclude=('id',)))
73
+    @hapic.output_body(UserSchema())
74
+    def add_user(self, hapic_data: HapicData):
75
+        """
76
+        Add new user
77
+        """
78
+        return {
79
+             'id': 4,
80
+             'username': 'some_user',
81
+             'email_address': 'some.user@hapic.com',
82
+             'first_name': 'Damien',
83
+             'last_name': 'Accorsi',
84
+             'display_name': 'Damien Accorsi',
85
+             'company': 'Algoo',
86
+        }
87
+
88
+    @hapic.with_api_doc()
89
+    @hapic.handle_exception(NoContentException, http_code=HTTPStatus.NO_CONTENT)
90
+    @hapic.input_path(UserPathSchema())
91
+    def del_user(self, id, hapic_data: HapicData):
92
+        """
93
+        delete user
94
+        """
95
+
96
+        # TODO - G.M - 2017-12-05 - Add better
97
+        #  way to doc response of this function, using response object ?
98
+        # return bottle.Response(
99
+        #     status=204,
100
+        # )
101
+        raise NoContentException
102
+
103
+    def bind(self, app:bottle.Bottle):
104
+        app.route('/about', callback=self.about)
105
+        app.route('/users', callback=self.get_users)
106
+        app.route('/users/<id>', callback=self.get_user)
107
+        app.route('/users/', callback=self.add_user,  method='POST')
108
+        app.route('/users/<id>', callback=self.del_user, method='DELETE')
109
+
110
+
111
+app = bottle.Bottle()
112
+controllers = Controllers()
113
+controllers.bind(app)
114
+hapic.set_context(hapic.ext.bottle.BottleContext(app))
115
+time.sleep(1)
116
+s = json.dumps(hapic.generate_doc())
117
+time.sleep(1)
118
+# print swagger doc
119
+print(s)
120
+# Run app
121
+app.run(host='localhost', port=8080, debug=True)

+ 54 - 0
example/fake_api/schema.py View File

@@ -0,0 +1,54 @@
1
+# -*- coding: utf-8 -*-
2
+import marshmallow
3
+
4
+
5
+class AboutResponseSchema(marshmallow.Schema):
6
+    version = marshmallow.fields.String(required=True,)
7
+    datetime = marshmallow.fields.DateTime(required=True)
8
+
9
+
10
+class UserPathSchema(marshmallow.Schema):
11
+    id = marshmallow.fields.Int(
12
+        required=True,
13
+        validate=marshmallow.validate.Range(min=1),
14
+    )
15
+
16
+
17
+class UserSchema(marshmallow.Schema):
18
+    id = marshmallow.fields.Int(required=True)
19
+    username = marshmallow.fields.String(
20
+        required=True,
21
+        validate = marshmallow.validate.Regexp(regex='[\w-]+'),
22
+    )
23
+    email_address = marshmallow.fields.Email(required=True)
24
+    first_name = marshmallow.fields.String(required=True)
25
+    last_name = marshmallow.fields.String(required=True)
26
+    display_name = marshmallow.fields.String(required=True)
27
+    company = marshmallow.fields.String(required=True)
28
+
29
+
30
+class PaginationSchema(marshmallow.Schema):
31
+    first_id = marshmallow.fields.Int(required=True)
32
+    last_id = marshmallow.fields.Int(required=True)
33
+    current_id = marshmallow.fields.Int(required=True)
34
+
35
+
36
+class ListsUserSchema(marshmallow.Schema):
37
+    item_nb = marshmallow.fields.Int(
38
+        required=True,
39
+        validate=marshmallow.validate.Range(min=0)
40
+    )
41
+    items = marshmallow.fields.Nested(
42
+        UserSchema,
43
+        many=True,
44
+        only=['id', 'username', 'display_name', 'company']
45
+    )
46
+    # TODO - G.M - 2017-12-05 - Fix nested schema import into doc !
47
+    # Can't add doc for nested Schema properly
48
+    # When schema item isn't added through their own method
49
+    # Ex : Pagination Schema doesn't work here but UserSchema is ok.
50
+    pagination = {
51
+        'first_id': marshmallow.fields.Int(required=True),
52
+        'last_id': marshmallow.fields.Int(required=True),
53
+        'current_id': marshmallow.fields.Int(required=True),
54
+    }