@onlineapps/service-wrapper 2.0.7 → 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 +76 -38
- package/docs/API_STRUCTURE_STANDARD.md +132 -0
- package/docs/ARCHITECTURE_DECISION.md +200 -0
- package/docs/CONFIGURATION_GUIDE.md +261 -0
- package/docs/FINAL_ARCHITECTURE.md +271 -0
- package/docs/HANDLER_VS_HTTP_COMPARISON.md +269 -0
- package/docs/INSTALLATION_GUIDE.md +353 -0
- package/docs/OPERATIONS_SCHEMA.md +405 -0
- package/docs/SERVICE_TESTING_STANDARD.md +389 -0
- package/docs/WRAPPER_ARCHITECTURE.md +218 -0
- package/onlineapps-service-wrapper-2.0.8.tgz +0 -0
- package/package.json +4 -3
- package/src/ServiceWrapper.js +433 -270
- package/test/monitoring-integration.test.js +150 -0
package/README.md
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
# @onlineapps/service-wrapper
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Collection of connectors providing all infrastructure components for business services**
|
|
4
|
+
|
|
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)**
|
|
8
|
+
|
|
9
|
+
## Naming Convention
|
|
10
|
+
|
|
11
|
+
This package uses `@onlineapps/service-wrapper` WITHOUT any connector prefix because:
|
|
12
|
+
- It's the main orchestration layer, not a specific connector
|
|
13
|
+
- All services depend on it directly
|
|
14
|
+
- It aggregates all other connectors (base, infra, orch)
|
|
15
|
+
|
|
16
|
+
Directory: `/shared/connector/conn-app-service-wrapper/` (historical, kept for backward compatibility)
|
|
4
17
|
|
|
5
18
|
## Purpose
|
|
6
19
|
|
|
@@ -30,32 +43,43 @@ This package provides the infrastructure layer that sits between:
|
|
|
30
43
|
|
|
31
44
|
## Usage
|
|
32
45
|
|
|
33
|
-
### 1.
|
|
46
|
+
### 1. Install Service Wrapper
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install @onlineapps/service-wrapper
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 2. Create Service Entry Point
|
|
34
53
|
|
|
35
54
|
```javascript
|
|
36
|
-
|
|
55
|
+
// index.js
|
|
37
56
|
const express = require('express');
|
|
57
|
+
const { ServiceWrapper } = require('@onlineapps/service-wrapper');
|
|
38
58
|
|
|
39
|
-
//
|
|
40
|
-
const app =
|
|
41
|
-
app.get('/hello', (req, res) => {
|
|
42
|
-
res.json({ message: `Hello ${req.query.name}` });
|
|
43
|
-
});
|
|
59
|
+
// Load your Express app (business logic only)
|
|
60
|
+
const app = require('./src/app');
|
|
44
61
|
|
|
45
|
-
//
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
serviceName: 'hello-service',
|
|
49
|
-
openApiSpec: require('./openapi.json'),
|
|
50
|
-
config: {
|
|
51
|
-
rabbitmq: process.env.RABBITMQ_URL,
|
|
52
|
-
registry: process.env.REGISTRY_URL,
|
|
53
|
-
port: process.env.PORT || 3000
|
|
54
|
-
}
|
|
55
|
-
});
|
|
62
|
+
// Load configuration
|
|
63
|
+
const config = require('./conn-config/config.json');
|
|
64
|
+
const operations = require('./conn-config/operations.json');
|
|
56
65
|
|
|
57
|
-
|
|
58
|
-
|
|
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
|
+
}
|
|
81
|
+
|
|
82
|
+
start().catch(console.error);
|
|
59
83
|
```
|
|
60
84
|
|
|
61
85
|
### 2. Service Receives
|
|
@@ -77,25 +101,37 @@ NO infrastructure code needed in your service!
|
|
|
77
101
|
|
|
78
102
|
## Configuration
|
|
79
103
|
|
|
80
|
-
|
|
104
|
+
### operations.json
|
|
105
|
+
```json
|
|
81
106
|
{
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
port: 3000, // Service port
|
|
90
|
-
healthPath: '/health', // Health check path
|
|
91
|
-
retryPolicy: { // Retry configuration
|
|
92
|
-
maxRetries: 3,
|
|
93
|
-
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" } }
|
|
94
114
|
}
|
|
95
115
|
}
|
|
96
116
|
}
|
|
97
117
|
```
|
|
98
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
|
+
|
|
99
135
|
## What This Handles
|
|
100
136
|
|
|
101
137
|
### Workflow Processing
|
|
@@ -133,12 +169,14 @@ Your service should NOT have:
|
|
|
133
169
|
```
|
|
134
170
|
my-service/
|
|
135
171
|
├── src/
|
|
136
|
-
│ ├──
|
|
172
|
+
│ ├── app.js # Express app (business logic only)
|
|
137
173
|
│ ├── routes/ # API endpoints
|
|
138
174
|
│ └── services/ # Business logic
|
|
139
|
-
├──
|
|
140
|
-
│
|
|
141
|
-
└──
|
|
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
|
|
142
180
|
```
|
|
143
181
|
|
|
144
182
|
## Testing
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# API Structure Standard for Microservices
|
|
2
|
+
|
|
3
|
+
## Endpoint Structure
|
|
4
|
+
|
|
5
|
+
All microservices follow a simple, unversioned API structure.
|
|
6
|
+
|
|
7
|
+
### URL Pattern
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
/ # Service discovery
|
|
11
|
+
/health # Health check
|
|
12
|
+
/status # Service status
|
|
13
|
+
/metrics # Prometheus metrics
|
|
14
|
+
/specification # Operations specification
|
|
15
|
+
/api/{operation} # Business operations
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Endpoint Categories
|
|
19
|
+
|
|
20
|
+
- **System endpoints**: Health, status, metrics, specification
|
|
21
|
+
- **Business endpoints** (`/api/*`): Application-specific operations
|
|
22
|
+
|
|
23
|
+
## Standard Endpoints
|
|
24
|
+
|
|
25
|
+
### Discovery Endpoint
|
|
26
|
+
|
|
27
|
+
**GET /**
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"service": "service-name",
|
|
31
|
+
"version": "1.0.0",
|
|
32
|
+
"description": "Service description",
|
|
33
|
+
"specification": "/specification",
|
|
34
|
+
"health": "/health",
|
|
35
|
+
"status": "/status"
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### System Endpoints
|
|
40
|
+
|
|
41
|
+
| Endpoint | Purpose | Response |
|
|
42
|
+
|----------|---------|----------|
|
|
43
|
+
| `GET /health` | Basic health check | `{"status": "healthy", "timestamp": "..."}` |
|
|
44
|
+
| `GET /status` | Detailed service status | Service metrics and dependencies |
|
|
45
|
+
| `GET /specification` | Operations specification | Operations JSON schema |
|
|
46
|
+
| `GET /metrics` | Prometheus metrics | Metrics in Prometheus format |
|
|
47
|
+
|
|
48
|
+
### Business Endpoints
|
|
49
|
+
|
|
50
|
+
Service-specific operations under `/api/*`:
|
|
51
|
+
- `POST /api/create-user`
|
|
52
|
+
- `POST /api/process-order`
|
|
53
|
+
- `GET /api/get-product`
|
|
54
|
+
|
|
55
|
+
## Implementation Guide
|
|
56
|
+
|
|
57
|
+
### Express.js Structure
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
const express = require('express');
|
|
61
|
+
const app = express();
|
|
62
|
+
|
|
63
|
+
// Root endpoint - service discovery
|
|
64
|
+
app.get('/', (req, res) => {
|
|
65
|
+
res.json({
|
|
66
|
+
service: process.env.SERVICE_NAME,
|
|
67
|
+
version: require('./package.json').version,
|
|
68
|
+
specification: '/specification',
|
|
69
|
+
health: '/health',
|
|
70
|
+
status: '/status'
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// System endpoints
|
|
75
|
+
app.get('/health', healthHandler);
|
|
76
|
+
app.get('/status', statusHandler);
|
|
77
|
+
app.get('/specification', specificationHandler);
|
|
78
|
+
app.get('/metrics', metricsHandler);
|
|
79
|
+
|
|
80
|
+
// Business endpoints under /api
|
|
81
|
+
app.post('/api/create-user', createUserHandler);
|
|
82
|
+
app.post('/api/process-order', processOrderHandler);
|
|
83
|
+
app.get('/api/get-product', getProductHandler);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Configuration Structure
|
|
87
|
+
|
|
88
|
+
All service configurations are stored in `conn-config/` directory:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
/your-service
|
|
92
|
+
/conn-config
|
|
93
|
+
/config.json # Main configuration
|
|
94
|
+
/operations.json # Operations specification
|
|
95
|
+
/middleware.json # Middleware configuration
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
See [Configuration Guide](./CONFIGURATION_GUIDE.md) for details.
|
|
99
|
+
|
|
100
|
+
## Migration Guide
|
|
101
|
+
|
|
102
|
+
### From OpenAPI to Operations
|
|
103
|
+
|
|
104
|
+
| Old | New | Purpose |
|
|
105
|
+
|-----|-----|------|
|
|
106
|
+
| `/api/v1/specification` | `/specification` | Operations schema |
|
|
107
|
+
| `/v1/system/health` | `/health` | Health check |
|
|
108
|
+
| `/v1/system/status` | `/status` | Service status |
|
|
109
|
+
| `/v1/{operation}` | `/api/{operation}` | Business operations |
|
|
110
|
+
|
|
111
|
+
### Simple Migration Steps
|
|
112
|
+
|
|
113
|
+
1. Create `operations.json` from OpenAPI
|
|
114
|
+
2. Remove version prefixes from endpoints
|
|
115
|
+
3. Move business endpoints under `/api`
|
|
116
|
+
4. Update service discovery response
|
|
117
|
+
|
|
118
|
+
## Testing Requirements
|
|
119
|
+
|
|
120
|
+
Tests must verify:
|
|
121
|
+
|
|
122
|
+
1. **Discovery endpoint** returns service info and specification link
|
|
123
|
+
2. **System endpoints** work correctly
|
|
124
|
+
3. **Business endpoints** under `/api` process operations
|
|
125
|
+
4. **Operations schema** is valid and complete
|
|
126
|
+
|
|
127
|
+
## Benefits
|
|
128
|
+
|
|
129
|
+
1. **Simplicity** - No version complexity
|
|
130
|
+
2. **Clear structure** - System vs business separation
|
|
131
|
+
3. **Direct mapping** - Operations to Cookbook steps
|
|
132
|
+
4. **Lightweight** - Minimal configuration needed
|
|
@@ -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.
|