@onlineapps/service-wrapper 2.0.8 → 2.0.9

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.
package/README.md CHANGED
@@ -1,8 +1,10 @@
1
1
  # @onlineapps/service-wrapper
2
2
 
3
- **Main orchestration package for microservices - NO prefix as it's the primary integration point**
3
+ **Collection of connectors providing all infrastructure components for business services**
4
4
 
5
- Infrastructure wrapper that handles all workflow processing, message queue operations, and service registration for microservices.
5
+ Service Wrapper is a set of reusable connector components that handle message queue operations, service registration, monitoring, and health checks for microservices in a single-process architecture.
6
+
7
+ > **For complete architecture documentation, see [docs/FINAL_ARCHITECTURE.md](./docs/FINAL_ARCHITECTURE.md)**
6
8
 
7
9
  ## Naming Convention
8
10
 
@@ -41,32 +43,43 @@ This package provides the infrastructure layer that sits between:
41
43
 
42
44
  ## Usage
43
45
 
44
- ### 1. Wrap Your Service
46
+ ### 1. Install Service Wrapper
47
+
48
+ ```bash
49
+ npm install @onlineapps/service-wrapper
50
+ ```
51
+
52
+ ### 2. Create Service Entry Point
45
53
 
46
54
  ```javascript
47
- const ServiceWrapper = require('@onlineapps/service-wrapper');
55
+ // index.js
48
56
  const express = require('express');
57
+ const { ServiceWrapper } = require('@onlineapps/service-wrapper');
49
58
 
50
- // Your pure business logic service
51
- const app = express();
52
- app.get('/hello', (req, res) => {
53
- res.json({ message: `Hello ${req.query.name}` });
54
- });
59
+ // Load your Express app (business logic only)
60
+ const app = require('./src/app');
55
61
 
56
- // Wrap with infrastructure
57
- const wrapper = new ServiceWrapper({
58
- service: app,
59
- serviceName: 'hello-service',
60
- openApiSpec: require('./openapi.json'),
61
- config: {
62
- rabbitmq: process.env.RABBITMQ_URL,
63
- registry: process.env.REGISTRY_URL,
64
- port: process.env.PORT || 3000
65
- }
66
- });
62
+ // Load configuration
63
+ const config = require('./conn-config/config.json');
64
+ const operations = require('./conn-config/operations.json');
65
+
66
+ async function start() {
67
+ // 1. Start Express server
68
+ const server = app.listen(process.env.PORT || 3000);
69
+
70
+ // 2. Initialize wrapper components
71
+ const wrapper = new ServiceWrapper({
72
+ app,
73
+ server,
74
+ config,
75
+ operations
76
+ });
77
+
78
+ await wrapper.initialize();
79
+ console.log('Service ready with all infrastructure components');
80
+ }
67
81
 
68
- // Start wrapped service
69
- wrapper.start();
82
+ start().catch(console.error);
70
83
  ```
71
84
 
72
85
  ### 2. Service Receives
@@ -88,25 +101,37 @@ NO infrastructure code needed in your service!
88
101
 
89
102
  ## Configuration
90
103
 
