bisslog-flask 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,26 @@
1
+ """
2
+ bisslog_flask
3
+
4
+ An extension of the `bisslog` library to support service orchestration via Flask.
5
+
6
+ This package enables dynamic registration of HTTP and WebSocket routes in a Flask
7
+ application, using declarative metadata (YAML/JSON). It promotes clean separation
8
+ between application logic and infrastructure concerns, aligning with hexagonal
9
+ or clean architecture principles.
10
+
11
+
12
+ Requirements
13
+ ------------
14
+ - Flask >= 2.0
15
+ - bisslog-schema >= 0.0.3
16
+ - flask-cors
17
+ - (optional) flask-socketio for WebSocket integration
18
+
19
+ License
20
+ -------
21
+ MIT ยฉ Darwin Stiven Herrera Cartagena
22
+ """
23
+ from .initializer.init_flask_app_manager import BisslogFlask
24
+ from .socket_helper.socket_helper import BisslogFlaskSocketHelper
25
+
26
+ __all__ = ["BisslogFlask", "BisslogFlaskSocketHelper"]
File without changes
@@ -0,0 +1,186 @@
1
+ """
2
+ Flask HTTP resolver for Bisslog-based use case routing.
3
+
4
+ This module provides a class to dynamically register HTTP endpoints
5
+ in a Flask application using 'use case metadata'. It supports CORS configuration
6
+ and flexible request mapping using the Bisslog schema and Mapper.
7
+
8
+ Classes
9
+ -------
10
+ BisslogFlaskHttpResolver : Register HTTP routes for use cases based on metadata.
11
+
12
+ Dependencies
13
+ ------------
14
+ - Flask
15
+ - flask_cors
16
+ - bisslog_schema
17
+ - bisslog.utils.mapping
18
+ """
19
+ from copy import deepcopy
20
+ from typing import Callable, Optional, Dict
21
+
22
+ from flask import Flask, request, jsonify
23
+ try:
24
+ from flask_cors import cross_origin
25
+ except ImportError:
26
+ cross_origin = None
27
+ from bisslog.utils.mapping import Mapper
28
+ from bisslog_schema.schema import UseCaseInfo, TriggerHttp, TriggerInfo
29
+ from bisslog_schema.schema.triggers.trigger_mappable import TriggerMappable
30
+
31
+ from .bisslog_flask_resolver import BisslogFlaskResolver
32
+
33
+
34
+ class BisslogFlaskHttpResolver(BisslogFlaskResolver):
35
+ """
36
+ Flask HTTP resolver that dynamically registers use cases as routes based on metadata.
37
+
38
+ This resolver wraps use case callables and maps request data accordingly,
39
+ applying optional CORS configuration at the endpoint level.
40
+
41
+ Inherits
42
+ --------
43
+ BisslogFlaskResolver
44
+ Base resolver interface for trigger-based route binding.
45
+ """
46
+
47
+ @staticmethod
48
+ def _lambda_fn(*args, fn, __mapper__: Optional[Mapper], **kwargs):
49
+ """Wraps a use case function to extract and map request data.
50
+
51
+ Parameters
52
+ ----------
53
+ *args : tuple
54
+ Positional arguments passed by Flask (usually none).
55
+ fn : Callable
56
+ The actual use case function to invoke.
57
+ __mapper__ : Optional[Mapper]
58
+ Mapper to transform HTTP request parts into function arguments.
59
+ **kwargs : dict
60
+ Keyword arguments passed by Flask (URL params, etc.).
61
+
62
+ Returns
63
+ -------
64
+ flask.Response
65
+ A JSON response with the result of the use case.
66
+ """
67
+ if __mapper__ is None:
68
+ more_kwargs = {}
69
+ if request.method.lower() not in ["get"]:
70
+ more_kwargs.update(request.get_json(silent=True) or {})
71
+ return jsonify(fn(*args, **kwargs, **more_kwargs))
72
+
73
+ res_map = __mapper__.map({
74
+ "path_query": request.view_args or {},
75
+ "body": request.get_json(silent=True) or {},
76
+ "params": request.args.to_dict(),
77
+ "headers": request.headers,
78
+ })
79
+ res = fn(**res_map)
80
+
81
+ return jsonify(res)
82
+
83
+ @staticmethod
84
+ def _use_case_factory(
85
+ use_case_name: str,
86
+ fn: Callable,
87
+ mapper: Optional[Dict[str, str]] = None,
88
+ trigger: Optional[TriggerHttp] = None
89
+ ):
90
+ """
91
+ Factory to produce a Flask view function with optional mapping and CORS.
92
+
93
+ Parameters
94
+ ----------
95
+ use_case_name : str
96
+ Unique name of the use case.
97
+ fn : Callable
98
+ The function to be wrapped and exposed via HTTP.
99
+ mapper : dict, optional
100
+ Mapping schema for request fields, if applicable.
101
+ trigger : TriggerHttp, optional
102
+ Trigger options used to configure CORS.
103
+
104
+ Returns
105
+ -------
106
+ Callable
107
+ A Flask-compatible view function.
108
+ """
109
+ use_case_fn_copy = deepcopy(fn)
110
+ __mapper__ = Mapper(name=f"Mapper {use_case_name}", base=mapper) if mapper else None
111
+
112
+ def uc(*args, **kwargs):
113
+ return BisslogFlaskHttpResolver._lambda_fn(
114
+ *args, fn=use_case_fn_copy, __mapper__=__mapper__, **kwargs
115
+ )
116
+
117
+ # Apply CORS dynamically if allowed
118
+ if trigger and trigger.allow_cors:
119
+ if cross_origin is None:
120
+ raise ImportError("flask_cors is not installed, please install it")
121
+ cors_kwargs = {
122
+ "origins": trigger.allowed_origins or "*",
123
+ "methods": [trigger.method.upper()],
124
+ "allow_headers": ["Content-Type", "Authorization"],
125
+ "supports_credentials": True
126
+ }
127
+ return cross_origin(**cors_kwargs)(uc)
128
+
129
+ return uc
130
+
131
+ @classmethod
132
+ def _add_use_case(cls, app: Flask, use_case_info: UseCaseInfo, trigger: TriggerInfo,
133
+ use_case_function):
134
+ """
135
+ Adds an HTTP endpoint to the Flask app for a given use case.
136
+
137
+ Parameters
138
+ ----------
139
+ app : Flask
140
+ The Flask application instance.
141
+ use_case_info : UseCaseInfo
142
+ Metadata describing the use case being added.
143
+ trigger : TriggerInfo
144
+ Metadata describing the trigger configuration (must be HTTP).
145
+ use_case_function : Callable
146
+ The use case logic to expose via HTTP.
147
+ """
148
+ if not isinstance(trigger.options, TriggerHttp):
149
+ return
150
+
151
+ method = trigger.options.method.upper()
152
+ path = trigger.options.path.replace("{", "<").replace("}", ">")
153
+
154
+ mapper = (
155
+ trigger.options.mapper
156
+ if isinstance(trigger.options, TriggerMappable)
157
+ else None
158
+ )
159
+ app.add_url_rule(
160
+ path,
161
+ endpoint=use_case_info.keyname + " " + path,
162
+ methods=[method],
163
+ view_func=cls._use_case_factory(
164
+ use_case_name=use_case_info.keyname,
165
+ fn=use_case_function,
166
+ mapper=mapper,
167
+ trigger=trigger.options
168
+ )
169
+ )
170
+
171
+ def __call__(self, app: Flask, use_case_info: UseCaseInfo,
172
+ trigger_info: TriggerInfo, use_case_callable: Callable, **kwargs):
173
+ """Entry point to register a use case route using this resolver.
174
+
175
+ Parameters
176
+ ----------
177
+ app : Flask
178
+ The Flask app where the route will be registered.
179
+ use_case_info : UseCaseInfo
180
+ Metadata of the use case.
181
+ trigger_info : TriggerInfo
182
+ Trigger configuration for the route.
183
+ use_case_callable : Callable
184
+ The function to execute when the route is called.
185
+ """
186
+ self._add_use_case(app, use_case_info, trigger_info, use_case_callable)
@@ -0,0 +1,46 @@
1
+ """
2
+ Abstract base class for Bisslog Flask route resolvers.
3
+
4
+ This module defines a common interface for resolving use case routes
5
+ in a Flask application. Subclasses implement logic to register routes
6
+ based on different trigger types (e.g., HTTP, WebSocket).
7
+ """
8
+ from abc import ABC, abstractmethod
9
+ from typing import Callable
10
+
11
+ from bisslog_schema.schema import UseCaseInfo, TriggerInfo
12
+
13
+ from flask import Flask
14
+
15
+
16
+ class BisslogFlaskResolver(ABC):
17
+ """Abstract base class for registering use case routes in a Flask application.
18
+
19
+ Implementations of this class handle the translation of trigger metadata
20
+ into concrete route registration logic, such as for HTTP or WebSocket endpoints.
21
+
22
+ Subclasses must implement the `__call__` method to perform the actual route binding."""
23
+
24
+ @abstractmethod
25
+ def __call__(self, app: Flask, use_case_info: UseCaseInfo,
26
+ trigger_info: TriggerInfo, use_case_callable: Callable, **kwargs) -> Callable:
27
+ """
28
+ Registers a use case route in a Flask app based on the given trigger.
29
+
30
+ Parameters
31
+ ----------
32
+ app : Flask
33
+ The Flask application instance where the route should be registered.
34
+ use_case_info : UseCaseInfo
35
+ Metadata describing the use case, including name and key.
36
+ trigger_info : TriggerInfo
37
+ Trigger metadata (e.g., HTTP, WebSocket) describing how the route is activated.
38
+ use_case_callable : Callable
39
+ The function or class instance that implements the use case logic.
40
+
41
+ Raises
42
+ ------
43
+ NotImplementedError
44
+ If the method is not implemented by a subclass.
45
+ """
46
+ raise NotImplementedError
@@ -0,0 +1,76 @@
1
+ """
2
+ WebSocket resolver for Bisslog-based Flask applications using Flask-SocketIO.
3
+
4
+ This module defines the `BisslogFlaskWebSocketResolver` class, which dynamically registers
5
+ WebSocket-based use case triggers in a Flask app. The class uses metadata definitions to
6
+ configure event routes (via `route_key`) and binds them to corresponding use case functions.
7
+ """
8
+ from typing import Callable
9
+ from flask import Flask, request
10
+
11
+ try:
12
+ from flask_socketio import SocketIO
13
+ except ImportError:
14
+ class SocketIO:
15
+ """Socket IO simulator while is not installed"""
16
+ def __init__(self, _, ** __):
17
+ raise ImportError("flask socketio is not installed, please install it")
18
+
19
+ from bisslog.utils.mapping import Mapper
20
+ from bisslog_schema.schema import UseCaseInfo, TriggerInfo
21
+ from bisslog_schema.schema.triggers.trigger_websocket import TriggerWebsocket
22
+ from .bisslog_flask_resolver import BisslogFlaskResolver
23
+
24
+
25
+ class BisslogFlaskWebSocketResolver(BisslogFlaskResolver):
26
+ """
27
+ Resolver that registers WebSocket use cases using Flask-SocketIO.
28
+
29
+ This class maps WebSocket events (via route_key) to the use case callables.
30
+ If a SocketIO instance is not already attached to the Flask app,
31
+ a new one will be created and stored in `app.extensions["socketio"]`.
32
+ """
33
+
34
+ def __call__(self, app: Flask, use_case_info: UseCaseInfo,
35
+ trigger_info: TriggerInfo, use_case_callable: Callable, **kwargs):
36
+ """
37
+ Register a WebSocket event handler for a use case.
38
+
39
+ Parameters
40
+ ----------
41
+ app : Flask
42
+ The Flask app instance.
43
+ use_case_info : UseCaseInfo
44
+ Metadata about the use case.
45
+ trigger_info : TriggerWebsocket
46
+ Trigger options containing the route_key and mapper.
47
+ use_case_callable : Callable
48
+ The actual use case function to call when the event is triggered.
49
+ kwargs : dict
50
+ Additional optional arguments (ignored here).
51
+ """
52
+ if not isinstance(trigger_info.options, TriggerWebsocket):
53
+ return
54
+
55
+ # Get or create SocketIO instance
56
+ socket_io_obj = app.extensions.get("socketio")
57
+ if socket_io_obj is None:
58
+ socket_io_obj = SocketIO(app, cors_allowed_origins="*")
59
+ app.extensions["socketio"] = socket_io_obj
60
+
61
+ route_key = trigger_info.options.route_key
62
+ mapper = Mapper(
63
+ name=f"mapper-ws-{use_case_info.keyname}-{route_key}",
64
+ base=trigger_info.options.mapper
65
+ ) if trigger_info.options.mapper else None
66
+
67
+ @socket_io_obj.on(route_key)
68
+ def on_event(data):
69
+ mapped_data = mapper.map({
70
+ "route_key": route_key,
71
+ "connection_id": request.sid,
72
+ "body": data,
73
+ "headers": dict(request.headers)
74
+ }) if mapper else data
75
+
76
+ return use_case_callable(**mapped_data) if mapper else use_case_callable(data)
@@ -0,0 +1,123 @@
1
+ """
2
+ Flask application initializer for Bisslog-based services.
3
+
4
+ This module defines a manager that reads service metadata and dynamically registers
5
+ use case endpoints into a Flask application using resolvers for HTTP and WebSocket triggers.
6
+
7
+ Classes
8
+ -------
9
+ InitFlaskAppManager : Initializes a Flask app with routes from use case metadata.
10
+
11
+ Dependencies
12
+ ------------
13
+ - Flask
14
+ - bisslog_schema
15
+ - BisslogFlaskResolver
16
+ """
17
+
18
+ from typing import Optional, Callable
19
+
20
+ from bisslog_schema import read_service_info_with_code
21
+ from bisslog_schema.schema import UseCaseInfo, TriggerHttp, TriggerWebsocket
22
+ from flask import Flask
23
+
24
+ from .bisslog_flask_http_resolver import BisslogFlaskHttpResolver
25
+ from .bisslog_flask_resolver import BisslogFlaskResolver
26
+ from .bisslog_flask_ws_resolver import BisslogFlaskWebSocketResolver
27
+
28
+
29
+ class InitFlaskAppManager:
30
+ """
31
+ Initializes a Flask app by registering routes from metadata using HTTP and WebSocket resolvers.
32
+
33
+ This manager reads metadata and code, then applies the appropriate processor (resolver)
34
+ to each use case according to its trigger type.
35
+
36
+ Parameters
37
+ ----------
38
+ http_processor : BisslogFlaskResolver
39
+ Resolver used to handle HTTP-triggered use cases.
40
+ websocket_processor : BisslogFlaskResolver
41
+ Resolver used to handle WebSocket-triggered use cases.
42
+ """
43
+
44
+ def __init__(self, http_processor: BisslogFlaskResolver,
45
+ websocket_processor: BisslogFlaskResolver) -> None:
46
+ self._http_processor = http_processor
47
+ self._websocket_processor = websocket_processor
48
+
49
+ def __call__(
50
+ self,
51
+ metadata_file: Optional[str] = None,
52
+ use_cases_folder_path: Optional[str] = None,
53
+ app: Optional[Flask] = None,
54
+ *,
55
+ encoding: str = "utf-8",
56
+ secret_key: Optional[str] = None,
57
+ jwt_secret_key: Optional[str] = None,
58
+ **kwargs) -> Flask:
59
+ """
60
+ Loads metadata, discovers use case functions, registers routes and returns the Flask app.
61
+
62
+ This method reads metadata and code from the given paths, initializes the Flask app
63
+ (if not provided), configures security options, and applies HTTP or WebSocket processors
64
+ based on the trigger type for each use case.
65
+
66
+ Parameters
67
+ ----------
68
+ metadata_file : str, optional
69
+ Path to the metadata file (YAML/JSON).
70
+ use_cases_folder_path : str, optional
71
+ Directory where use case code is located.
72
+ app : Flask, optional
73
+ An existing Flask app instance to which routes will be added.
74
+ If not provided, a new app is created using the service name.
75
+ encoding : str, optional
76
+ File encoding for reading metadata (default is "utf-8").
77
+ secret_key : str, optional
78
+ Secret key to set in app config (used for session security).
79
+ jwt_secret_key : str, optional
80
+ JWT secret key to set in app config (used for token authentication).
81
+ **kwargs : Any
82
+ Additional keyword arguments (not currently used).
83
+
84
+ Returns
85
+ -------
86
+ Flask
87
+ The Flask app instance with registered use case routes.
88
+ """
89
+ full_service_data = read_service_info_with_code(
90
+ metadata_file=metadata_file,
91
+ use_cases_folder_path=use_cases_folder_path,
92
+ encoding=encoding
93
+ )
94
+ service_info = full_service_data.declared_metadata
95
+ use_cases = full_service_data.discovered_use_cases
96
+
97
+ # Initialize Flask app
98
+ if app is None:
99
+ app = Flask(service_info.name)
100
+
101
+ # Configure security
102
+ if secret_key is not None:
103
+ app.config["SECRET_KEY"] = secret_key
104
+ if jwt_secret_key is not None:
105
+ app.config["JWT_SECRET_KEY"] = jwt_secret_key
106
+
107
+ # Register each use case to the appropriate processor
108
+ for use_case_keyname in service_info.use_cases:
109
+ use_case_info: UseCaseInfo = service_info.use_cases[use_case_keyname]
110
+ use_case_callable: Callable = use_cases[use_case_keyname]
111
+
112
+ for trigger in use_case_info.triggers:
113
+ if isinstance(trigger.options, TriggerHttp):
114
+ self._http_processor(
115
+ app, use_case_info, trigger, use_case_callable, **kwargs)
116
+ if isinstance(trigger.options, TriggerWebsocket):
117
+ self._websocket_processor(
118
+ app, use_case_info, trigger, use_case_callable, **kwargs)
119
+
120
+ return app
121
+
122
+
123
+ BisslogFlask = InitFlaskAppManager(BisslogFlaskHttpResolver(), BisslogFlaskWebSocketResolver())
File without changes
@@ -0,0 +1,106 @@
1
+ """
2
+ Helper class for sending notifications through WebSocket using Flask-SocketIO.
3
+
4
+ This module provides a concrete implementation of the `WebSocketManager` interface,
5
+ allowing you to send events, manage rooms, and communicate with WebSocket clients
6
+ via Flask-SocketIO.
7
+ """
8
+
9
+ from typing import Any
10
+
11
+ from bisslog.ports.ws_manager import WebSocketManager
12
+
13
+
14
+ class BisslogFlaskSocketHelper(WebSocketManager):
15
+ """
16
+ Flask-SocketIO implementation of the WebSocketManager interface.
17
+
18
+ This class adapts Flask-SocketIO's functionality to the `bisslog` WebSocket contract,
19
+ allowing event emission, room management, and direct message delivery using
20
+ a consistent interface.
21
+ """
22
+
23
+ def __init__(self, conn) -> None:
24
+ super().__init__(conn)
25
+
26
+ def emit(self, event: str, connection_id: str, payload: Any,
27
+ broadcast: bool = False, to: str = None):
28
+ """
29
+ Emit an event to a specific connection or to a room.
30
+
31
+ Parameters
32
+ ----------
33
+ event : str
34
+ Name of the event to emit.
35
+ connection_id : str
36
+ SocketIO session ID of the client.
37
+ payload : Any
38
+ Data to send.
39
+ broadcast : bool, optional
40
+ Whether to broadcast to all clients (default: False).
41
+ to : str, optional
42
+ Target room (if broadcasting).
43
+ """
44
+ self.conn.emit(
45
+ event,
46
+ payload,
47
+ to=to or connection_id,
48
+ broadcast=broadcast
49
+ )
50
+
51
+ def join_room(self, room: str, connection_id: str):
52
+ """
53
+ Add a connection to a room.
54
+
55
+ Parameters
56
+ ----------
57
+ room : str
58
+ Name of the room.
59
+ connection_id : str
60
+ Session ID of the connection to join the room.
61
+ """
62
+ self.conn.server.enter_room(connection_id, room)
63
+
64
+ def leave_room(self, room: str, connection_id: str):
65
+ """
66
+ Remove a connection from a room.
67
+
68
+ Parameters
69
+ ----------
70
+ room : str
71
+ Name of the room.
72
+ connection_id : str
73
+ Session ID of the connection to leave the room.
74
+ """
75
+ self.conn.server.leave_room(connection_id, room)
76
+
77
+ def rooms(self, connection_id: str):
78
+ """
79
+ Get a list of rooms the connection is part of.
80
+
81
+ Parameters
82
+ ----------
83
+ connection_id : str
84
+ Session ID of the client.
85
+
86
+ Returns
87
+ -------
88
+ list[str]
89
+ List of room names.
90
+ """
91
+ return list(self.conn.server.rooms(connection_id))
92
+
93
+ def send(self, event: str, payload: Any = None, connection_id: str = None):
94
+ """
95
+ Send a message with or without an event name.
96
+
97
+ Parameters
98
+ ----------
99
+ event : str
100
+ Event name or message label.
101
+ payload : Any, optional
102
+ Payload to send.
103
+ connection_id : str, optional
104
+ Target client (if None, broadcast).
105
+ """
106
+ self.conn.send(payload or event, to=connection_id)
@@ -0,0 +1,141 @@
1
+ Metadata-Version: 2.4
2
+ Name: bisslog_flask
3
+ Version: 0.0.1
4
+ Summary: It is an extension of the bisslog library to support processes with flask
5
+ Author-email: Darwin Stiven Herrera Cartagena <darwinsherrerac@gmail.com>
6
+ Project-URL: Homepage, https://github.com/darwinhc/bisslog-flask
7
+ Keywords: hexagonal,adapters,bisslog,flask
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.7
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: bisslog>=0.0.7
14
+ Requires-Dist: bisslog-schema>=0.0.3
15
+ Requires-Dist: flask
16
+ Provides-Extra: websocket
17
+ Requires-Dist: flask-socketio; extra == "websocket"
18
+ Provides-Extra: cors
19
+ Requires-Dist: flask-cors>=6.0.0; extra == "cors"
20
+ Dynamic: license-file
21
+
22
+
23
+ # bisslog-flask
24
+
25
+ [![PyPI](https://img.shields.io/pypi/v/bisslog-flask)](https://pypi.org/project/bisslog-flask/)
26
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
27
+
28
+ **bisslog-flask** is an extension of the bisslog library to support processes with Flask. It enables dynamic HTTP and WebSocket route registration from use case metadata, allowing developers to build clean, modular, and metadata-driven APIs with minimal boilerplate.
29
+
30
+ Part of the bisslog ecosystem, it is designed to work seamlessly with domain-centric architectures like Hexagonal or Clean Architecture.
31
+
32
+ ## Features
33
+
34
+ - ๐Ÿ” Dynamic route registration for HTTP and WebSocket triggers
35
+
36
+ - ๐Ÿง  Metadata-driven setup โ€“ use YAML or JSON to declare your use cases
37
+
38
+ - ๐Ÿ”’ Automatic CORS per endpoint using flask-cors
39
+
40
+ - ๐Ÿ”Œ Extensible resolver pattern โ€“ plug in your own processor
41
+
42
+ - โš™๏ธ Mapper integration โ€“ maps HTTP request parts to domain function arguments
43
+
44
+
45
+
46
+ ## ๐Ÿ“ฆ Installation
47
+
48
+ ~~~shell
49
+ pip install bisslog-flask
50
+ ~~~
51
+
52
+
53
+
54
+
55
+ ## ๐Ÿš€ Quickstart
56
+
57
+ ### Programmatically
58
+
59
+ if you want to configure the app before bisslog touches it
60
+ ~~~python
61
+ from flask import Flask
62
+ from bisslog_flask import BisslogFlask
63
+
64
+ app = Flask(__name__)
65
+ BisslogFlask(
66
+ metadata_file="metadata.yml",
67
+ use_cases_folder_path="src/domain/use_cases",
68
+ app=app
69
+ )
70
+
71
+ if __name__ == "__main__":
72
+ app.run(debug=True)
73
+ ~~~
74
+
75
+ or
76
+
77
+ ~~~python
78
+ from bisslog_flask import BisslogFlask
79
+
80
+ app = BisslogFlask(
81
+ metadata_file="metadata.yml",
82
+ use_cases_folder_path="src/domain/use_cases"
83
+ )
84
+
85
+ if __name__ == "__main__":
86
+ app.run(debug=True)
87
+ ~~~
88
+
89
+
90
+
91
+ ## ๐Ÿ”ง How It Works
92
+
93
+ 1. Loads metadata and discovers use case functions (or callables), then uses resolvers to register routes dynamically into a Flask app.
94
+
95
+
96
+ ## ๐Ÿ” CORS Handling
97
+
98
+ CORS is applied only when allow_cors: true is specified in the trigger
99
+
100
+ Fully dynamic: works even with dynamic Flask routes like /users/<id>
101
+
102
+ Powered by `@cross_origin` from `flask-cors`
103
+
104
+
105
+ ## โœ… Requirements
106
+
107
+ Python โ‰ฅ 3.7
108
+
109
+ Flask โ‰ฅ 2.0
110
+
111
+ bisslog-schema โ‰ฅ 0.0.3
112
+
113
+ flask-cors
114
+
115
+ (Optional) flask-socketio if using WebSocket triggers
116
+
117
+
118
+ ## ๐Ÿงช Testing Tip
119
+
120
+ You can test the generated Flask app directly with `app.test_client()` if you take the programmatic way:
121
+
122
+ ```python
123
+ from bisslog_flask import BisslogFlask
124
+
125
+ def test_user_create():
126
+ app = BisslogFlask(metadata_file="metadata.yml", use_cases_folder_path="src/use_cases")
127
+ client = app.test_client()
128
+ response = client.post("/user", json={"name": "Ana", "email": "ana@example.com"})
129
+ assert response.status_code == 200
130
+ ```
131
+
132
+ Not generating code or using the programmatic way you just need to test your use cases.
133
+
134
+
135
+
136
+ ## ๐Ÿ“œ License
137
+
138
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
139
+
140
+
141
+
@@ -0,0 +1,13 @@
1
+ bisslog_flask/__init__.py,sha256=BEf_UxFtcMfaM-Smh_bwc6Xn8pR8LcEjby3nCs0hdXE,758
2
+ bisslog_flask/initializer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ bisslog_flask/initializer/bisslog_flask_http_resolver.py,sha256=d-KFQwMXeRyq3_Cu5bxCF7CpnetfnKainChEbdxDk2c,6257
4
+ bisslog_flask/initializer/bisslog_flask_resolver.py,sha256=QWjft6HZbBplbP1vVMNoPhGoSZBJubAotwLR76HVttw,1708
5
+ bisslog_flask/initializer/bisslog_flask_ws_resolver.py,sha256=s-eDdk5HA6E_D8iZC6IN7RSW-96mzu8m8VGL3Xqm9PQ,2974
6
+ bisslog_flask/initializer/init_flask_app_manager.py,sha256=QzO1dae3YFap2VEXK3gSexLkdfBGaLWrHK732z5s0K0,4682
7
+ bisslog_flask/socket_helper/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ bisslog_flask/socket_helper/socket_helper.py,sha256=sR9xQSPWzijhPNRh8WRxDbzE7rqFqm4w0Vql4gBGiGU,3037
9
+ bisslog_flask-0.0.1.dist-info/licenses/LICENSE,sha256=TSlM1hRIXc6yR3xpGzy2DMSSbds0svqHSetfNfQqCEk,1074
10
+ bisslog_flask-0.0.1.dist-info/METADATA,sha256=w82no5oSrRtS7XEDT38gs6UYIrzyuBHK4eEJkpQptH0,3551
11
+ bisslog_flask-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
+ bisslog_flask-0.0.1.dist-info/top_level.txt,sha256=Xk85d0SIhkUP1HjsXOtq2vlU7yQT3mFApyb5IVgtG6w,14
13
+ bisslog_flask-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Darwin Herrera C.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ bisslog_flask