orbit-code-ai 0.1.37 → 0.1.39
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/dist/cli.mjs +367 -63
- package/package.json +1 -1
- package/skills/api-contract/SKILL.md +287 -0
- package/skills/apic-api/SKILL.md +309 -73
package/skills/apic-api/SKILL.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: apic-api
|
|
3
|
-
description: Generate a complete IBM API Connect (APIC) API definition for the DataPower API Gateway — full OpenAPI 2.0 (or 3.0) YAML including the x-ibm-configuration assembly (middleware logging, JWT validate, token-expiration switch, ESB response envelope, and catch handlers). Standard
|
|
3
|
+
description: Generate a complete IBM API Connect (APIC) API definition for the DataPower API Gateway — full OpenAPI 2.0 (or 3.0) YAML including the x-ibm-configuration assembly (middleware logging, JWT validate, token-expiration switch, ESB response envelope, and catch handlers). Standard middleware is baked in with opt-out flags.
|
|
4
4
|
trigger: /apic-api
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# /apic-api
|
|
8
8
|
|
|
9
9
|
Generate a full APIC API definition (the `*.yaml` you import into API Connect / publish to the
|
|
10
|
-
DataPower API Gateway). Output mirrors the house template
|
|
11
|
-
|
|
10
|
+
DataPower API Gateway). Output mirrors the house template, illustrated by three reference shapes (SamplePost / SampleFwd /
|
|
11
|
+
SampleDetect): a Swagger/OpenAPI contract **plus** the complete `x-ibm-configuration` assembly.
|
|
12
12
|
|
|
13
13
|
## Usage
|
|
14
14
|
|
|
@@ -18,25 +18,33 @@ AmerApp APIs: a Swagger/OpenAPI contract **plus** the complete `x-ibm-configurat
|
|
|
18
18
|
Flags:
|
|
19
19
|
--openapi 2.0|3.0 target spec version — USER'S CHOICE. If omitted, ask the user which one
|
|
20
20
|
they want before generating. Orbit does not assume a version.
|
|
21
|
+
--pattern P integration pattern (see "Two integration patterns"):
|
|
22
|
+
backend (default) = APIC calls a raw backend and WRAPS the response in the
|
|
23
|
+
ESB {Header,Body} envelope.
|
|
24
|
+
wrapper = APIC publishes an existing integration service (ACE OR
|
|
25
|
+
webMethods) that ALREADY returns the ESB envelope, so
|
|
26
|
+
APIC is a thin proxy and does NOT re-wrap (implies
|
|
27
|
+
--no-envelope).
|
|
28
|
+
If unspecified, ASK which pattern before generating.
|
|
21
29
|
--crypto <name> jws-crypto object for JWT validation (default: <appsegment>-crypto-object)
|
|
22
|
-
--backend-auth <name> APIC variable injected as backend auth header (e.g.
|
|
30
|
+
--backend-auth <name> APIC variable injected as backend auth header (e.g. backend-auth)
|
|
23
31
|
--jwt force JWT on (skip the prompt); --no-jwt forces it off. If neither is
|
|
24
32
|
given, ASK the user whether JWT validation is required (see Clarify step).
|
|
25
33
|
--no-jwt omit jwt-validate + Check Expiration + 400 throw + ExpiredToken catch
|
|
26
34
|
(no token enforcement)
|
|
27
|
-
--no-logging omit the middleware UpsertMDLogQ logging invoke (
|
|
35
|
+
--no-logging omit the middleware UpsertMDLogQ logging invoke (SampleDetect-style)
|
|
28
36
|
--no-envelope return the raw backend body instead of the {Header,Body} ESB envelope
|
|
29
37
|
--no-cors disable CORS
|
|
30
38
|
|
|
31
39
|
Backend-call tuning (all optional — infer sensible values from the prompt if not given):
|
|
32
40
|
--backend-verb V backend invoke verb: GET|POST|keep (default = API verb; "keep" forwards the
|
|
33
|
-
caller's verb,
|
|
41
|
+
caller's verb, SampleDetect-style)
|
|
34
42
|
--backend-type T backend response handling: json|detect (default json; "detect" =
|
|
35
|
-
content-type based, used by
|
|
43
|
+
content-type based, used by SampleDetect)
|
|
36
44
|
--invoke-version V backend invoke policy version: 2.2.0|2.3.0 (default 2.2.0; 2.3.0 adds
|
|
37
45
|
stop-on-error + graphql-send-type)
|
|
38
46
|
--backend-auth-header H header the --backend-auth value is set on (default Authorization;
|
|
39
|
-
|
|
47
|
+
SampleFwd uses "Token")
|
|
40
48
|
--backend-headers k=v,... extra STATIC headers set before the backend call
|
|
41
49
|
(e.g. REST-Framework-Version=4)
|
|
42
50
|
--pass-headers a,b,... headers FORWARDED to the backend → invoke header-control allowlist
|
|
@@ -45,37 +53,43 @@ Flags:
|
|
|
45
53
|
params. CRITICAL: every query param the backend needs must be listed, or the
|
|
46
54
|
gateway strips it.
|
|
47
55
|
--parse P backend parse: json (inline document_type json, default) | default
|
|
48
|
-
(apic-default-parsesettings,
|
|
49
|
-
--use-content-type add use-content-type: true to the backend parse (
|
|
50
|
-
--envelope-placement P where Prepare Response Header goes: in-case (default,
|
|
51
|
-
top-level (after the switch,
|
|
56
|
+
(apic-default-parsesettings, SampleDetect-style)
|
|
57
|
+
--use-content-type add use-content-type: true to the backend parse (SampleFwd/SampleDetect)
|
|
58
|
+
--envelope-placement P where Prepare Response Header goes: in-case (default, SamplePost/SampleDetect) |
|
|
59
|
+
top-level (after the switch, SampleFwd)
|
|
52
60
|
|
|
53
61
|
Examples:
|
|
54
|
-
/apic-api
|
|
55
|
-
backend $(
|
|
56
|
-
/apic-api
|
|
57
|
-
backend $(
|
|
62
|
+
/apic-api SampleGetUserInfo GET /v1/SampleApp \
|
|
63
|
+
backend $(backend-base-url)/api/resource/workers?onlyData=true; query param expand
|
|
64
|
+
/apic-api SampleUpdateCustomer POST /v1/SampleApp \
|
|
65
|
+
backend $(backend-base-url)/api/UpdateCustomer; --backend-auth backend-auth; \
|
|
58
66
|
body fields: customerSysId,email,idNumber,name,avatar,gender,dateOfBirth,attachment_records
|
|
59
67
|
```
|
|
60
68
|
|
|
61
69
|
## Variables to Derive
|
|
62
70
|
|
|
63
71
|
From the inputs:
|
|
64
|
-
- `{ApiTitle}` = Title Case of ApiName, e.g. `
|
|
65
|
-
- `{x-ibm-name}` = kebab-case of ApiName, e.g. `
|
|
66
|
-
- `{AppSegment}` = the app portion of basePath after `/v1/`, e.g. `
|
|
67
|
-
- `{appsegmentlower}` = lowercase AppSegment, e.g. `
|
|
72
|
+
- `{ApiTitle}` = Title Case of ApiName, e.g. `SampleDetect Get User Info`
|
|
73
|
+
- `{x-ibm-name}` = kebab-case of ApiName, e.g. `sampledetect-get-userinfo` (also the file stem)
|
|
74
|
+
- `{AppSegment}` = the app portion of basePath after `/v1/`, e.g. `SampleDetect`
|
|
75
|
+
- `{appsegmentlower}` = lowercase AppSegment, e.g. `sampledetect`
|
|
68
76
|
- `{version}` = `1.0.0` unless supplied
|
|
69
|
-
- `{operation-path}` = the API's own path
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
77
|
+
- `{operation-path}` = the API's own exposed path.
|
|
78
|
+
- **If the user supplies an explicit path — use it VERBATIM, exact casing, no re-derivation.**
|
|
79
|
+
Any of `path: /getCommodities`, `exposed path /getCommodities`, or a gateway path like
|
|
80
|
+
`commodity/api/v1.0/getCommodities` (→ take the segment after basePath: `/getCommodities`) counts
|
|
81
|
+
as explicit. A supplied `/getCommodities` must NOT become `/GetCommodities`.
|
|
82
|
+
- Only when NO path is supplied, derive it from the API name (PascalCase, leading slash):
|
|
83
|
+
`Get Customer Balance` → `/GetCustomerBalance`.
|
|
84
|
+
- **NEVER** take it from the backend target-url's path (the backend path is unrelated to the
|
|
85
|
+
exposed API path) — except the explicit-gateway-path case above, where the exposed segment is
|
|
86
|
+
stated by the user.
|
|
73
87
|
- `{verb}` = GET or POST (lowercase in `paths`)
|
|
74
88
|
- `{crypto-object}` = `--crypto` or `{appsegmentlower}-crypto-object`
|
|
75
89
|
- `{backend-target-url}` = backend URL from the description (keep `$(...)` APIC vars verbatim,
|
|
76
90
|
including claim injections like `?userEmail=$(decoded.claims.EmailAddress)`)
|
|
77
91
|
- `{backend-auth-var}` = `--backend-auth` value (only emitted if provided)
|
|
78
|
-
- `{backend-auth-header}` = `--backend-auth-header` or `Authorization` (
|
|
92
|
+
- `{backend-auth-header}` = `--backend-auth-header` or `Authorization` (SampleFwd: `Token`)
|
|
79
93
|
- `{backend-verb}` = `--backend-verb` or the API verb (may be `keep` — forwards caller's verb)
|
|
80
94
|
- `{backend-type}` = `--backend-type` or `json` (or `detect`)
|
|
81
95
|
- `{query}` = list of backend query params (from `--query` or inferred from the backend URL / prompt)
|
|
@@ -93,13 +107,18 @@ in a single batched follow-up** (alongside the 2.0/3.0 question). Do NOT invent
|
|
|
93
107
|
values for these:
|
|
94
108
|
|
|
95
109
|
- **OpenAPI version** — 2.0 or 3.0 (always ask if unspecified).
|
|
110
|
+
- **Integration pattern** — is APIC calling a **raw backend** (it must wrap the response in the ESB
|
|
111
|
+
envelope → `backend`), or **publishing an existing integration service (ACE or webMethods)** that
|
|
112
|
+
already returns the ESB envelope (APIC is a thin proxy, no re-wrap → `wrapper`)? Ask unless
|
|
113
|
+
`--pattern` is given or the prompt makes it clear (e.g. "expose our ACE flow", "wrap the webMethods
|
|
114
|
+
service", "the backend already returns the envelope").
|
|
96
115
|
- **JWT validation** — **ASK whether this API requires JWT validation** unless `--jwt`/`--no-jwt`
|
|
97
116
|
was passed or the prompt clearly states it. JWT is NOT assumed on. If **yes**, include the JWT
|
|
98
117
|
policies and ask for the crypto object (below). If **no**, omit JWT entirely (see the
|
|
99
118
|
"No-JWT shape" section) and do not ask for a crypto object.
|
|
100
|
-
- **Channel / app + basePath** — e.g. `/v1/
|
|
119
|
+
- **Channel / app + basePath** — e.g. `/v1/SampleDetect`. The app segment also drives naming. There is
|
|
101
120
|
no way to infer this from the operation name; ask (offer the known channels if helpful).
|
|
102
|
-
- **JWT crypto object** — e.g. `$(
|
|
121
|
+
- **JWT crypto object** — e.g. `$(sampledetect-crypto-object)`. Tied to the channel, not the operation.
|
|
103
122
|
**Only ask this when JWT is enabled.** Do not derive it from the API name.
|
|
104
123
|
- **Backend auth** — the APIC variable and the header it goes on (`Authorization` vs `Token`), if
|
|
105
124
|
the backend needs auth. Ask only if the prompt implies the backend is protected.
|
|
@@ -108,6 +127,58 @@ If the user prefers not to answer, fall back to clearly-marked placeholders
|
|
|
108
127
|
(`$(CHANGEME-crypto-object)`, `basePath: /v1/CHANGEME`) and list every placeholder in the summary —
|
|
109
128
|
never a guess that looks real.
|
|
110
129
|
|
|
130
|
+
## Two integration patterns
|
|
131
|
+
|
|
132
|
+
Every APIC API generated here is one of two shapes. Pick from `--pattern`, the prompt, or the
|
|
133
|
+
Clarify answer.
|
|
134
|
+
|
|
135
|
+
**`backend` (default) — APIC → raw backend.** APIC calls a backend service that returns a *raw*
|
|
136
|
+
body, so APIC is responsible for the ESB contract: it runs the full middleware and **wraps the
|
|
137
|
+
backend response** in the `{Header, Body}` envelope via the `Prepare Response Header` gatewayscript.
|
|
138
|
+
This is the skeleton exactly as written below.
|
|
139
|
+
|
|
140
|
+
**`wrapper` — APIC → existing integration service (TRUE thin proxy).** The backend *is* an existing
|
|
141
|
+
integration service — **ACE or webMethods** — that already owns the response contract (envelope,
|
|
142
|
+
business errors, correlation). APIC adds only gateway concerns (client-id/secret, optional JWT,
|
|
143
|
+
optional logging) and forwards the service's request/response **unchanged**. The pattern is identical
|
|
144
|
+
whichever platform sits behind it; only `{backend-target-url}` differs.
|
|
145
|
+
|
|
146
|
+
A thin wrapper must **NOT stamp house-specific conventions** onto a service that has its own. So,
|
|
147
|
+
unlike `backend`, wrapper mode drops all of these:
|
|
148
|
+
- **No `Prepare Response Header`** — do not re-wrap the success body (report "ESB envelope: off
|
|
149
|
+
(service-provided)").
|
|
150
|
+
- **No RefId-enforcing `Prepare Request`.** The frozen Prepare Request rejects on a missing `RefId`
|
|
151
|
+
header — that is one house's standard, not universal, and would reject a client that uses a
|
|
152
|
+
different correlation header. Omit it. If the spec names a correlation header (e.g. `X-Request-Id`),
|
|
153
|
+
optionally capture it with a **non-rejecting** `set-variable`; never `context.reject(...)`.
|
|
154
|
+
- **No ESB `{Header, Body}` error envelope in `catch`.** The frozen `DeFaultCatch` writes the house
|
|
155
|
+
envelope and depends on `context.customheaders.*` that a wrapper never sets. Use the **neutral
|
|
156
|
+
catch** below (surfaces the gateway error plainly). Business errors are unaffected — they come back
|
|
157
|
+
as a normal response body from the wrapped service.
|
|
158
|
+
- **Declare the spec's ACTUAL inbound headers** in `paths` (e.g. `X-Request-Id`), **not** the house
|
|
159
|
+
`RefId` / `CallerReqTime`.
|
|
160
|
+
- `{backend-target-url}` is the upstream service endpoint (an internal `$(...)` base-url variable),
|
|
161
|
+
not an external vendor URL.
|
|
162
|
+
- Keep security (client-id/secret); apply JWT / MW logging only as the flags/Clarify decide.
|
|
163
|
+
|
|
164
|
+
**For the actual YAML to emit in wrapper mode, use the complete standalone template in the
|
|
165
|
+
"## Wrapper skeleton (COMPLETE …)" section** — copy that entire file and fill the slots. Do NOT
|
|
166
|
+
assemble from the backend "## OpenAPI 2.0 skeleton"; the wrapper skeleton is self-contained and
|
|
167
|
+
already excludes the `Prepare Request`, `map`, `Prepare Response Header`, and ESB catch.
|
|
168
|
+
|
|
169
|
+
## Configurable middleware / backend variables
|
|
170
|
+
|
|
171
|
+
The `$(...)` names below are **placeholders you map to your gateway's real APIC variables** — they
|
|
172
|
+
contain no organization-specific names:
|
|
173
|
+
- `$(mw-auth)` and `$(mw-log-base-url)` — the standard middleware logging auth + base URL. Set these
|
|
174
|
+
to whatever your DataPower catalog actually calls them. **Deploy-critical:** if the names don't
|
|
175
|
+
match real gateway variables, logging silently fails.
|
|
176
|
+
- `$(backend-auth)` and `$(backend-base-url)` — the backend's auth variable and base URL.
|
|
177
|
+
- `$({crypto-object})` — the JWT crypto object (only when JWT is on).
|
|
178
|
+
|
|
179
|
+
Never invent real-looking values for these; when unknown, keep the placeholder and list it in the
|
|
180
|
+
summary (see the Clarify rules).
|
|
181
|
+
|
|
111
182
|
## Generation rules
|
|
112
183
|
|
|
113
184
|
1. **The spec version is the user's choice — Orbit supports both 2.0 and 3.0 equally.** Never
|
|
@@ -119,13 +190,27 @@ never a guess that looks real.
|
|
|
119
190
|
2b. **JWT is optional and not assumed.** Decide JWT on/off from `--jwt`/`--no-jwt`, an explicit
|
|
120
191
|
statement in the prompt, or the clarify answer. With JWT **off**, build the simpler "No-JWT shape"
|
|
121
192
|
(no jwt-validate, no Check Expiration, no switch, no ExpiredToken catch) — see that section.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
193
|
+
2c. **WRAPPER MODE IS A HARD OVERRIDE — obey before anything below.** When `--pattern wrapper`, the
|
|
194
|
+
assembly is the **"Thin-wrapper assembly"** block (in "Two integration patterns") — emit THAT,
|
|
195
|
+
not the main skeleton. Regardless of any "frozen/verbatim" rule below, in wrapper mode you MUST
|
|
196
|
+
**NOT emit** any of the following (they belong to `backend` only):
|
|
197
|
+
- ❌ the `Prepare Request` gatewayscript (the RefId `context.reject` guard) — omit entirely;
|
|
198
|
+
- ❌ the ESB `{Header, Body}` `DeFaultCatch` — use the **neutral catch** (`{code, message}`) instead;
|
|
199
|
+
- ❌ the `Prepare Response Header` gatewayscript — never re-wrap;
|
|
200
|
+
- ❌ the `RefId` / `CallerReqTime` path-level header params — declare the spec's real headers instead;
|
|
201
|
+
- ❌ any request `map` — a wrapper forwards the body **as-is** (no identity map, even for POST).
|
|
202
|
+
The frozen fragments' "paste verbatim" only means: IF a fragment is emitted, it is byte-exact. It
|
|
203
|
+
does NOT mean every fragment must appear. Wrapper mode emits fewer fragments — that is correct.
|
|
204
|
+
3. **Paste the frozen gatewayscript verbatim** (in the `backend` pattern). The JS strings below must
|
|
205
|
+
be byte-exact — DataPower rejects malformed assembly. Do not "clean up" or reformat them. (Wrapper
|
|
206
|
+
mode omits several of them — see rule 2c.)
|
|
207
|
+
4. **GET vs POST** (`backend` pattern): GET → query/header params, no request `map`, no `definitions`.
|
|
208
|
+
POST with body fields → add a request `map` policy + a `Request` definition (SamplePost pattern).
|
|
209
|
+
**Wrapper mode: NEVER add a request `map`** (the body is forwarded unchanged); still emit the
|
|
210
|
+
POST `definitions/Request` for the contract, and the leading `parse`.
|
|
126
211
|
5. Respect opt-out flags by omitting the corresponding policy (see annotations in the skeleton).
|
|
127
212
|
6. **Preserve every `$(...)` APIC variable reference exactly** — never strip the wrapper. In
|
|
128
|
-
particular `jws-crypto` MUST be `$({crypto-object})` (e.g. `$(
|
|
213
|
+
particular `jws-crypto` MUST be `$({crypto-object})` (e.g. `$(sampledetect-crypto-object)`), not the
|
|
129
214
|
bare name. A bare value is treated by the gateway as a literal string, not a variable, and breaks
|
|
130
215
|
JWT validation. Same for `target-url`, backend auth values, and any `$(...)` in the fragments.
|
|
131
216
|
7. **Backend `parameter-control` allowlist MUST list every backend query param.** An empty allowlist
|
|
@@ -143,7 +228,7 @@ never a guess that looks real.
|
|
|
143
228
|
10. **Do not hand-append allowlisted query params to the backend `target-url`.** Params listed in the
|
|
144
229
|
invoke `parameter-control` allowlist are forwarded automatically. Only manually append values
|
|
145
230
|
that are NOT request params — i.e. injected claims like `?userEmail=$(decoded.claims.EmailAddress)`
|
|
146
|
-
(
|
|
231
|
+
(SampleFwd) or `&q=...$(decoded.claims.EmailAddress)` (SampleDetect). Appending
|
|
147
232
|
`?accountId=$(request.parameters.accountId)` for an already-allowlisted `accountId` is wrong.
|
|
148
233
|
11. **Reproduce every gatewayscript `source` character-for-character.** Do not strip comments, blank
|
|
149
234
|
lines, or re-indent. The single-line quoted form (`"...\n..."`) is canonical and must be copied
|
|
@@ -153,7 +238,14 @@ never a guess that looks real.
|
|
|
153
238
|
|
|
154
239
|
## OpenAPI 2.0 skeleton
|
|
155
240
|
|
|
156
|
-
|
|
241
|
+
> ⛔ **`--pattern wrapper`: DO NOT USE THIS SKELETON AT ALL.** Skip straight to the **"## Wrapper
|
|
242
|
+
> skeleton (COMPLETE …)"** section below and emit that entire file instead. It is a complete,
|
|
243
|
+
> standalone document — there is nothing to copy from here. The `Prepare Request`, `map`,
|
|
244
|
+
> `Prepare Response Header`, and ESB `DeFaultCatch` fragments in this skeleton do NOT exist in wrapper
|
|
245
|
+
> output; if you paste any of them for a wrapper, it is a bug.
|
|
246
|
+
|
|
247
|
+
Assemble the file in this order. Fill `{slots}`; paste frozen fragments unchanged. **(`backend`
|
|
248
|
+
pattern — for `wrapper`, see the box above.)**
|
|
157
249
|
|
|
158
250
|
```yaml
|
|
159
251
|
swagger: '2.0'
|
|
@@ -171,7 +263,7 @@ x-ibm-configuration:
|
|
|
171
263
|
testable: true
|
|
172
264
|
assembly:
|
|
173
265
|
execute:
|
|
174
|
-
# ── POST-WITH-BODY ONLY: leading parse of the incoming request (
|
|
266
|
+
# ── POST-WITH-BODY ONLY: leading parse of the incoming request (SamplePost). Omit for GET. ──
|
|
175
267
|
# Place this as the FIRST policy, before logging, so message.body is parsed for the map.
|
|
176
268
|
- parse:
|
|
177
269
|
version: 2.2.0
|
|
@@ -194,7 +286,7 @@ x-ibm-configuration:
|
|
|
194
286
|
title: Log-set-variable
|
|
195
287
|
actions:
|
|
196
288
|
- set: message.headers.Authorization
|
|
197
|
-
value: $(
|
|
289
|
+
value: $(mw-auth)
|
|
198
290
|
type: string
|
|
199
291
|
- invoke:
|
|
200
292
|
version: 2.0.0
|
|
@@ -214,7 +306,7 @@ x-ibm-configuration:
|
|
|
214
306
|
keep-payload: true
|
|
215
307
|
output: outResp
|
|
216
308
|
target-url: >-
|
|
217
|
-
$(
|
|
309
|
+
$(mw-log-base-url)/MW/MWLogServices/GeneralLog/UpsertMDLogQ?Environment=$(env.path)&ServiceName=$(api.name)&UserName=$(client.app.id)&RequestDt=$(system.datetime)
|
|
218
310
|
|
|
219
311
|
# ── JWT (only when JWT is enabled). If JWT is OFF, omit jwt-validate + Check Expiration AND
|
|
220
312
|
# drop the switch below — run the backend call directly. See "No-JWT shape". ──
|
|
@@ -237,8 +329,8 @@ x-ibm-configuration:
|
|
|
237
329
|
- condition: ($statusCode() = 200)
|
|
238
330
|
execute:
|
|
239
331
|
# Backend auth + static headers — emit only if --backend-auth / --backend-headers given.
|
|
240
|
-
# Header name = {backend-auth-header} (default Authorization;
|
|
241
|
-
# Add one action per --backend-headers entry (e.g. REST-Framework-Version: '4',
|
|
332
|
+
# Header name = {backend-auth-header} (default Authorization; SampleFwd uses "Token").
|
|
333
|
+
# Add one action per --backend-headers entry (e.g. REST-Framework-Version: '4', SampleDetect).
|
|
242
334
|
- set-variable:
|
|
243
335
|
version: 2.0.0
|
|
244
336
|
title: set-variable
|
|
@@ -253,15 +345,15 @@ x-ibm-configuration:
|
|
|
253
345
|
# POST-with-body ONLY → request map (see "POST request map" section). Omit for GET.
|
|
254
346
|
|
|
255
347
|
# ── Backend call ──
|
|
256
|
-
# verb: {backend-verb} (GET|POST|keep — "keep" forwards caller's verb,
|
|
257
|
-
# backend-type: {backend-type} (json default | detect,
|
|
348
|
+
# verb: {backend-verb} (GET|POST|keep — "keep" forwards caller's verb, SampleDetect)
|
|
349
|
+
# backend-type: {backend-type} (json default | detect, SampleDetect)
|
|
258
350
|
# version 2.3.0 ⇒ also include stop-on-error: [] and graphql-send-type: detect (see variations ref)
|
|
259
351
|
- invoke:
|
|
260
352
|
version: 2.2.0 # or 2.3.0
|
|
261
353
|
title: invoke
|
|
262
354
|
backend-type: json # or detect
|
|
263
355
|
header-control:
|
|
264
|
-
type: blocklist # → allowlist with {pass-headers} when forwarding custom headers (
|
|
356
|
+
type: blocklist # → allowlist with {pass-headers} when forwarding custom headers (SampleFwd: Token, rolename)
|
|
265
357
|
values: []
|
|
266
358
|
parameter-control:
|
|
267
359
|
type: allowlist
|
|
@@ -278,8 +370,8 @@ x-ibm-configuration:
|
|
|
278
370
|
target-url: >-
|
|
279
371
|
{backend-target-url}
|
|
280
372
|
# Backend parse — pick ONE form (see --parse / variations ref):
|
|
281
|
-
# inline json (default) ── or ── named default: apic-default-parsesettings (
|
|
282
|
-
# add `use-content-type: true` when --use-content-type (
|
|
373
|
+
# inline json (default) ── or ── named default: apic-default-parsesettings (SampleDetect)
|
|
374
|
+
# add `use-content-type: true` when --use-content-type (SampleFwd/SampleDetect).
|
|
283
375
|
- parse:
|
|
284
376
|
version: 2.2.0
|
|
285
377
|
title: parse
|
|
@@ -288,8 +380,8 @@ x-ibm-configuration:
|
|
|
288
380
|
document_type: json
|
|
289
381
|
|
|
290
382
|
# ── FROZEN: Prepare Response Header — OMIT if --no-envelope. ──
|
|
291
|
-
# Default placement: HERE (inside the 200 case,
|
|
292
|
-
# If --envelope-placement top-level (
|
|
383
|
+
# Default placement: HERE (inside the 200 case, SamplePost/SampleDetect).
|
|
384
|
+
# If --envelope-placement top-level (SampleFwd): move this policy OUT of the switch,
|
|
293
385
|
# to top-level execute AFTER the switch and BEFORE the log policy.
|
|
294
386
|
- gatewayscript:
|
|
295
387
|
version: 2.0.0
|
|
@@ -368,11 +460,15 @@ x-ibm-configuration:
|
|
|
368
460
|
error-content: payload
|
|
369
461
|
paths:
|
|
370
462
|
{operation-path}:
|
|
371
|
-
|
|
463
|
+
# `backend` pattern: house correlation headers (RefId / CallerReqTime), as below.
|
|
464
|
+
# `wrapper` pattern: DELETE the RefId and CallerReqTime entries below entirely and put the spec's
|
|
465
|
+
# ACTUAL inbound headers here (e.g. X-Request-Id). Do NOT keep RefId/CallerReqTime AND add the
|
|
466
|
+
# spec header — replace, don't append. (See rule 2c.)
|
|
467
|
+
parameters: # path-level shared params (RefId may be required: true, SampleFwd)
|
|
372
468
|
- name: RefId
|
|
373
469
|
in: header
|
|
374
470
|
type: string
|
|
375
|
-
# required: true # add when RefId is mandatory (
|
|
471
|
+
# required: true # add when RefId is mandatory (SampleFwd)
|
|
376
472
|
- name: CallerReqTime
|
|
377
473
|
in: header
|
|
378
474
|
type: string
|
|
@@ -388,12 +484,12 @@ paths:
|
|
|
388
484
|
# GET example: - { name: inboxId, in: query, type: string, required: true }
|
|
389
485
|
# 2. POST-with-body: - { name: body, in: body, required: true, schema: { $ref: '#/definitions/Request' } }
|
|
390
486
|
# 3. authorization header (below)
|
|
391
|
-
# 4. any extra forwarded headers, e.g. rolename (
|
|
487
|
+
# 4. any extra forwarded headers, e.g. rolename (SampleFwd, required: true)
|
|
392
488
|
- name: authorization
|
|
393
489
|
required: true
|
|
394
490
|
in: header
|
|
395
491
|
type: string
|
|
396
|
-
# - name: rolename # example: custom forwarded header (
|
|
492
|
+
# - name: rolename # example: custom forwarded header (SampleFwd)
|
|
397
493
|
# required: true
|
|
398
494
|
# in: header
|
|
399
495
|
# type: string
|
|
@@ -417,6 +513,145 @@ basePath: {basePath}
|
|
|
417
513
|
|
|
418
514
|
---
|
|
419
515
|
|
|
516
|
+
## Wrapper skeleton (COMPLETE — use this ENTIRE file for `--pattern wrapper`)
|
|
517
|
+
|
|
518
|
+
For `--pattern wrapper`, **emit exactly this file** and fill the `{slots}`. It already omits the
|
|
519
|
+
`Prepare Request`, the `map`, the `Prepare Response Header`, and the ESB catch — do NOT add any of
|
|
520
|
+
them back, and do NOT copy anything from the backend skeleton above. There is no subtraction to do:
|
|
521
|
+
this is the whole document. (If `--jwt` is on for a wrapper — rare — add `jwt-validate` +
|
|
522
|
+
`Check Expiration` + `switch` before `invoke` per the main skeleton, keeping everything else here.)
|
|
523
|
+
|
|
524
|
+
```yaml
|
|
525
|
+
swagger: '2.0'
|
|
526
|
+
info:
|
|
527
|
+
title: {ApiTitle}
|
|
528
|
+
x-ibm-name: {x-ibm-name}
|
|
529
|
+
version: {version}
|
|
530
|
+
x-ibm-configuration:
|
|
531
|
+
cors:
|
|
532
|
+
enabled: true # --no-cors → false
|
|
533
|
+
gateway: datapower-api-gateway
|
|
534
|
+
type: rest
|
|
535
|
+
phase: realized
|
|
536
|
+
enforced: true
|
|
537
|
+
testable: true
|
|
538
|
+
assembly:
|
|
539
|
+
execute:
|
|
540
|
+
# POST-with-body ONLY: leading parse. Omit this policy entirely for GET.
|
|
541
|
+
- parse:
|
|
542
|
+
version: 2.2.0
|
|
543
|
+
title: parse
|
|
544
|
+
parse-settings-reference:
|
|
545
|
+
parse-settings:
|
|
546
|
+
document_type: json
|
|
547
|
+
max_value_length: 0
|
|
548
|
+
max_width: 0
|
|
549
|
+
|
|
550
|
+
# OPTIONAL correlation capture — ONLY if the spec names an inbound correlation header.
|
|
551
|
+
# Non-rejecting. Use the spec's real header name. Omit this whole policy if none.
|
|
552
|
+
- set-variable:
|
|
553
|
+
version: 2.0.0
|
|
554
|
+
title: Capture Correlation Id
|
|
555
|
+
actions:
|
|
556
|
+
- set: context.customheaders.CorrelationId
|
|
557
|
+
value: $(request.headers.X-Request-Id) # ← spec's real header
|
|
558
|
+
type: string
|
|
559
|
+
|
|
560
|
+
# MW logging — include the Log-set-variable + Log-invoke pair from the backend skeleton
|
|
561
|
+
# ONLY if NOT --no-logging. Omit both for --no-logging.
|
|
562
|
+
# Backend auth — include a set-variable ({backend-auth-header}: $({backend-auth-var}))
|
|
563
|
+
# ONLY if --backend-auth was given.
|
|
564
|
+
|
|
565
|
+
# ── Backend call → the ACE/webMethods service (direct, no switch) ──
|
|
566
|
+
- invoke:
|
|
567
|
+
version: 2.2.0
|
|
568
|
+
title: invoke
|
|
569
|
+
backend-type: json
|
|
570
|
+
header-control:
|
|
571
|
+
type: blocklist # → allowlist {pass-headers} if forwarding specific headers
|
|
572
|
+
values: []
|
|
573
|
+
parameter-control:
|
|
574
|
+
type: allowlist
|
|
575
|
+
values: [] # list every backend {query} param; empty = none forwarded
|
|
576
|
+
timeout: 60
|
|
577
|
+
verb: {verb}
|
|
578
|
+
http-version: HTTP/1.1
|
|
579
|
+
chunked-uploads: true
|
|
580
|
+
persistent-connection: true
|
|
581
|
+
cache-response: protocol
|
|
582
|
+
cache-ttl: 900
|
|
583
|
+
websocket-upgrade: false
|
|
584
|
+
target-url: >-
|
|
585
|
+
{backend-target-url}
|
|
586
|
+
- parse:
|
|
587
|
+
version: 2.2.0
|
|
588
|
+
title: parse
|
|
589
|
+
parse-settings-reference:
|
|
590
|
+
parse-settings:
|
|
591
|
+
document_type: json
|
|
592
|
+
- log:
|
|
593
|
+
version: 2.1.0
|
|
594
|
+
title: log
|
|
595
|
+
log-level: default
|
|
596
|
+
mode: gather-and-send
|
|
597
|
+
finally: []
|
|
598
|
+
# Neutral catch — surface the gateway error plainly. NO ESB {Header,Body} envelope.
|
|
599
|
+
catch:
|
|
600
|
+
- default:
|
|
601
|
+
- gatewayscript:
|
|
602
|
+
version: 2.0.0
|
|
603
|
+
title: DeFaultCatch
|
|
604
|
+
source: "var code = context.get('error.status.code');\nvar reason = context.get('error.message');\ncontext.message.statusCode = code;\nsession.output.write({ \"code\": code, \"message\": reason });"
|
|
605
|
+
properties:
|
|
606
|
+
target-url:
|
|
607
|
+
value: http://example.com/operation-name
|
|
608
|
+
description: The URL of the target service
|
|
609
|
+
encoded: false
|
|
610
|
+
activity-log:
|
|
611
|
+
enabled: true
|
|
612
|
+
success-content: activity
|
|
613
|
+
error-content: payload
|
|
614
|
+
paths:
|
|
615
|
+
{operation-path}:
|
|
616
|
+
parameters:
|
|
617
|
+
# The spec's REAL inbound headers ONLY. Example correlation header shown.
|
|
618
|
+
# Do NOT add RefId or CallerReqTime here.
|
|
619
|
+
- name: X-Request-Id # ← replace with the spec's actual header(s)
|
|
620
|
+
in: header
|
|
621
|
+
type: string
|
|
622
|
+
{verb}: # get: or post:
|
|
623
|
+
responses:
|
|
624
|
+
'200':
|
|
625
|
+
description: success
|
|
626
|
+
schema:
|
|
627
|
+
type: string
|
|
628
|
+
parameters:
|
|
629
|
+
# POST-with-body: body param (GET: omit). Plus any backend {query} params as in: query.
|
|
630
|
+
- name: body
|
|
631
|
+
in: body
|
|
632
|
+
required: true
|
|
633
|
+
schema:
|
|
634
|
+
$ref: '#/definitions/Request'
|
|
635
|
+
securityDefinitions:
|
|
636
|
+
clientID:
|
|
637
|
+
type: apiKey
|
|
638
|
+
in: header
|
|
639
|
+
name: X-IBM-Client-Id
|
|
640
|
+
clientSecret:
|
|
641
|
+
type: apiKey
|
|
642
|
+
name: X-IBM-Client-Secret
|
|
643
|
+
in: header
|
|
644
|
+
security:
|
|
645
|
+
- clientID: []
|
|
646
|
+
clientSecret: []
|
|
647
|
+
schemes:
|
|
648
|
+
- https
|
|
649
|
+
basePath: {basePath}
|
|
650
|
+
# definitions: only for POST-with-body — same Request block as the backend skeleton.
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
420
655
|
## No-JWT shape (when JWT validation is OFF)
|
|
421
656
|
|
|
422
657
|
When the API does **not** require JWT, generate a simpler assembly: there's no token to validate, so
|
|
@@ -435,7 +670,7 @@ call runs directly, and the `catch` keeps only the `default` handler.
|
|
|
435
670
|
source: "<<< the FROZEN Prepare Request source, verbatim >>>"
|
|
436
671
|
|
|
437
672
|
# Middleware logging — include unless --no-logging (same as main skeleton)
|
|
438
|
-
- set-variable: { version: 2.0.0, title: Log-set-variable, actions: [ { set: message.headers.Authorization, value: $(
|
|
673
|
+
- set-variable: { version: 2.0.0, title: Log-set-variable, actions: [ { set: message.headers.Authorization, value: $(mw-auth), type: string } ] }
|
|
439
674
|
- invoke: # ...the Log-invoke (UpsertMDLogQ) policy, verbatim...
|
|
440
675
|
|
|
441
676
|
# Backend auth + static headers (only if --backend-auth / --backend-headers given)
|
|
@@ -497,7 +732,7 @@ Notes for the No-JWT shape:
|
|
|
497
732
|
## POST request map (only when body fields are given)
|
|
498
733
|
|
|
499
734
|
Insert this `map` **inside the 200 case, before the backend `invoke`**, and add the matching
|
|
500
|
-
`definitions` block. Pattern from
|
|
735
|
+
`definitions` block. Pattern from SamplePost — first output field defaults from a JWT claim, the rest
|
|
501
736
|
copy through from input:
|
|
502
737
|
|
|
503
738
|
```yaml
|
|
@@ -545,20 +780,20 @@ definitions:
|
|
|
545
780
|
## Policy variations reference (drawn from the three live samples)
|
|
546
781
|
|
|
547
782
|
Use these exact forms when the prompt calls for them. The three samples map to:
|
|
548
|
-
**
|
|
549
|
-
**
|
|
550
|
-
**
|
|
783
|
+
**SamplePost** = POST + leading parse + request map + logging(v2.3.0) + envelope in-case;
|
|
784
|
+
**SampleFwd** = GET + logging(v2.0.0) + Token-header backend + forwarded headers + envelope top-level;
|
|
785
|
+
**SampleDetect** = GET + NO logging + verb keep + backend-type detect + named parse + envelope in-case.
|
|
551
786
|
|
|
552
|
-
### Logging invoke — two variants (omit entirely if `--no-logging`,
|
|
787
|
+
### Logging invoke — two variants (omit entirely if `--no-logging`, SampleDetect)
|
|
553
788
|
|
|
554
|
-
**(a) v2.0.0 "json" (
|
|
789
|
+
**(a) v2.0.0 "json" (SampleFwd)** — current skeleton default:
|
|
555
790
|
```yaml
|
|
556
791
|
- invoke:
|
|
557
792
|
version: 2.0.0
|
|
558
793
|
title: Log-invoke
|
|
559
794
|
verb: POST
|
|
560
795
|
target-url: >-
|
|
561
|
-
$(
|
|
796
|
+
$(mw-log-base-url)/MW/MWLogServices/GeneralLog/UpsertMDLogQ?Environment=$(env.path)&ServiceName=$(api.name)&UserName=$(client.app.id)&RequestDt=$(system.datetime)
|
|
562
797
|
follow-redirects: false
|
|
563
798
|
timeout: 60
|
|
564
799
|
parameter-control: { type: allowlist, values: [] }
|
|
@@ -570,7 +805,7 @@ Use these exact forms when the prompt calls for them. The three samples map to:
|
|
|
570
805
|
keep-payload: true
|
|
571
806
|
chunked-uploads: true
|
|
572
807
|
```
|
|
573
|
-
**(b) v2.3.0 "detect" (
|
|
808
|
+
**(b) v2.3.0 "detect" (SamplePost)** — preceded by its own `set-variable` setting `Authorization: $(mw-auth)`:
|
|
574
809
|
```yaml
|
|
575
810
|
- invoke:
|
|
576
811
|
version: 2.3.0
|
|
@@ -589,11 +824,11 @@ Use these exact forms when the prompt calls for them. The three samples map to:
|
|
|
589
824
|
websocket-upgrade: false
|
|
590
825
|
graphql-send-type: detect
|
|
591
826
|
target-url: >-
|
|
592
|
-
$(
|
|
827
|
+
$(mw-log-base-url)/MW/MWLogServices/GeneralLog/UpsertMDLogQ?Environment=$(env.path)&ServiceName=$(api.name)&UserName=$(client.app.id)&RequestDt=$(system.datetime)
|
|
593
828
|
output: logResp
|
|
594
829
|
```
|
|
595
830
|
|
|
596
|
-
### Backend invoke — v2.3.0 / detect / keep (
|
|
831
|
+
### Backend invoke — v2.3.0 / detect / keep (SampleDetect)
|
|
597
832
|
Same as the skeleton invoke, but with these fields:
|
|
598
833
|
```yaml
|
|
599
834
|
- invoke:
|
|
@@ -613,17 +848,17 @@ Same as the skeleton invoke, but with these fields:
|
|
|
613
848
|
websocket-upgrade: false
|
|
614
849
|
graphql-send-type: detect
|
|
615
850
|
target-url: >-
|
|
616
|
-
$(
|
|
851
|
+
$(backend-base-url)/api/resource/workers?onlyData=true&q=emails.EmailAddress='$(decoded.claims.EmailAddress)'
|
|
617
852
|
```
|
|
618
853
|
|
|
619
|
-
### Backend with forwarded headers (
|
|
854
|
+
### Backend with forwarded headers (SampleFwd) — Token auth + allowlist
|
|
620
855
|
```yaml
|
|
621
856
|
- set-variable:
|
|
622
857
|
version: 2.0.0
|
|
623
858
|
title: set-variable
|
|
624
859
|
actions:
|
|
625
860
|
- set: message.headers.Token
|
|
626
|
-
value: $(
|
|
861
|
+
value: $(backend-auth)
|
|
627
862
|
type: string
|
|
628
863
|
- invoke:
|
|
629
864
|
version: 2.2.0
|
|
@@ -639,24 +874,24 @@ Same as the skeleton invoke, but with these fields:
|
|
|
639
874
|
verb: GET
|
|
640
875
|
# ...rest as skeleton...
|
|
641
876
|
target-url: >-
|
|
642
|
-
$(
|
|
877
|
+
$(backend-base-url)/api/GetCorrespondences?userEmail=$(decoded.claims.EmailAddress)
|
|
643
878
|
```
|
|
644
879
|
|
|
645
|
-
### Multi-action set-variable (
|
|
880
|
+
### Multi-action set-variable (SampleDetect) — auth + static framework header
|
|
646
881
|
```yaml
|
|
647
882
|
- set-variable:
|
|
648
883
|
version: 2.0.0
|
|
649
884
|
title: set-variable
|
|
650
885
|
actions:
|
|
651
886
|
- set: message.headers.Authorization
|
|
652
|
-
value: $(
|
|
887
|
+
value: $(backend-auth)
|
|
653
888
|
type: string
|
|
654
889
|
- set: message.headers.REST-Framework-Version
|
|
655
890
|
value: '4'
|
|
656
891
|
type: string
|
|
657
892
|
```
|
|
658
893
|
|
|
659
|
-
### Backend parse — named-default form (
|
|
894
|
+
### Backend parse — named-default form (SampleDetect)
|
|
660
895
|
```yaml
|
|
661
896
|
- parse:
|
|
662
897
|
version: 2.2.0
|
|
@@ -666,13 +901,13 @@ Same as the skeleton invoke, but with these fields:
|
|
|
666
901
|
use-content-type: true
|
|
667
902
|
```
|
|
668
903
|
|
|
669
|
-
### Envelope placement — top-level (
|
|
904
|
+
### Envelope placement — top-level (SampleFwd)
|
|
670
905
|
The `Prepare Response Header` gatewayscript sits at **top-level execute, after the `switch`,
|
|
671
906
|
before `log`** — not inside the 200 case. The `switch` there is `version: 2.1.0`.
|
|
672
907
|
|
|
673
908
|
### Quick per-sample knob table
|
|
674
909
|
|
|
675
|
-
| Knob |
|
|
910
|
+
| Knob | SamplePost | SampleFwd | SampleDetect |
|
|
676
911
|
|---|---|---|---|
|
|
677
912
|
| method | POST | GET | GET |
|
|
678
913
|
| leading parse | yes | no | no |
|
|
@@ -680,7 +915,7 @@ before `log`** — not inside the 200 case. The `switch` there is `version: 2.1.
|
|
|
680
915
|
| request map + definitions | yes | no | no |
|
|
681
916
|
| backend version / type | 2.2.0 / json | 2.2.0 / json | 2.3.0 / detect |
|
|
682
917
|
| backend verb | POST | GET | keep |
|
|
683
|
-
| backend auth header | Authorization $(
|
|
918
|
+
| backend auth header | Authorization $(backend-auth) | Token $(backend-auth) | Authorization $(backend-auth) + REST-Framework-Version '4' |
|
|
684
919
|
| forwarded headers (allowlist) | — | Token, rolename | — |
|
|
685
920
|
| query params (allowlist) | — | inboxId,index,pageSize,language,userEmail | expand |
|
|
686
921
|
| backend parse | inline json | inline json (use-content-type) | default apic-default-parsesettings (use-content-type) |
|
|
@@ -720,12 +955,13 @@ below referencing the path you wrote.
|
|
|
720
955
|
After the file is written, print a short summary:
|
|
721
956
|
|
|
722
957
|
```
|
|
723
|
-
✓ {ApiTitle} — APIC {2.0|3.0} definition generated → {x-ibm-name}_{version}.yaml
|
|
958
|
+
✓ {ApiTitle} — APIC {2.0|3.0} definition generated → {x-ibm-name}_{version}.yaml [apic-skill rev-W2]
|
|
724
959
|
|
|
960
|
+
pattern {backend | wrapper (ACE/webMethods)}
|
|
725
961
|
verb {VERB} {operation-path} (basePath {basePath})
|
|
726
962
|
JWT validate {on|off} crypto: $({crypto-object})
|
|
727
963
|
MW logging {on|off}
|
|
728
|
-
ESB envelope {on|off}
|
|
964
|
+
ESB envelope {on|off (wrapper → off, service-provided)}
|
|
729
965
|
backend {backend-target-url}
|
|
730
966
|
request map {yes (N fields)|no}
|
|
731
967
|
|