$npx -y skills add totvs/engpro-advpl-tlpp-skills --skill fwrest-client-generatorGenerate AdvPL/TLPP code that CONSUMES external REST APIs using the FWRest client class. Covers GET, POST, PUT, DELETE verbs, header construction, query/path parameters, JSON body serialization, authentication (No Auth, HTTP Basic, Bearer Token/JWT, OAuth 2.0), timeout, SSL, stat
| 1 | # FWRest Client Generator |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | Generate production-ready AdvPL/TLPP code that **consumes** external REST APIs using the framework `FWRest` class. `FWRest` is the **HTTP client** class — it is the counterpart to the `@Get/@Post` annotation-based REST server (see `tlpp-rest-endpoint-generator` for *exposing* endpoints, not consuming them). |
| 6 | |
| 7 | `FWRest` wraps low-level HTTP socket calls and supports the four standard verbs **GET, POST, PUT, DELETE** (no native PATCH support). It handles SSL automatically through `appserver.ini` socket configuration. |
| 8 | |
| 9 | ## When to Use |
| 10 | |
| 11 | Use this skill when generating code that: |
| 12 | |
| 13 | - Calls a third-party REST API from inside Protheus (integrations with CRMs, payment gateways, ERPs, government services, etc.) |
| 14 | - Sends JSON payloads to external services |
| 15 | - Pulls data from external endpoints into a Protheus routine |
| 16 | - Needs HTTP Basic, Bearer/JWT, or OAuth 2.0 authentication |
| 17 | - Replaces legacy `HTTPCGet` / `HTTPCPost` / `HTTPQuote` calls with the framework client |
| 18 | |
| 19 | **Do NOT use** this skill for: |
| 20 | |
| 21 | - Exposing endpoints from Protheus → use [`../tlpp-rest-endpoint-generator/SKILL.md`](../tlpp-rest-endpoint-generator/SKILL.md) |
| 22 | - Workstation-side HTTP calls that must run on the user's machine → use `HTTPCGet`/`HTTPCPost` with WebAgent |
| 23 | - File downloads from non-REST endpoints → use `HTTPQuote` or `WSDownload` |
| 24 | |
| 25 | --- |
| 26 | |
| 27 | ## FWRest Architecture |
| 28 | |
| 29 | ### Lifecycle |
| 30 | |
| 31 | A typical FWRest call follows this five-step lifecycle: |
| 32 | |
| 33 | 1. **Instantiate** — `oClient := FWRest():New(cHost)` where `cHost` is the **base URL only** (scheme + host + optional port), e.g. `"https://api.example.com"`. |
| 34 | 2. **Configure** — `SetPath()`, `SetPostParams()`, `SetGetParams()`, `SetTimeOut()`, `SetChkStatus()`, `SetLegacySuccess()`. |
| 35 | 3. **Build headers** — Plain `Array` of `"Key: Value"` strings, e.g. `{"Content-Type: application/json", "Authorization: Bearer xyz"}`. |
| 36 | 4. **Invoke verb** — `:Get(aHead)`, `:Post(aHead)`, `:Put(aHead, cBody)`, `:Delete(aHead, cBody)`. All return `.T.` on success. |
| 37 | 5. **Read result** — `GetResult()` on success (response body as character), `GetLastError()` on failure, `GetHTTPCode()` for the numeric status. |
| 38 | |
| 39 | ### Path vs Query Parameters |
| 40 | |
| 41 | | Concern | API | Example | |
| 42 | | --- | --- | --- | |
| 43 | | Path segments | `SetPath("/api/v1/customers/123")` | URL: `/api/v1/customers/123` | |
| 44 | | Query string (inline) | `SetPath("/api/v1/customers?page=1")` | URL: `/api/v1/customers?page=1` | |
| 45 | | Query string (separate) | `SetGetParams("page=1&size=20")` | Appended after path | |
| 46 | | GET param via verb | `:Get(aHead, "page=1")` | Appended after path | |
| 47 | |
| 48 | > **Special characters in query values must be URI-encoded** via the `Escape()` function — otherwise the request will fail or be misinterpreted. |
| 49 | |
| 50 | ### Status Code Semantics |
| 51 | |
| 52 | | Method | Behavior | |
| 53 | | --- | --- | |
| 54 | | `Get()` | Returns `.T.` only for HTTP **200** (legacy) or **200–299** (with `SetLegacySuccess(.F.)`) | |
| 55 | | `Post()` | Returns `.T.` for **200** or **201** (legacy) or **200–299** (with `SetLegacySuccess(.F.)`) | |
| 56 | | `Put()` / `Delete()` | Returns `.T.` for **200** or **201** (legacy) or **200–299** (with `SetLegacySuccess(.F.)`) | |
| 57 | | `SetChkStatus(.F.)` | Disables internal HTTP code validation — verb returns `.T.` if **the connection succeeded**, regardless of HTTP code. You then call `GetHTTPCode()` to decide. **Use this for APIs that return 204, 207, 3xx, or 4xx as part of the contract.** | |
| 58 | |
| 59 | ### No PATCH Support |
| 60 | |
| 61 | `FWRest` does **not** support the PATCH verb. If the target API requires PATCH, generate code using `HTTPQuote()` instead and note this limitation explicitly. |
| 62 | |
| 63 | --- |
| 64 | |
| 65 | ## Bundled Reference Files |
| 66 | |
| 67 | This skill uses progressive disclosure. The SKILL.md body covers the architecture, decision logic, and the generation checklist. Detailed method reference, code templates, and authentication patterns are in the `references/` directory — read them on demand based on the scenario: |
| 68 | |
| 69 | | Reference File | When to Read | Content | |
| 70 | | --- | --- | --- | |
| 71 | | [references/fwrest-api-reference.md](references/fwrest-api-reference.md) | Looking up **exact method signatures**, **parameter types**, **minimum LIB version** per method, or behavior of `SetChkStatus`/`SetLegacySuccess`/`SetTimeOut`/`GetHTTPCode` | Complete `FWRest` method reference table with syntax, parameters, returns, LIB v |