91
- ```javascript
104
+ ### operations.json
105
+ ```json
92
106
  {
93
- service: expressApp, // Your Express app
94
- serviceName: 'my-service', // Service identifier
95
- openApiSpec: {}, // OpenAPI specification
96
- config: {
97
- rabbitmq: 'amqp://...', // RabbitMQ connection
98
- registry: 'http://...', // Registry URL
99
- redis: 'redis://...', // Redis connection
100
- port: 3000, // Service port
101
- healthPath: '/health', // Health check path
102
- retryPolicy: { // Retry configuration
103
- maxRetries: 3,
104
- backoffMs: 1000
107
+ "operations": {
108
+ "operation-name": {
109
+ "description": "Operation description",
110
+ "endpoint": "/api/operation",
111
+ "method": "POST",
112
+ "input": { "name": { "type": "string", "required": true } },
113
+ "output": { "result": { "type": "string" } }
105
114
  }
106
115
  }
107
116
  }
108
117
  ```
109
118
 
119
+ ### config.json
120
+ ```json
121
+ {
122
+ "service": {
123
+ "name": "my-service",
124
+ "port": 3000
125
+ },
126
+ "wrapper": {
127
+ "mq": { "url": "${RABBITMQ_URL}" },
128
+ "registry": { "url": "${REGISTRY_URL}" },
129
+ "monitoring": { "enabled": true },
130
+ "health": { "endpoint": "/health" }
131
+ }
132
+ }
133
+ ```
134
+
110
135
  ## What This Handles
111
136
 
112
137
  ### Workflow Processing
@@ -144,12 +169,14 @@ Your service should NOT have:
144
169
  ```
145
170
  my-service/
146
171
  ├── src/
147
- │ ├── index.js # Express app (business logic only)
172
+ │ ├── app.js # Express app (business logic only)
148
173
  │ ├── routes/ # API endpoints
149
174
  │ └── services/ # Business logic
150
- ├── connector-config/
151
- └── openapi.json # API specification
152
- └── package.json # Dependencies (no @onlineapps/connector-*)
175
+ ├── conn-config/
176
+ ├── config.json # Service & wrapper configuration
177
+ └── operations.json # Operations specification
178
+ ├── index.js # Main entry point (initializes wrapper)
179
+ └── package.json # Dependencies including @onlineapps/service-wrapper
153
180
  ```
154
181
 
155
182
  ## Testing
@@ -0,0 +1,200 @@
1
+ # Architecture Decision: Service Wrapper vs Business Services
2
+
3
+ > **NOTE: This document describes the evolution of our thinking. For the final decision, see [FINAL_ARCHITECTURE.md](./FINAL_ARCHITECTURE.md)**
4
+
5
+ ## Executive Summary
6
+
7
+ After critical analysis, we've determined that business services should remain as standard Express applications with Service Wrapper acting as a thin MQ-to-HTTP proxy layer.
8
+
9
+ ## Business Service Requirements
10
+
11
+ ### MUST Have:
12
+ 1. **Express HTTP Server** - Full REST API capability
13
+ 2. **Own Database Connections** - Direct ORM/query access
14
+ 3. **Own Dependencies** - Complete node_modules
15
+ 4. **Standalone Operation** - Must run without wrapper
16
+ 5. **Standard Testing** - curl/Postman testable
17
+
18
+ ### Service Structure:
19
+ ```
20
+ /service-name/
21
+ /src/
22
+ app.js # Express application
23
+ /models/ # Database models
24
+ /controllers/ # HTTP controllers
25
+ /services/ # Business logic
26
+ /validators/ # Input validation
27
+ /conn-config/
28
+ operations.json # Operation definitions
29
+ config.json # Service configuration
30
+ package.json # All dependencies
31
+ ```
32
+
33
+ ### Operations Specification:
34
+ ```json
35
+ {
36
+ "operations": {
37
+ "operation-name": {
38
+ "endpoint": "/api/operation",
39
+ "method": "POST",
40
+ "input": { "schema": "..." },
41
+ "output": { "schema": "..." }
42
+ }
43
+ }
44
+ }
45
+ ```
46
+
47
+ ## Service Wrapper Responsibilities
48
+
49
+ ### Core Functions:
50
+ 1. **MQ Listener** - Consumes from RabbitMQ queues
51
+ 2. **HTTP Proxy** - Forwards to service endpoints
52
+ 3. **Service Registry** - Registers with discovery
53
+ 4. **Cookbook Router** - Routes workflow steps
54
+
55
+ ### What Wrapper Does NOT Do:
56
+ - ❌ Create HTTP server for service
57
+ - ❌ Handle business logic
58
+ - ❌ Manage database connections
59
+ - ❌ Validate business rules
60
+ - ❌ Generate responses
61
+
62
+ ### Wrapper Architecture:
63
+ ```javascript
64
+ // wrapper.js
65
+ const ServiceWrapper = require('@onlineapps/service-wrapper');
66
+
67
+ new ServiceWrapper({
68
+ serviceName: 'hello-service',
69
+ serviceUrl: 'http://localhost:3000',
70
+ mqConfig: { /* RabbitMQ settings */ },
71
+ mode: 'proxy' // Just forwards MQ→HTTP
72
+ }).start();
73
+ ```
74
+
75
+ ## Communication Flow
76
+
77
+ ```
78
+ [Cookbook Message]
79
+
80
+ [Service Wrapper]
81
+ ├─ Reads operations.json
82
+ ├─ Maps operation to endpoint
83
+ ├─ Makes HTTP call
84
+
85
+ [Business Service Express]
86
+ ├─ Handles HTTP request
87
+ ├─ Executes business logic
88
+ ├─ Returns HTTP response
89
+
90
+ [Service Wrapper]
91
+ ├─ Transforms response
92
+ └─ Sends to next queue
93
+ ```
94
+
95
+ ## Why This Architecture?
96
+
97
+ ### Separation of Concerns:
98
+ - **Business Service** = Business logic + API
99
+ - **Service Wrapper** = MQ communication only
100
+
101
+ ### Benefits:
102
+ 1. **Independence** - Services run standalone
103
+ 2. **Simplicity** - No complex handler mapping
104
+ 3. **Compatibility** - Works with existing services
105
+ 4. **Testability** - Standard HTTP testing
106
+ 5. **Flexibility** - Can swap wrapper implementations
107
+
108
+ ### Drawbacks Considered:
109
+ - Extra HTTP hop (acceptable for clarity)
110
+ - Two processes (acceptable for isolation)
111
+ - More memory (acceptable for stability)
112
+
113
+ ## Migration Path
114
+
115
+ ### For New Services:
116
+ 1. Build Express API normally
117
+ 2. Add operations.json
118
+ 3. Add wrapper.js for MQ
119
+
120
+ ### For Existing Services:
121
+ 1. Keep service unchanged
122
+ 2. Add operations.json
123
+ 3. Add wrapper.js for MQ
124
+
125
+ ### No Breaking Changes Required!
126
+
127
+ ## Decision Matrix
128
+
129
+ | Aspect | Handlers Approach | Express + Wrapper |
130
+ |--------|------------------|-------------------|
131
+ | Complexity | High | Low |
132
+ | Testing | Complex | Simple |
133
+ | Dependencies | Conflicting | Isolated |
134
+ | Database | Problematic | Natural |
135
+ | Debugging | Hard | Easy |
136
+ | **Winner** | ❌ | ✅ |
137
+
138
+ ## Final Decision
139
+
140
+ **Business services remain as Express applications.**
141
+ **Service Wrapper acts as MQ-to-HTTP proxy only.**
142
+
143
+ This provides:
144
+ - Maximum compatibility
145
+ - Minimum complexity
146
+ - Clear separation
147
+ - Easy migration
148
+
149
+ ## Implementation Guidelines
150
+
151
+ 1. **Every service has:**
152
+ - Express app with REST endpoints
153
+ - operations.json describing operations
154
+ - Optional wrapper.js for MQ integration
155
+
156
+ 2. **Service Wrapper:**
157
+ - Reads operations.json
158
+ - Listens to MQ
159
+ - Calls HTTP endpoints
160
+ - Returns responses to MQ
161
+
162
+ 3. **No direct handler execution**
163
+ - Always through HTTP
164
+ - Clear contract via operations.json
165
+ - Standard REST patterns
166
+
167
+ ## Examples
168
+
169
+ ### Hello Service:
170
+ ```javascript
171
+ // app.js - Standard Express
172
+ app.post('/api/good-day', (req, res) => {
173
+ res.json({ message: `Good day, ${req.body.name}!` });
174
+ });
175
+
176
+ // operations.json - Contract
177
+ {
178
+ "operations": {
179
+ "good-day": {
180
+ "endpoint": "/api/good-day",
181
+ "method": "POST"
182
+ }
183
+ }
184
+ }
185
+
186
+ // wrapper.js - MQ Bridge
187
+ new ServiceWrapper({
188
+ serviceUrl: 'http://localhost:33199'
189
+ }).start();
190
+ ```
191
+
192
+ ### Invoicing Service:
193
+ - Keeps all controllers, models, validators
194
+ - Adds operations.json
195
+ - Adds wrapper.js
196
+ - NO other changes needed
197
+
198
+ ## Conclusion
199
+
200
+ The architecture prioritizes **simplicity and compatibility** over theoretical purity. Services remain standard Express apps, making them easy to develop, test, and maintain. Service Wrapper provides the MQ integration layer without disrupting the service internals.
@@ -0,0 +1,271 @@
1
+ # Service Wrapper - Final Architecture Decision
2
+
3
+ ## Executive Summary
4
+
5
+ Service Wrapper is a **collection of connectors** that provides all infrastructure components necessary for business services to function within the OA Drive system. It operates as a **single process architecture** where wrapper components run embedded within the service process.
6
+
7
+ ## Core Principles
8
+
9
+ 1. **Component Collection** - Service Wrapper is NOT a framework but a set of reusable connector components
10
+ 2. **Single Process** - All components run in the same process as the business service
11
+ 3. **Express + HTTP** - Business services remain standard Express applications
12
+ 4. **MQ-to-HTTP Proxy** - Wrapper listens on RabbitMQ and makes local HTTP calls
13
+ 5. **Zero Infrastructure in Services** - Services contain ONLY business logic
14
+
15
+ ## Architecture Decision
16
+
17
+ ### Why HTTP Pattern Over Handler Pattern
18
+
19
+ Despite handler pattern being **3.4x faster** (2.1ms vs 7.1ms) and using **67% less memory** (60MB vs 100MB), we chose the HTTP pattern because:
20
+
21
+ #### Handler Pattern Fatal Issues ❌
22
+ - **Node modules conflicts** - Service needs mongoose 5.x, wrapper needs 6.x = CONFLICT
23
+ - **Database connections broken** - Can't maintain connection pools
24
+ - **Third-party integration failures** - AWS SDK version conflicts
25
+ - **Testing becomes impossible** - Can't test service independently
26
+
27
+ #### HTTP Pattern Benefits ✅
28
+ - **100% compatibility** - All existing services work unchanged
29
+ - **Standard patterns** - All Express tooling works
30
+ - **Full functionality** - Databases, third-party services all work
31
+ - **Simple testing** - Service can run standalone
32
+ - **Acceptable overhead** - 5ms per request is negligible
33
+
34
+ ### Verdict
35
+ For typical service with 100 req/s:
36
+ - Performance difference: 500ms spread across 100 requests = **5ms per request**
37
+ - **5ms overhead is acceptable price for working solution!**
38
+
39
+ ## Implementation Architecture
40
+
41
+ ### Service Structure
42
+
43
+ ```
44
+ hello-service/
45
+ ├── src/
46
+ │ ├── app.js # Express app - business logic only
47
+ │ ├── routes/ # Business endpoints
48
+ │ └── handlers/ # Business logic
49
+ ├── conn-config/ # Wrapper configuration
50
+ │ ├── config.json # Service & wrapper config
51
+ │ └── operations.json # Operation to endpoint mapping
52
+ ├── index.js # Main entry point (initializes wrapper)
53
+ ├── package.json # Dependencies including @onlineapps/service-wrapper
54
+ └── .env # Environment variables
55
+ ```
56
+
57
+ ### Runtime Flow
58
+
59
+ ```javascript
60
+ // index.js - Service entry point
61
+ const express = require('express');
62
+ const { ServiceWrapper } = require('@onlineapps/service-wrapper');
63
+ const app = require('./src/app');
64
+
65
+ async function start() {
66
+ // 1. Start Express server
67
+ const server = app.listen(PORT);
68
+
69
+ // 2. Initialize wrapper components
70
+ const wrapper = new ServiceWrapper({
71
+ app,
72
+ server,
73
+ config: require('./conn-config/config.json'),
74
+ operations: require('./conn-config/operations.json')
75
+ });
76
+
77
+ await wrapper.initialize();
78
+ // Service now has all infrastructure components!
79
+ }
80
+ ```
81
+
82
+ ### Message Processing
83
+
84
+ #### HTTP Request Flow
85
+ ```
86
+ Client → HTTP → Express Router → Handler → Response
87
+
88
+ MonitoringConnector (metrics)
89
+ ```
90
+
91
+ #### MQ Message Flow
92
+ ```
93
+ RabbitMQ → MQConnector → Parse operations.json → HTTP localhost:3000/api/endpoint
94
+
95
+ Express Router → Handler
96
+
97
+ Response → MQ
98
+ ```
99
+
100
+ ## Component Architecture
101
+
102
+ ### Service Wrapper Components
103
+
104
+ 1. **MQConnector** - RabbitMQ integration
105
+ - Listens on `workflow.init` queue
106
+ - Listens on `{service-name}.workflow` queue
107
+ - Routes messages based on operations.json
108
+
109
+ 2. **MonitoringConnector** - Metrics collection
110
+ - Request tracking
111
+ - Performance metrics
112
+ - Error rates
113
+
114
+ 3. **HealthConnector** - Health checks
115
+ - Provides `/health` endpoint
116
+ - Aggregates component status
117
+ - Custom health check support
118
+
119
+ 4. **RegistryConnector** - Service discovery
120
+ - Registers service on startup
121
+ - Sends heartbeat
122
+ - Updates capabilities
123
+
124
+ ## Operations Schema
125
+
126
+ Replaces OpenAPI with simpler format optimized for workflow processing:
127
+
128
+ ```json
129
+ {
130
+ "operations": {
131
+ "operation-name": {
132
+ "description": "Human-readable description",
133
+ "endpoint": "/api/operation-name",
134
+ "method": "POST",
135
+ "input": {
136
+ "field1": { "type": "string", "required": true }
137
+ },
138
+ "output": {
139
+ "result": { "type": "string" }
140
+ }
141
+ }
142
+ }
143
+ }
144
+ ```
145
+
146
+ ## Benefits of This Architecture
147
+
148
+ ### For Development
149
+ - **Zero infrastructure code** in services
150
+ - **Standard Express patterns** work
151
+ - **Simple debugging** - one process, one log stream
152
+ - **Easy testing** - service runs standalone
153
+
154
+ ### For Operations
155
+ - **Simple deployment** - one process per service
156
+ - **Central management** - update wrapper version for all
157
+ - **Graceful shutdown** - wrapper handles cleanup
158
+ - **No message loss** - RabbitMQ persistent queues
159
+
160
+ ### For Performance
161
+ - **5ms overhead** - acceptable for real-world use
162
+ - **Efficient resource usage** - shared memory in single process
163
+ - **Connection pooling** - wrapper manages MQ connections
164
+ - **Horizontal scaling** - just add more service instances
165
+
166
+ ## What Services DON'T Handle
167
+
168
+ - ❌ RabbitMQ connection management
169
+ - ❌ Queue subscription logic
170
+ - ❌ Message parsing and validation
171
+ - ❌ Service discovery registration
172
+ - ❌ Health check implementation
173
+ - ❌ Monitoring middleware
174
+ - ❌ Retry and error handling
175
+
176
+ **All handled by Service Wrapper components!**
177
+
178
+ ## Migration Strategy
179
+
180
+ ### For New Services
181
+ 1. Create Express app with business logic
182
+ 2. Add `conn-config/operations.json`
183
+ 3. Add Service Wrapper dependency
184
+ 4. Create `index.js` entry point
185
+ 5. Deploy
186
+
187
+ ### For Existing Services
188
+ 1. Keep all existing code unchanged
189
+ 2. Add configuration files
190
+ 3. Wrap with Service Wrapper
191
+ 4. Remove infrastructure code
192
+ 5. Deploy - no breaking changes!
193
+
194
+ ## Configuration
195
+
196
+ ### Service Configuration (conn-config/config.json)
197
+ ```json
198
+ {
199
+ "service": {
200
+ "name": "hello-service",
201
+ "version": "1.0.0",
202
+ "port": 3000
203
+ },
204
+ "wrapper": {
205
+ "mq": {
206
+ "url": "${RABBITMQ_URL}",
207
+ "prefetch": 10
208
+ },
209
+ "monitoring": {
210
+ "enabled": true
211
+ },
212
+ "health": {
213
+ "endpoint": "/health"
214
+ },
215
+ "registry": {
216
+ "url": "${REGISTRY_URL}"
217
+ }
218
+ }
219
+ }
220
+ ```
221
+
222
+ ## Testing Strategy
223
+
224
+ ### Unit Tests (without wrapper)
225
+ ```javascript
226
+ const app = require('./src/app');
227
+ const request = require('supertest');
228
+
229
+ test('business logic', async () => {
230
+ const res = await request(app).post('/api/operation');
231
+ expect(res.status).toBe(200);
232
+ });
233
+ ```
234
+
235
+ ### Integration Tests (with wrapper)
236
+ ```javascript
237
+ const { start } = require('./index');
238
+
239
+ beforeAll(async () => {
240
+ await start();
241
+ });
242
+
243
+ test('full service', async () => {
244
+ // Test with all infrastructure
245
+ });
246
+ ```
247
+
248
+ ## Performance Characteristics
249
+
250
+ | Metric | Value | Acceptable? |
251
+ |--------|-------|-------------|
252
+ | Added latency | 5ms per request | ✅ Yes |
253
+ | Memory overhead | 40MB per service | ✅ Yes |
254
+ | CPU overhead | 4% per 1000 req/s | ✅ Yes |
255
+ | Startup time | +2 seconds | ✅ Yes |
256
+
257
+ ## Conclusion
258
+
259
+ This architecture provides the **optimal balance** between:
260
+ - **Simplicity** - Single process, standard patterns
261
+ - **Compatibility** - Works with all existing services
262
+ - **Performance** - Acceptable overhead for massive benefits
263
+ - **Maintainability** - Central management, no duplication
264
+
265
+ The 5ms latency overhead is a **small price** for:
266
+ - 100% compatibility
267
+ - Zero infrastructure code in services
268
+ - Central management of all components
269
+ - Full functionality including databases
270
+
271
+ **This is the final, production-ready architecture for Service Wrapper.**