# Tlpp REST Endpoint Generator

> Generate TLPP REST endpoints using annotation-based routing (@Get, @Post, @Put, @Patch, @Delete) with the oRest object. Follows TOTVS API standards (TTALK) including pagination, error model, standard headers, and Swagger documentation. Use when user says 'create REST endpoint', 'TLPP REST', '@Get annotation', 'oRest endpoint'.

- Skill: `tbc-servicos/tlpp-rest-endpoint-generator` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add tbc-servicos/tlpp-rest-endpoint-generator`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tbc-servicos/tlpp-rest-endpoint-generator/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- License: MIT
- Author: tbc-servicos (https://skillmd.com/u/tbc-servicos)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tbc-servicos/tlpp-rest-endpoint-generator

---


# TLPP REST Endpoint Generator

## Overview

Generate production-ready TLPP REST endpoints using the native annotation-based REST framework. TLPP REST replaces the legacy WsRESTful pattern with a simpler, annotation-driven approach. Each endpoint is a function decorated with an HTTP verb annotation and uses the global `oRest` object to handle requests and responses.

## When to Use

Use this skill when:

- Creating new REST API endpoints in TLPP
- Implementing TOTVS TTALK-compliant APIs
- Generating CRUD endpoints for Protheus entities
- Building integration APIs for external systems
- Migrating WsRESTful services to TLPP REST

---

## TLPP REST Architecture

### How It Works

1. A function is annotated with an HTTP verb annotation (e.g., `@Get("/path")`)
2. The TLPP REST Server automatically registers the route at startup via annotation scanning
3. When a request matches the route, the annotated function is invoked
4. The function uses the global `oRest` object to read the request and write the response
5. Swagger/OpenAPI documentation is generated automatically from the annotations

### Available Annotations

| Annotation            | HTTP Verb | Typical Use                  |
| --------------------- | --------- | ---------------------------- |
| `@Get("endpoint")`    | GET       | Retrieve resource(s)         |
| `@Post("endpoint")`   | POST      | Create a new resource        |
| `@Put("endpoint")`    | PUT       | Full update of a resource    |
| `@Patch("endpoint")`  | PATCH     | Partial update of a resource |
| `@Delete("endpoint")` | DELETE    | Remove a resource            |

**Annotation properties:**

- `endpoint` (required): The URI path for the route
- `description` (optional): Description shown in Swagger docs

```tlpp
// Minimal form (endpoint only)
@Get("/api/v1/customers")

// Full form (named properties)
@Get(endpoint="/api/v1/customers", description="List all customers")
```

---

## The oRest Object

The `oRest` object is a global object available inside any annotated REST function. It provides all methods for reading requests and writing responses.

### Request Methods

| Method                         | Returns   | Description                            |
| ------------------------------ | --------- | -------------------------------------- |
| `oRest:getQueryRequest()`      | Json      | Query string parameters (`?key=value`) |
| `oRest:getBodyRequest()`       | Character | Raw request body as string             |
| `oRest:getPathParamsRequest()` | Json      | Path parameters (e.g., `:id`)          |
| `oRest:getHeaderRequest()`     | Json      | All request headers                    |
| `oRest:getClientIP()`          | Character | Client IP address                      |

### Response Methods

| Method                                        | Parameters           | Description                                               |
| --------------------------------------------- | -------------------- | --------------------------------------------------------- |
| `oRest:setResponse(cBody)`                    | Character            | Set response body (concatenates if called multiple times) |
| `oRest:setStatusResponse(nCode, cBody)`       | Numeric, Character   | Set HTTP status code and body; returns Logical            |
| `oRest:setKeyHeaderResponse(cKey, cValue)`    | Character, Character | Set a response header                                     |
| `oRest:updateKeyHeaderResponse(cKey, cValue)` | Character, Character | Update an existing response header                        |
| `oRest:resetResponse()`                       | —                    | Clear the response body                                   |
| `oRest:getBodyResponse()`                     | —                    | Get current response body                                 |

### Path Parameters

Use `:paramName` syntax in the endpoint path to define path parameters:

```tlpp
@Get("/api/v1/customers/:id")
User Function getCustomer() as Logical
  Local jPathParams := oRest:getPathParamsRequest() as Json
  Local cId := jPathParams["id"] as Character
  // ...
