@onlineapps/conn-orch-api-mapper 1.0.0 → 1.0.2
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/API.md +0 -0
- package/README.md +262 -0
- package/coverage/clover.xml +0 -0
- package/coverage/coverage-final.json +0 -0
- package/coverage/lcov-report/ApiMapper.js.html +0 -0
- package/coverage/lcov-report/base.css +0 -0
- package/coverage/lcov-report/block-navigation.js +0 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -0
- package/coverage/lcov-report/index.js.html +0 -0
- package/coverage/lcov-report/prettify.css +0 -0
- package/coverage/lcov-report/prettify.js +0 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -0
- package/coverage/lcov.info +0 -0
- package/onlineapps-conn-orch-api-mapper-1.0.0.tgz +0 -0
- package/package.json +1 -2
- package/src/ApiMapper.js +68 -22
- package/src/index.js +0 -0
- package/{test → tests}/component/api-mapping-flow.test.js +1 -1
- package/{test → tests}/unit/ApiMapper.unit.test.js +1 -1
package/API.md
CHANGED
|
File without changes
|
package/README.md
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# @onlineapps/conn-orch-api-mapper
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
Maps cookbook operations to HTTP API endpoints. Bridges the gap between MQ-based workflow steps and RESTful service APIs.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
```bash
|
|
8
|
+
npm install @onlineapps/conn-orch-api-mapper
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
- Operation to endpoint mapping
|
|
13
|
+
- Parameter transformation
|
|
14
|
+
- Response mapping
|
|
15
|
+
- Header injection
|
|
16
|
+
- Service discovery integration
|
|
17
|
+
- OpenAPI schema support
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Basic Setup
|
|
22
|
+
```javascript
|
|
23
|
+
const { ApiMapper } = require('@onlineapps/conn-orch-api-mapper');
|
|
24
|
+
|
|
25
|
+
const mapper = new ApiMapper({
|
|
26
|
+
registryUrl: 'http://api_services_registry:33100',
|
|
27
|
+
cacheEnabled: true,
|
|
28
|
+
cacheTTL: 300
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Initialize mapper
|
|
32
|
+
await mapper.initialize();
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Operation Mapping
|
|
36
|
+
```javascript
|
|
37
|
+
// Map cookbook operation to HTTP request
|
|
38
|
+
const httpRequest = await mapper.mapOperation({
|
|
39
|
+
service: 'hello-service',
|
|
40
|
+
operation: 'greet',
|
|
41
|
+
params: {
|
|
42
|
+
name: 'World',
|
|
43
|
+
language: 'en'
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Returns:
|
|
48
|
+
{
|
|
49
|
+
method: 'POST',
|
|
50
|
+
url: 'http://hello-service:33199/api/greet',
|
|
51
|
+
headers: {
|
|
52
|
+
'Content-Type': 'application/json',
|
|
53
|
+
'X-Workflow-Id': 'wf-uuid'
|
|
54
|
+
},
|
|
55
|
+
body: {
|
|
56
|
+
name: 'World',
|
|
57
|
+
language: 'en'
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Response Mapping
|
|
63
|
+
```javascript
|
|
64
|
+
// Map HTTP response back to workflow format
|
|
65
|
+
const workflowResult = mapper.mapResponse({
|
|
66
|
+
status: 200,
|
|
67
|
+
headers: { 'content-type': 'application/json' },
|
|
68
|
+
body: { greeting: 'Hello World' }
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Returns:
|
|
72
|
+
{
|
|
73
|
+
success: true,
|
|
74
|
+
data: { greeting: 'Hello World' },
|
|
75
|
+
metadata: {
|
|
76
|
+
httpStatus: 200,
|
|
77
|
+
processingTime: 45
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Configuration
|
|
83
|
+
|
|
84
|
+
### Options
|
|
85
|
+
```javascript
|
|
86
|
+
{
|
|
87
|
+
registryUrl: 'http://registry:33100', // Registry service URL
|
|
88
|
+
cacheEnabled: true, // Cache service mappings
|
|
89
|
+
cacheTTL: 300, // Cache TTL in seconds
|
|
90
|
+
timeout: 5000, // HTTP request timeout
|
|
91
|
+
retries: 3, // Retry attempts
|
|
92
|
+
validateSchema: true // Validate against OpenAPI
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Environment Variables
|
|
97
|
+
```bash
|
|
98
|
+
REGISTRY_URL=http://api_services_registry:33100
|
|
99
|
+
API_MAPPER_CACHE_ENABLED=true
|
|
100
|
+
API_MAPPER_CACHE_TTL=300
|
|
101
|
+
API_MAPPER_TIMEOUT=5000
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Mapping Rules
|
|
105
|
+
|
|
106
|
+
### Default Mapping
|
|
107
|
+
```javascript
|
|
108
|
+
// Cookbook operation
|
|
109
|
+
{ service: 'service-name', operation: 'operation-name' }
|
|
110
|
+
|
|
111
|
+
// Maps to HTTP
|
|
112
|
+
POST /api/operation-name
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Custom Mappings
|
|
116
|
+
```javascript
|
|
117
|
+
// Define custom mappings
|
|
118
|
+
mapper.addMapping('hello-service', {
|
|
119
|
+
greet: {
|
|
120
|
+
method: 'POST',
|
|
121
|
+
path: '/api/greet',
|
|
122
|
+
paramMapping: {
|
|
123
|
+
name: 'body.name',
|
|
124
|
+
lang: 'query.language'
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
status: {
|
|
128
|
+
method: 'GET',
|
|
129
|
+
path: '/health'
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Service Discovery
|
|
135
|
+
|
|
136
|
+
The mapper integrates with the service registry:
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
// Auto-discover service endpoints
|
|
140
|
+
const endpoint = await mapper.discoverEndpoint('hello-service');
|
|
141
|
+
// Returns: http://hello-service:33199
|
|
142
|
+
|
|
143
|
+
// Get service OpenAPI spec
|
|
144
|
+
const spec = await mapper.getServiceSpec('hello-service');
|
|
145
|
+
// Returns OpenAPI specification object
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Parameter Transformation
|
|
149
|
+
|
|
150
|
+
### Input Transformation
|
|
151
|
+
```javascript
|
|
152
|
+
// Transform cookbook params to HTTP request
|
|
153
|
+
const transformed = mapper.transformParams({
|
|
154
|
+
params: { name: 'World', count: 5 },
|
|
155
|
+
mapping: {
|
|
156
|
+
name: 'body.name',
|
|
157
|
+
count: 'query.limit'
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Returns:
|
|
162
|
+
{
|
|
163
|
+
body: { name: 'World' },
|
|
164
|
+
query: { limit: 5 }
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Output Transformation
|
|
169
|
+
```javascript
|
|
170
|
+
// Transform HTTP response to workflow output
|
|
171
|
+
const output = mapper.transformResponse({
|
|
172
|
+
response: { data: { items: [...] } },
|
|
173
|
+
mapping: {
|
|
174
|
+
'data.items': 'results',
|
|
175
|
+
'data.total': 'count'
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## API Reference
|
|
181
|
+
|
|
182
|
+
### ApiMapper
|
|
183
|
+
|
|
184
|
+
#### initialize()
|
|
185
|
+
Initializes the mapper and loads service registry.
|
|
186
|
+
|
|
187
|
+
#### mapOperation(operation)
|
|
188
|
+
Maps a cookbook operation to HTTP request.
|
|
189
|
+
|
|
190
|
+
#### mapResponse(response)
|
|
191
|
+
Maps HTTP response to workflow result.
|
|
192
|
+
|
|
193
|
+
#### discoverEndpoint(serviceName)
|
|
194
|
+
Discovers service endpoint from registry.
|
|
195
|
+
|
|
196
|
+
#### getServiceSpec(serviceName)
|
|
197
|
+
Retrieves OpenAPI specification for service.
|
|
198
|
+
|
|
199
|
+
#### addMapping(serviceName, mappings)
|
|
200
|
+
Adds custom operation mappings.
|
|
201
|
+
|
|
202
|
+
#### transformParams(params, mapping)
|
|
203
|
+
Transforms parameters according to mapping rules.
|
|
204
|
+
|
|
205
|
+
## Integration with Service Wrapper
|
|
206
|
+
|
|
207
|
+
The API mapper is automatically used by service-wrapper:
|
|
208
|
+
|
|
209
|
+
```javascript
|
|
210
|
+
const { ServiceWrapper } = require('@onlineapps/service-wrapper');
|
|
211
|
+
|
|
212
|
+
const wrapper = new ServiceWrapper({
|
|
213
|
+
apiMapping: {
|
|
214
|
+
enabled: true,
|
|
215
|
+
customMappings: {...}
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// API mapping is automatically configured
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## OpenAPI Integration
|
|
223
|
+
|
|
224
|
+
Supports OpenAPI 3.0 specifications:
|
|
225
|
+
|
|
226
|
+
```javascript
|
|
227
|
+
// Validate against OpenAPI schema
|
|
228
|
+
const valid = await mapper.validateOperation({
|
|
229
|
+
service: 'hello-service',
|
|
230
|
+
operation: 'greet',
|
|
231
|
+
params: { name: 'World' }
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// Generate request from OpenAPI
|
|
235
|
+
const request = await mapper.fromOpenAPI({
|
|
236
|
+
spec: openApiSpec,
|
|
237
|
+
operationId: 'greetUser',
|
|
238
|
+
params: { name: 'World' }
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Testing
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
npm test # Run all tests
|
|
246
|
+
npm run test:unit # Unit tests only
|
|
247
|
+
npm run test:component # Component tests
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Dependencies
|
|
251
|
+
- `@onlineapps/conn-orch-registry` - Service registry client
|
|
252
|
+
- `axios` - HTTP client
|
|
253
|
+
- `openapi-validator` - Schema validation
|
|
254
|
+
|
|
255
|
+
## Related Documentation
|
|
256
|
+
- [Service Wrapper](/shared/connector/service-wrapper/README.md) - Integration guide
|
|
257
|
+
- [Registry System](/docs/modules/registry.md) - Service discovery
|
|
258
|
+
- [Cookbook Connector](/shared/connector/conn-orch-cookbook/README.md) - Operation format
|
|
259
|
+
- [API Standards](/docs/STANDARDS_OVERVIEW.md#api-structure) - Endpoint conventions
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
*Version: 1.0.0 | License: MIT*
|
package/coverage/clover.xml
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/coverage/lcov.info
CHANGED
|
File without changes
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlineapps/conn-orch-api-mapper",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "API mapping connector for OA Drive - maps cookbook operations to HTTP endpoints",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
"keywords": [
|
|
14
14
|
"api",
|
|
15
15
|
"mapping",
|
|
16
|
-
"openapi",
|
|
17
16
|
"cookbook",
|
|
18
17
|
"http",
|
|
19
18
|
"connector"
|
package/src/ApiMapper.js
CHANGED
|
@@ -184,42 +184,88 @@ class ApiMapper {
|
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
/**
|
|
187
|
-
* Parse OpenAPI specification to extract operations
|
|
187
|
+
* Parse OpenAPI specification or operations.json to extract operations
|
|
188
188
|
* @private
|
|
189
|
-
* @param {Object} spec - OpenAPI specification
|
|
189
|
+
* @param {Object} spec - OpenAPI specification or operations.json format
|
|
190
190
|
* @returns {Object} Operations map
|
|
191
191
|
*/
|
|
192
192
|
_parseOpenApiSpec(spec) {
|
|
193
193
|
const operations = {};
|
|
194
194
|
|
|
195
|
-
if (!spec ||
|
|
195
|
+
if (!spec || typeof spec !== 'object') {
|
|
196
196
|
return operations;
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
//
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
summary: operation.summary,
|
|
213
|
-
description: operation.description
|
|
214
|
-
};
|
|
215
|
-
}
|
|
199
|
+
// Check if this is operations.json format (has "operations" key at root)
|
|
200
|
+
if (spec.operations && typeof spec.operations === 'object') {
|
|
201
|
+
// Parse operations.json format
|
|
202
|
+
Object.entries(spec.operations).forEach(([operationId, operation]) => {
|
|
203
|
+
operations[operationId] = {
|
|
204
|
+
method: (operation.method || 'POST').toUpperCase(),
|
|
205
|
+
path: operation.endpoint || `/${operationId}`,
|
|
206
|
+
parameters: operation.input ? this._convertOperationsJsonInputToOpenApi(operation.input) : [],
|
|
207
|
+
requestBody: operation.input ? { content: { 'application/json': { schema: { type: 'object', properties: operation.input } } } } : undefined,
|
|
208
|
+
responses: operation.output ? { '200': { description: 'Success', content: { 'application/json': { schema: { type: 'object', properties: operation.output } } } } } : { '200': { description: 'Success' } },
|
|
209
|
+
summary: operation.description,
|
|
210
|
+
description: operation.description
|
|
211
|
+
};
|
|
216
212
|
});
|
|
217
|
-
|
|
213
|
+
this.logger?.info(`Parsed ${Object.keys(operations).length} operations from operations.json format`);
|
|
214
|
+
return operations;
|
|
215
|
+
}
|
|
218
216
|
|
|
219
|
-
|
|
217
|
+
// Extract all operations from OpenAPI paths (original OpenAPI format)
|
|
218
|
+
if (spec.paths) {
|
|
219
|
+
Object.entries(spec.paths).forEach(([path, pathItem]) => {
|
|
220
|
+
Object.entries(pathItem).forEach(([method, operation]) => {
|
|
221
|
+
if (['get', 'post', 'put', 'patch', 'delete'].includes(method)) {
|
|
222
|
+
const operationId = operation.operationId ||
|
|
223
|
+
`${method}_${path.replace(/[^a-zA-Z0-9]/g, '_')}`;
|
|
224
|
+
|
|
225
|
+
operations[operationId] = {
|
|
226
|
+
method: method.toUpperCase(),
|
|
227
|
+
path,
|
|
228
|
+
parameters: operation.parameters || [],
|
|
229
|
+
requestBody: operation.requestBody,
|
|
230
|
+
responses: operation.responses,
|
|
231
|
+
summary: operation.summary,
|
|
232
|
+
description: operation.description
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
this.logger?.info(`Parsed ${Object.keys(operations).length} operations from OpenAPI spec`);
|
|
220
240
|
return operations;
|
|
221
241
|
}
|
|
222
242
|
|
|
243
|
+
/**
|
|
244
|
+
* Convert operations.json input format to OpenAPI parameters
|
|
245
|
+
* @private
|
|
246
|
+
* @param {Object} input - operations.json input schema
|
|
247
|
+
* @returns {Array} OpenAPI parameters array
|
|
248
|
+
*/
|
|
249
|
+
_convertOperationsJsonInputToOpenApi(input) {
|
|
250
|
+
const parameters = [];
|
|
251
|
+
Object.entries(input).forEach(([name, schema]) => {
|
|
252
|
+
parameters.push({
|
|
253
|
+
name,
|
|
254
|
+
in: 'body', // operations.json uses body parameters
|
|
255
|
+
required: schema.required !== false,
|
|
256
|
+
schema: {
|
|
257
|
+
type: schema.type || 'string',
|
|
258
|
+
description: schema.description,
|
|
259
|
+
minLength: schema.minLength,
|
|
260
|
+
maxLength: schema.maxLength,
|
|
261
|
+
enum: schema.enum,
|
|
262
|
+
default: schema.default
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
return parameters;
|
|
267
|
+
}
|
|
268
|
+
|
|
223
269
|
/**
|
|
224
270
|
* Resolve variables in input using context
|
|
225
271
|
* @private
|
package/src/index.js
CHANGED
|
File without changes
|