Return oRest:setStatusResponse(200, cResponse)
```

---

## Bundled Reference Files

This skill uses progressive disclosure. The SKILL.md body covers the architecture, decision logic, and the generation checklist. Detailed endpoint templates, TTALK standards, and troubleshooting are in the `references/` directory — read them on demand based on the scenario:

| Reference File | When to Read | Content |
| --- | --- | --- |
| [references/tlpp-rest-endpoint-templates.md](references/tlpp-rest-endpoint-templates.md) | Generating **any CRUD endpoint** — GET list (paginated), GET by ID, POST, PUT, or DELETE | Full code templates for all 5 HTTP verbs, shared helper functions (`BuildErrorResponse`, `BuildValidationErrorResponse`) |
| [references/ttalk-standards-and-configuration.md](references/ttalk-standards-and-configuration.md) | Checking **TTALK response formats**, **HTTP status codes**, **REST server `appserver.ini` configuration**, or **debugging endpoint issues** | TTALK collection/error JSON formats, pagination query parameters, status code table, `appserver.ini` REST section, troubleshooting guide |

> Also refer to [references/sonarqube-rules-reference.md](../references/sonarqube-rules-reference.md) for the complete SonarQube rules reference shared across skills.

---

## Endpoint Generation Workflow

### Step 1: Gather Requirements

Determine from the user's request:

- Which HTTP verb(s) to generate (GET, POST, PUT, PATCH, DELETE, or full CRUD)
- The target Protheus entity/table (e.g., SA1 = Customers, SA2 = Suppliers)
- The endpoint base path (e.g., `/api/v1/customers`)
- Whether TTALK-compliant pagination is needed (collection endpoints)

### Step 2: Load Templates

Read [references/tlpp-rest-endpoint-templates.md](references/tlpp-rest-endpoint-templates.md) for the code templates matching the required verb(s). Adapt the templates to the target entity by replacing table aliases, field names, and namespace.

### Step 3: Apply TTALK Standards

For TOTVS-ecosystem APIs, read [references/ttalk-standards-and-configuration.md](references/ttalk-standards-and-configuration.md) to ensure responses follow the standard collection format, error model, and HTTP status codes.

### Step 4: Validate Against Checklist

Use the checklist below to verify the generated code covers all requirements.

---

## Endpoint Generation Checklist

### Structure

- [ ] `#include "tlpp-core.th"` is the first include
- [ ] `Namespace` declaration matches project convention
- [ ] User Function name is descriptive and uses camelCase
- [ ] HTTP verb annotation matches the operation semantics
- [ ] Endpoint path follows RESTful conventions (`/api/v1/{resource}`)
- [ ] Path parameters use `:paramName` syntax

### Request Handling

- [ ] Body parsed and validated for POST/PUT/PATCH
- [ ] Path parameters extracted via `oRest:getPathParamsRequest()`
- [ ] Query parameters extracted via `oRest:getQueryRequest()`
- [ ] Input sanitized before use in SQL queries (`FWExecStatement`)

### Response

- [ ] `Content-Type` header set to `application/json`
- [ ] Correct HTTP status code used
- [ ] Success response follows TTALK format
- [ ] Error response follows TTALK error model
- [ ] Collection endpoints include pagination (`hasNext`, `items`, `remainingRecords`)

### Data Access

- [ ] Workarea positioned correctly before read/write
- [ ] Database locks acquired with `RecLock()` and released with `MsUnlock()`
- [ ] `D_E_L_E_T_` filter always included in queries
- [ ] Branch filter (`FWxFilial`) always included
- [ ] Temporary aliases closed with `DBCloseArea()`
- [ ] SQL injection prevented (`FWExecStatement`)

### Error Handling

- [ ] `Try-Catch` wraps database operations
- [ ] Errors logged with `FWLogMsg()` including function context
- [ ] Error responses use TTALK error format
- [ ] Lock failures handled gracefully

### Security

- [ ] Authentication verified (if applicable)
- [ ] Authorization checked for the operation
- [ ] Input validated against expected types and ranges
- [ ] No sensitive data in error messages

### SonarQube Compliance

- [ ] No `RpcSetEnv` / `RpcSetType` calls in REST endpoint functions — use REST Server `PrepareIn` configuration instead
- [ ] No assignment to `__cUserID` or `cEmpAnt` — these are protected system variables
- [ ] No `StaticCall()` — use `FWLoadModel()`, `FWLoadMenuDef()`, or namespace-based calls
- [ ] No hardcoded passwords or credentials in source code
- [ ] `FWExecStatement` used for all queries with dynamic parameters
- [ ] Logging via `FWLogMsg()`, not `ConOut()`
- [ ] No `IIF()` — use `If/Else/EndIf` blocks
- [ ] `GetMV()` / `ExistBlock()` calls moved outside of loops
- [ ] No UI functions (`MsgAlert`, `MsgYesNo`, `Aviso`, `Help`) inside transaction-scoped handlers
- [ ] Includes in lowercase (e.g., `#include "totvs.ch"`)

> Refer to [references/sonarqube-rules-reference.md](../references/sonarqube-rules-reference.md) for the complete SonarQube rules reference.


