@fui-org/fui-cli 1.3.2 → 2.0.0
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 +19 -3
- package/dist/fui-bmg5pnmq.js +379 -0
- package/dist/fui.js +1 -1
- package/package.json +3 -6
- package/skills/fui/SKILL.md +9 -41
- package/skills/fui-skill/SKILL.md +95 -225
- package/skills/fui-skill/assets/projectdefaultstyle-3.0.css +555 -0
- package/skills/fui-skill/assets/projectdefaultstyle.css +207 -235
- package/skills/fui-skill/references/INDEX.md +105 -137
- package/skills/fui-skill/references/advanced-techniques.md +76 -68
- package/skills/fui-skill/references/coding-standards.md +56 -56
- package/skills/fui-skill/references/component-design.md +166 -173
- package/skills/fui-skill/references/component-quickref.md +61 -60
- package/skills/fui-skill/references/component-table.md +128 -117
- package/skills/fui-skill/references/components-dialog.md +55 -56
- package/skills/fui-skill/references/components-display.md +24 -30
- package/skills/fui-skill/references/components-echart.md +186 -261
- package/skills/fui-skill/references/components-input.md +72 -96
- package/skills/fui-skill/references/controls-patterns.md +196 -342
- package/skills/fui-skill/references/controls-styling-vocabulary.md +130 -97
- package/skills/fui-skill/references/db-table-design.md +24 -28
- package/skills/fui-skill/references/db-workflow.md +191 -390
- package/skills/fui-skill/references/default-function.md +169 -128
- package/skills/fui-skill/references/design-modes.md +35 -63
- package/skills/fui-skill/references/echart-templates.md +204 -196
- package/skills/fui-skill/references/fastproject.md +62 -60
- package/skills/fui-skill/references/fsheet.md +109 -124
- package/skills/fui-skill/references/fullstack-workflow.md +90 -128
- package/skills/fui-skill/references/module-data-patterns.md +31 -40
- package/skills/fui-skill/references/module-json-anatomy.md +47 -52
- package/skills/fui-skill/references/module-structure.md +80 -196
- package/skills/fui-skill/references/new-session.md +49 -51
- package/skills/fui-skill/references/pdfmake.md +17 -17
- package/skills/fui-skill/references/permission-system.md +89 -108
- package/skills/fui-skill/references/platform-architecture.md +128 -153
- package/skills/fui-skill/references/project-config.md +102 -134
- package/skills/fui-skill/references/project-provisioning.md +139 -244
- package/skills/fui-skill/references/script-map.md +208 -242
- package/skills/fui-skill/references/sql-clr-functions.md +98 -97
- package/skills/fui-skill/references/system-design.md +63 -88
- package/skills/fui-skill/references/tapi-file-api.md +46 -52
- package/skills/fui-skill/references/tapi-permission-patterns.md +51 -53
- package/skills/fui-skill/references/tapi-reference.md +132 -207
- package/skills/fui-skill/references/tools-registry.md +84 -460
- package/skills/fui-skill/references/ui-crosswindow-patterns.md +79 -75
- package/skills/fui-skill/references/ui-dialog-patterns.md +98 -72
- package/skills/fui-skill/references/ui-layout-patterns.md +26 -26
- package/skills/fui-skill/references/ui-patterns.md +71 -83
- package/skills/fui-skill/references/ui-screenshot-review.md +63 -62
- package/skills/fui-skill/references/ui-table-cell-patterns.md +61 -59
- package/skills/fui-skill/references/ui-templates.md +16 -23
- package/skills/fui-skill/references/verification.md +236 -246
- package/skills/fui-skill/references/watcher-patterns.md +30 -63
- package/skills/fui-skill/references/websocket-realtime.md +83 -66
- package/skills/fui-skill/scripts/component-3.0.js +298 -131
- package/skills/fui-skill/scripts/component.js +277 -271
- package/skills/fui-skill/scripts/componentTable-3.0.js +182 -53
- package/skills/fui-skill/scripts/componentTable.js +171 -49
- package/skills/fui-skill/scripts/defaultfunction-3.0.js +88 -3
- package/skills/fui-skill/scripts/defaultfunction.js +88 -3
- package/skills/fui-skill/scripts/fsheet.js +38 -0
- package/dist/fui-y8an39cn.js +0 -420
- package/skills/fui-skill/README.md +0 -112
- package/skills/fui-skill/metadata.json +0 -75
- package/skills/fui-skill-cli/SKILL.md +0 -139
- package/skills/fui-skill-cli/references/INDEX.md +0 -110
- package/skills/fui-skill-cli/references/advanced-techniques.md +0 -168
- package/skills/fui-skill-cli/references/coding-standards.md +0 -112
- package/skills/fui-skill-cli/references/component-design.md +0 -448
- package/skills/fui-skill-cli/references/component-quickref.md +0 -78
- package/skills/fui-skill-cli/references/component-table.md +0 -248
- package/skills/fui-skill-cli/references/components-dialog.md +0 -191
- package/skills/fui-skill-cli/references/components-display.md +0 -141
- package/skills/fui-skill-cli/references/components-echart.md +0 -316
- package/skills/fui-skill-cli/references/components-input.md +0 -335
- package/skills/fui-skill-cli/references/controls-patterns.md +0 -701
- package/skills/fui-skill-cli/references/controls-styling-vocabulary.md +0 -137
- package/skills/fui-skill-cli/references/db-table-design.md +0 -73
- package/skills/fui-skill-cli/references/db-workflow.md +0 -288
- package/skills/fui-skill-cli/references/default-function.md +0 -425
- package/skills/fui-skill-cli/references/design-modes.md +0 -57
- package/skills/fui-skill-cli/references/echart-templates.md +0 -489
- package/skills/fui-skill-cli/references/fastproject.md +0 -99
- package/skills/fui-skill-cli/references/fsheet.md +0 -203
- package/skills/fui-skill-cli/references/fullstack-workflow.md +0 -313
- package/skills/fui-skill-cli/references/module-data-patterns.md +0 -117
- package/skills/fui-skill-cli/references/module-json-anatomy.md +0 -132
- package/skills/fui-skill-cli/references/module-structure.md +0 -141
- package/skills/fui-skill-cli/references/new-session.md +0 -85
- package/skills/fui-skill-cli/references/pdfmake.md +0 -60
- package/skills/fui-skill-cli/references/permission-system.md +0 -150
- package/skills/fui-skill-cli/references/platform-architecture.md +0 -269
- package/skills/fui-skill-cli/references/project-config.md +0 -303
- package/skills/fui-skill-cli/references/project-provisioning.md +0 -278
- package/skills/fui-skill-cli/references/script-map.md +0 -262
- package/skills/fui-skill-cli/references/sql-clr-functions.md +0 -225
- package/skills/fui-skill-cli/references/system-design.md +0 -89
- package/skills/fui-skill-cli/references/tapi-file-api.md +0 -185
- package/skills/fui-skill-cli/references/tapi-permission-patterns.md +0 -156
- package/skills/fui-skill-cli/references/tapi-reference.md +0 -474
- package/skills/fui-skill-cli/references/tools-registry.md +0 -84
- package/skills/fui-skill-cli/references/ui-crosswindow-patterns.md +0 -321
- package/skills/fui-skill-cli/references/ui-dialog-patterns.md +0 -255
- package/skills/fui-skill-cli/references/ui-layout-patterns.md +0 -176
- package/skills/fui-skill-cli/references/ui-patterns.md +0 -303
- package/skills/fui-skill-cli/references/ui-screenshot-review.md +0 -95
- package/skills/fui-skill-cli/references/ui-table-cell-patterns.md +0 -318
- package/skills/fui-skill-cli/references/ui-templates.md +0 -22
- package/skills/fui-skill-cli/references/verification.md +0 -236
- package/skills/fui-skill-cli/references/watcher-patterns.md +0 -163
- package/skills/fui-skill-cli/references/websocket-realtime.md +0 -271
|
@@ -1,59 +1,49 @@
|
|
|
1
1
|
# tAPI Reference — Transparent Query API (Core)
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Owns: **tAPI conventions: SP naming (`spAPI_*`/`spAPI_AUTH_*`/`spAPIFILE_*`), params, URL, response contract, `/help` route**. Deploy workflow: [db-workflow.md](db-workflow.md).
|
|
4
4
|
|
|
5
|
-
tAPI
|
|
5
|
+
tAPI auto-generates APIs from SQL SPs; the SP name sets URL, auth type and access (no controllers/routes). Accepts **GET and POST** — don't specify a method in the SP; module.json picks it. Load as needed:
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
| Topic | File |
|
|
8
|
+
| ------------------------------------------------------------------------------- | ---------------------------------------------------------- |
|
|
9
|
+
| Permission checks in SP body (5 patterns, `@sys_SystemRight`, `getSystemRight`) | [tapi-permission-patterns.md](tapi-permission-patterns.md) |
|
|
10
|
+
| File API — GET/UPLOAD, `spAPIFILE_`, `fileContent`, `tblFileData` | [tapi-file-api.md](tapi-file-api.md) |
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
> Image processing, outbound HTTP, email, server file I/O, regex → first check for an existing **SQL CLR function** (`httpCall`, `sendMail`, `ImageResize`, `FileWriter`, `RegexMatch`...): [sql-clr-functions.md](sql-clr-functions.md).
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|---|---|
|
|
13
|
-
| Kiểm tra quyền trong thân SP (5 pattern, `@sys_SystemRight`, `getSystemRight`) | [tapi-permission-patterns.md](tapi-permission-patterns.md) |
|
|
14
|
-
| File API — GET/UPLOAD, `spAPIFILE_`, `fileContent`, `tblFileData` | [tapi-file-api.md](tapi-file-api.md) |
|
|
15
|
-
|
|
16
|
-
> Nếu SP cần xử lý ảnh, gọi HTTP ra ngoài, gửi email, đọc/ghi file trên server, hoặc regex — kiểm tra xem DB đã có sẵn **SQL CLR function** (`httpCall`, `sendMail`, `ImageResize`, `FileWriter`, `RegexMatch`...) chưa trước khi viết logic thủ công. Xem [sql-clr-functions.md](sql-clr-functions.md).
|
|
17
|
-
|
|
18
|
-
## 1. Quy tắc đặt tên SP
|
|
19
|
-
|
|
20
|
-
### Cấu trúc tên
|
|
14
|
+
## 1. SP naming
|
|
21
15
|
|
|
22
16
|
```
|
|
23
17
|
spAPI_[AUTH_]FunctionName
|
|
24
18
|
```
|
|
25
19
|
|
|
26
|
-
|
|
|
27
|
-
|
|
28
|
-
| `spAPI_`
|
|
29
|
-
| `AUTH_`
|
|
30
|
-
| `FunctionName` | ✅
|
|
31
|
-
|
|
32
|
-
**Ví dụ tên SP:**
|
|
20
|
+
| Part | Required | Meaning |
|
|
21
|
+
| -------------- | -------- | ---------------------------------------------------------------- |
|
|
22
|
+
| `spAPI_` | ✅ | Marks SP as API-callable. Missing → API cannot call it |
|
|
23
|
+
| `AUTH_` | ❌ | No auth required. Omitted → valid token mandatory |
|
|
24
|
+
| `FunctionName` | ✅ | API function name used in URL, e.g. `MessageHome`, `UserSetting` |
|
|
33
25
|
|
|
34
26
|
```sql
|
|
35
27
|
spAPI_MessageHome -- có auth
|
|
36
28
|
spAPI_AUTH_SelectChat -- không cần auth
|
|
37
29
|
```
|
|
38
30
|
|
|
39
|
-
|
|
31
|
+
File API:
|
|
40
32
|
|
|
41
33
|
```
|
|
42
34
|
spAPIFILE_Document -- SP để GET file
|
|
43
35
|
spAPIFILE_UPLOAD_Document -- SP để nhận file upload
|
|
44
36
|
```
|
|
45
37
|
|
|
46
|
-
|
|
38
|
+
Details: [tapi-file-api.md](tapi-file-api.md).
|
|
47
39
|
|
|
48
40
|
---
|
|
49
41
|
|
|
50
|
-
## 2.
|
|
51
|
-
|
|
52
|
-
Ba loại tham số:
|
|
42
|
+
## 2. SP parameters
|
|
53
43
|
|
|
54
|
-
### `@url1_`, `@url2_`, `@url3_`... —
|
|
44
|
+
### `@url1_`, `@url2_`, `@url3_`... — route params
|
|
55
45
|
|
|
56
|
-
|
|
46
|
+
Taken from URL segments in order:
|
|
57
47
|
|
|
58
48
|
```
|
|
59
49
|
https://api.domain.vn/app/FunctionName/value1/value2
|
|
@@ -64,22 +54,21 @@ https://api.domain.vn/app/FunctionName/value1/value2
|
|
|
64
54
|
@url2_Mode varchar(50), -- nhận "value2"
|
|
65
55
|
```
|
|
66
56
|
|
|
67
|
-
### `@sys_` —
|
|
57
|
+
### `@sys_` — system params (injected by tAPI, never sent by client)
|
|
68
58
|
|
|
69
|
-
|
|
|
70
|
-
|
|
71
|
-
| `@sys_UserID`
|
|
72
|
-
| `@sys_UserName`
|
|
73
|
-
| `@sys_GroupID`
|
|
74
|
-
| `@sys_DepartmentID`
|
|
75
|
-
| `@sys_SystemRight`
|
|
76
|
-
| `@sys_FunctionRight`
|
|
77
|
-
| `@sys_SessionID`
|
|
78
|
-
| `@sys_RawData`
|
|
79
|
-
| `@sys_header_{
|
|
59
|
+
| Param | Type | Meaning |
|
|
60
|
+
| -------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
61
|
+
| `@sys_UserID` | varchar(9) | Authenticated user ID |
|
|
62
|
+
| `@sys_UserName` | varchar(50) | Login name |
|
|
63
|
+
| `@sys_GroupID` | int | User's group |
|
|
64
|
+
| `@sys_DepartmentID` | varchar(9) | Department ID |
|
|
65
|
+
| `@sys_SystemRight` | int | Tiered right (1=low, 9=high) |
|
|
66
|
+
| `@sys_FunctionRight` | varchar(2000) | Function rights as `[AD][RPT][MGR]` |
|
|
67
|
+
| `@sys_SessionID` | varchar(50) | Auth session ID |
|
|
68
|
+
| `@sys_RawData` | nvarchar(max) | Full client JSON body |
|
|
69
|
+
| `@sys_header_{HeaderName}` | varchar(n) | **A family, not one fixed name** — reads any HTTP header; `NULL` if client didn't send it. Naming rule below |
|
|
80
70
|
|
|
81
|
-
> **CRITICAL —
|
|
82
|
-
> tAPI backend tự gán toàn bộ tham số `@sys_*` từ session đã xác thực. Nếu client truyền vào `IN`, giá trị sẽ bị **bỏ qua hoặc ghi đè** bởi server — truyền vào là thừa và có thể gây nhầm lẫn.
|
|
71
|
+
> **CRITICAL — never put `@sys_` in module.json `IN`.** tAPI fills all `@sys_*` from the session; client values are **ignored or overwritten**.
|
|
83
72
|
>
|
|
84
73
|
> ```json
|
|
85
74
|
> // ❌ SAI — không đưa sys_ vào IN
|
|
@@ -88,45 +77,29 @@ https://api.domain.vn/app/FunctionName/value1/value2
|
|
|
88
77
|
> // ✅ ĐÚNG — chỉ truyền custom params
|
|
89
78
|
> "IN": { "ModuleID": "sModuleID" }
|
|
90
79
|
> ```
|
|
91
|
-
>
|
|
92
|
-
> `@sys_UserID`, `@sys_SystemRight`, `@sys_FunctionRight`... đều được tAPI tự điền — SP nhận đúng giá trị mà không cần client gửi.
|
|
93
80
|
|
|
94
|
-
#### `@sys_header_*` —
|
|
81
|
+
#### `@sys_header_*` — read HTTP headers: replace each `-` with `_`
|
|
95
82
|
|
|
96
|
-
|
|
97
|
-
giới hạn trong một danh sách cho sẵn. Nhưng tên header HTTP chứa dấu `-` (`User-Agent`,
|
|
98
|
-
`Sec-Ch-Ua-Mobile`), mà **`-` không hợp lệ trong tên biến/tham số của SQL Server**. Viết thẳng tên
|
|
99
|
-
header vào là script không biên dịch được:
|
|
83
|
+
Works for **any** header. `-` is invalid in SQL Server param names, so the literal name won't compile:
|
|
100
84
|
|
|
101
85
|
```sql
|
|
102
86
|
-- ❌ SAI — lỗi cú pháp ngay lúc CREATE PROCEDURE, không phải lỗi runtime
|
|
103
87
|
@sys_header_User-Agent varchar(500)
|
|
104
88
|
```
|
|
105
89
|
|
|
106
|
-
**
|
|
107
|
-
|
|
108
|
-
chuyển tên là con đường **duy nhất**.
|
|
90
|
+
- **No quoting works**: `@[sys_header_User-Agent]` and `@"sys_header_User-Agent"` are both invalid. Renaming is the **only** way.
|
|
91
|
+
- **Each `-` → one `_`.** 1-to-1: don't drop characters, change case, or merge segments.
|
|
109
92
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
93
|
+
| HTTP header | SP param |
|
|
94
|
+
| ------------------ | ---------------------------------------- |
|
|
95
|
+
| `User-Agent` | `@sys_header_User_Agent` |
|
|
96
|
+
| `Sec-Ch-Ua-Mobile` | `@sys_header_Sec_Ch_Ua_Mobile` |
|
|
97
|
+
| `X-Forwarded-For` | `@sys_header_X_Forwarded_For` |
|
|
98
|
+
| `Accept-Language` | `@sys_header_Accept_Language` |
|
|
99
|
+
| `Cookie` | `@sys_header_Cookie` — no `-`, unchanged |
|
|
113
100
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
| `User-Agent` | `@sys_header_User_Agent` |
|
|
117
|
-
| `Sec-Ch-Ua-Mobile` | `@sys_header_Sec_Ch_Ua_Mobile` |
|
|
118
|
-
| `X-Forwarded-For` | `@sys_header_X_Forwarded_For` |
|
|
119
|
-
| `Accept-Language` | `@sys_header_Accept_Language` |
|
|
120
|
-
| `Cookie` | `@sys_header_Cookie` — không có `-` thì giữ nguyên |
|
|
121
|
-
|
|
122
|
-
Chiều ngược lại (đọc SP có sẵn để biết nó lấy header nào): bỏ tiền tố `@sys_header_`, rồi đổi mọi `_`
|
|
123
|
-
còn lại thành `-` — `@sys_header_Accept_Language` → `Accept-Language`.
|
|
124
|
-
|
|
125
|
-
**Hoa-thường không quan trọng** — tAPI so khớp không phân biệt chữ hoa chữ thường, ở cả tiền tố lẫn tên
|
|
126
|
-
header: `@sys_header_User_Agent`, `@sys_Header_User_Agent`, `@sys_header_USER_AGENT` đều tra đúng một
|
|
127
|
-
header. (Đó là lý do `@sys_Header_RequestID` viết hoa chữ `H` trong bảng trên vẫn chạy.) Dù vậy **hãy
|
|
128
|
-
viết đúng hoa-thường như tên header chuẩn** (`User-Agent`, không `USER_AGENT`): người đọc SP nhận ra
|
|
129
|
-
ngay header nào, khỏi phải dịch. Thứ **bắt buộc** đúng vẫn chỉ là dấu `_` thay cho `-`.
|
|
101
|
+
- Reverse (reading an existing SP): drop `@sys_header_`, turn remaining `_` into `-` — `@sys_header_Accept_Language` → `Accept-Language`.
|
|
102
|
+
- Matching is **case-insensitive** (prefix and name): `@sys_header_User_Agent`, `@sys_Header_User_Agent`, `@sys_header_USER_AGENT` are the same header (so `@sys_Header_RequestID` works). Still use standard casing (`User-Agent`, not `USER_AGENT`). Only `_` for `-` is mandatory.
|
|
130
103
|
|
|
131
104
|
```sql
|
|
132
105
|
CREATE PROCEDURE spAPI_AuditLog_Insert
|
|
@@ -145,27 +118,15 @@ BEGIN
|
|
|
145
118
|
END
|
|
146
119
|
```
|
|
147
120
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
- **
|
|
151
|
-
module.json, và **không được gán default value** (`= null` là lỗi cứng — `db_sp_deploy` chặn, xem mục
|
|
152
|
-
dưới).
|
|
153
|
-
- **Client không gửi header thì tham số là `NULL`** (không phải chuỗi rỗng) — và header vắng mặt là
|
|
154
|
-
chuyện bình thường, không phải ca hiếm: lời gọi từ script/server-to-server thường không có
|
|
155
|
-
`User-Agent`. `NULL` kéo theo hai hệ quả im lặng của T-SQL, bọc bằng `ISNULL(...)` ngay tại chỗ dùng:
|
|
156
|
-
- **So sánh ra UNKNOWN, không ra TRUE/FALSE.** `WHERE @sys_header_User_Agent <> 'bot'` **loại luôn**
|
|
157
|
-
dòng khi header vắng — ngược hẳn điều người viết mong đợi.
|
|
158
|
-
- **Nối chuỗi bằng `+` biến cả chuỗi thành `NULL`.** Một header vắng đủ để xoá trắng nguyên câu log.
|
|
159
|
-
- **Dữ liệu header do client tự khai, KHÔNG tin được.** `User-Agent`, `X-Forwarded-For` giả được hết —
|
|
160
|
-
dùng để ghi log/thống kê thì hợp lý, lấy làm căn cứ phân quyền thì không. Quyền lấy từ
|
|
161
|
-
`@sys_UserID`/`@sys_SystemRight` (tAPI dựng từ token đã xác thực), không lấy từ header.
|
|
121
|
+
- **Still `@sys_*`:** auto-filled, **not** in `IN`, **no default** (`= null` is a hard error; `fui sp deploy` blocks it, see below).
|
|
122
|
+
- **Missing header → `NULL`** (not `''`) — normal, e.g. script/server-to-server calls often lack `User-Agent`. Wrap in `ISNULL(...)` at use: comparisons give UNKNOWN (`WHERE @sys_header_User_Agent <> 'bot'` **drops** the row), and `+` concatenation gives `NULL` (blanks the whole log string).
|
|
123
|
+
- **Untrusted (client-supplied, spoofable).** Log/stats only, never authorization; take rights from `@sys_UserID`/`@sys_SystemRight` (from the verified token).
|
|
162
124
|
|
|
163
|
-
|
|
164
|
-
đầu vào mà tAPI thực sự thấy (xem §3.1).
|
|
125
|
+
Check the name tAPI sees: `fui sp help <name>` (§3.1).
|
|
165
126
|
|
|
166
|
-
### Custom params —
|
|
127
|
+
### Custom params — business params
|
|
167
128
|
|
|
168
|
-
|
|
129
|
+
Param name = JSON body field name:
|
|
169
130
|
|
|
170
131
|
```sql
|
|
171
132
|
@StudentID varchar(9),
|
|
@@ -173,36 +134,14 @@ Tên tham số = tên field trong JSON body gửi lên:
|
|
|
173
134
|
@Keyword nvarchar(200)
|
|
174
135
|
```
|
|
175
136
|
|
|
176
|
-
####
|
|
177
|
-
|
|
178
|
-
Đây là hành vi nền tảng, quyết định cách đọc mọi mục còn lại của §2:
|
|
179
|
-
|
|
180
|
-
| Tình huống | tAPI làm gì |
|
|
181
|
-
|---|---|
|
|
182
|
-
| Body **thiếu** một khoá mà SP có tham số | truyền **`NULL`** cho tham số đó |
|
|
183
|
-
| Body **thừa** một khoá mà SP không có tham số | **bỏ qua im lặng** |
|
|
184
|
-
|
|
185
|
-
**Không có ca nào báo lỗi.** Gõ sai tên khoá trong `IN` của module.json (`StudentId` thay vì
|
|
186
|
-
`StudentID`) không làm request hỏng — SP chỉ nhận `NULL` và trả về kết quả rỗng hoặc sai, còn HTTP vẫn
|
|
187
|
-
200. Đây là lớp lỗi hỏng-âm-thầm hay gặp nhất khi nối API.
|
|
137
|
+
#### Param binding is LENIENT — never errors
|
|
188
138
|
|
|
189
|
-
|
|
139
|
+
- Body **lacks** a key → param gets **`NULL`**. Body has an **extra** key → **silently ignored**.
|
|
140
|
+
- A typo in `IN` (`StudentId` vs `StudentID`) → SP gets `NULL`, empty/wrong data, HTTP 200. Most common silent wiring bug.
|
|
141
|
+
- **Renaming/removing an SP param is a contract change with NO signal**: old modules keep sending old keys. Audit callers or compare with `fui sp help <name>` (§3.1).
|
|
142
|
+
- **`NULL` follows T-SQL rules** (`<>` → UNKNOWN drops rows; `+` → `NULL`): wrap possibly-absent params in `ISNULL(...)` at use.
|
|
190
143
|
|
|
191
|
-
-
|
|
192
|
-
chạy, chỉ là giá trị rơi vào hư không. Đừng trông chờ một lỗi để biết mình quên sửa nơi gọi — tự
|
|
193
|
-
soát, hoặc đối chiếu bằng `db_sp_help`.
|
|
194
|
-
- **`NULL` lan theo luật T-SQL**: `WHERE @x <> 'y'` thành UNKNOWN nên loại luôn dòng, và `+` nối chuỗi
|
|
195
|
-
ra `NULL`. Tham số có thể vắng thì bọc `ISNULL(...)` ngay tại chỗ dùng.
|
|
196
|
-
|
|
197
|
-
Kiểm tên khoá thật sự tới được SP: `db_sp_help({ name })` in danh sách tham số mà tAPI đang thấy
|
|
198
|
-
(xem §3.1).
|
|
199
|
-
|
|
200
|
-
> **CRITICAL — Không được gán giá trị mặc định cho bất kỳ tham số nào:**
|
|
201
|
-
> tAPI **luôn truyền đủ mọi tham số của SP** — khoá nào client không gửi thì nó truyền `NULL`. Nên
|
|
202
|
-
> `DEFAULT` trong khai báo SP **không bao giờ được dùng tới**: viết `@HeID int = 99` rồi không gửi
|
|
203
|
-
> `HeID` thì nhận `NULL`, không phải `99`. Default ở đây là một lời hứa luôn bị phá, và nó im lặng.
|
|
204
|
-
> Không gán `= value` hay `= null` cho bất kỳ tham số nào — kể cả `@sys_*`. **Đây không chỉ là quy ước**: `db_sp_deploy` chặn cứng (code-level, `detectDefaultApiParams()` trong `src/tools/db.ts`) mọi SP `spAPI_*`/`spAPIFILE_*` có tham số dạng này, và `db_sp_verify` cảnh báo sớm cùng lỗi trước cả khi deploy.
|
|
205
|
-
> Cần một giá trị mặc định thì đặt **trong thân SP**: `SET @HeID = ISNULL(@HeID, 99)`.
|
|
144
|
+
> **CRITICAL — no default value on any param** (`= value` or `= null`, including `@sys_*`). tAPI **always passes every param** (`NULL` if not sent), so `@HeID int = 99` silently gives `NULL`, not `99`. `fui sp deploy` hard-blocks it for `spAPI_*`/`spAPIFILE_*` (`detectDefaultApiParams()` in `src/tools/db.ts`); `fui sp verify` warns earlier. Set defaults **in the body**: `SET @HeID = ISNULL(@HeID, 99)`.
|
|
206
145
|
>
|
|
207
146
|
> ```sql
|
|
208
147
|
> -- ❌ SAI
|
|
@@ -220,30 +159,26 @@ Kiểm tên khoá thật sự tới được SP: `db_sp_help({ name })` in danh
|
|
|
220
159
|
> @sys_SystemRight int
|
|
221
160
|
> ```
|
|
222
161
|
|
|
223
|
-
Client
|
|
162
|
+
Client sends: `POST /app/FunctionName` with body `{ "StudentID": "SV001", "SemesterID": 1 }`
|
|
224
163
|
|
|
225
164
|
---
|
|
226
165
|
|
|
227
|
-
## 3. URL
|
|
166
|
+
## 3. API URL
|
|
228
167
|
|
|
229
168
|
```
|
|
230
169
|
{domain}/{apiName}/{FunctionName}/{url1}/{url2}...
|
|
231
170
|
{domain}/{apiName}/auth/{FunctionName}/{url1}/{url2}...
|
|
232
171
|
```
|
|
233
172
|
|
|
234
|
-
|
|
|
235
|
-
|
|
236
|
-
| `domain`
|
|
237
|
-
| `apiName`
|
|
238
|
-
| `auth`
|
|
239
|
-
| `FunctionName`
|
|
240
|
-
| `url1`, `url2`... | Route params
|
|
241
|
-
|
|
242
|
-
**Một project có thể có NHIỀU `apiName`** — tức nhiều database, mỗi cái một alias. `"API": "/{alias}/Ten"`
|
|
243
|
-
trong module.json là thứ nói SP đó nằm ở database nào; MCP dùng đúng alias ấy làm tên thư mục
|
|
244
|
-
`_db/{alias}/` và làm tham số `db` của các DB tool (xem [db-workflow.md](db-workflow.md) §1, §4).
|
|
173
|
+
| Part | Meaning |
|
|
174
|
+
| ----------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
175
|
+
| `domain` | API domain, e.g. `https://api.example.vn` |
|
|
176
|
+
| `apiName` | App apiName: `me`, `congvan`, `calen`... — also the **DB connection alias** in the workspace (`_db/{apiName}/`) |
|
|
177
|
+
| `auth` | Add when SP has `AUTH_` (no token) |
|
|
178
|
+
| `FunctionName` | SP name after the prefix |
|
|
179
|
+
| `url1`, `url2`... | Route params for `@url1_`, `@url2_` |
|
|
245
180
|
|
|
246
|
-
**
|
|
181
|
+
**A project can have MANY `apiName`s** (one DB alias each). `"API": "/{alias}/Ten"` in module.json names the SP's database; fui uses that alias for `_db/{alias}/` and as `--db` of DB commands ([db-workflow.md](db-workflow.md) §1, §4).
|
|
247
182
|
|
|
248
183
|
```
|
|
249
184
|
SP: spAPI_AUTH_Select_Chat
|
|
@@ -256,8 +191,7 @@ SP: spAPI_GetStudentDetail (@url1_StudentID)
|
|
|
256
191
|
URL: https://api.example.vn/me/GetStudentDetail/SV001
|
|
257
192
|
```
|
|
258
193
|
|
|
259
|
-
> **CRITICAL —
|
|
260
|
-
> `domain` KHÔNG BAO GIỜ tự có dấu `/` ở cuối — phải tự chèn đúng MỘT dấu `/` trước `apiName` khi ghép. Gõ tắt bằng tay rất dễ dính lỗi này vì mắt đọc lướt không phân biệt được đâu là phần domain, đâu là phần apiName trong một chuỗi liền.
|
|
194
|
+
> **CRITICAL — common bug: missing `/` between `domain` and `apiName`.** `domain` NEVER ends with `/`; insert exactly ONE `/` before `apiName`.
|
|
261
195
|
>
|
|
262
196
|
> ```
|
|
263
197
|
> domain=tapi.lhu.edu.vn, apiName=ts, function=TS_Report_HeXetTuyenSelectAll
|
|
@@ -266,32 +200,30 @@ URL: https://api.example.vn/me/GetStudentDetail/SV001
|
|
|
266
200
|
> ✅ ĐÚNG: https://tapi.lhu.edu.vn/ts/TS_Report_HeXetTuyenSelectAll
|
|
267
201
|
> ```
|
|
268
202
|
>
|
|
269
|
-
>
|
|
203
|
+
> **Don't build URLs by hand/memory** — copy the `Wiring URL: ...` line from `fui sp verify` (or `fui sp help`) verbatim.
|
|
270
204
|
|
|
271
|
-
### 3.1
|
|
205
|
+
### 3.1 Param cache & `/help` route
|
|
272
206
|
|
|
273
|
-
tAPI **
|
|
274
|
-
|
|
275
|
-
Route xoá cache = URL gọi API thật, chèn thêm `/help` ngay sau domain (trước `apiName`):
|
|
207
|
+
tAPI **caches each function's param signature** after the first call. After ALTERing a `spAPI_*`/`spAPIFILE_*` SP's params (add/remove/rename/retype), the live endpoint keeps the **old** signature until cleared. Route = API URL with `/help` right after domain:
|
|
276
208
|
|
|
277
209
|
```
|
|
278
210
|
{domain}/help/{apiName}/{FunctionName} ← xoá cache + trả về tham số của hàm
|
|
279
211
|
{domain}/help/{apiName}/auth/{FunctionName}
|
|
280
212
|
```
|
|
281
213
|
|
|
282
|
-
|
|
214
|
+
It **(a) clears the cache** and **(b) returns the input params** (useful before wiring `IN`).
|
|
215
|
+
|
|
216
|
+
**Mandatory after every SP ALTER/UPDATE** (else old signature → param errors even with a correct SP):
|
|
283
217
|
|
|
284
|
-
|
|
285
|
-
-
|
|
286
|
-
-
|
|
287
|
-
- Không xoá cache → endpoint thật tiếp tục phục vụ theo chữ ký **cũ**, có thể gây lỗi tham số ngay cả khi SP đã đúng.
|
|
288
|
-
- **`/help` báo lỗi thì DỪNG, không thử URL biến thể.** Dạng URL (`/auth/` hay không) suy ra từ tên SP, không phải thứ để đoán; thử qua lại chỉ tốn lượt mà không đổi kết quả. Chỉ quay lại `db_sp_help` khi endpoint thật thực sự còn nhận tham số cũ.
|
|
218
|
+
- `fui sp deploy` auto-calls `/help` **once, standard URL; ignore failure** (SP is already deployed).
|
|
219
|
+
- `ALTER PROCEDURE` via `fui exec`: **no auto-clear → run `fui sp help` manually** right after. The only manual case.
|
|
220
|
+
- **`/help` errors → STOP, no URL variants.** `/auth/` or not follows from the SP name; retrying changes nothing. Re-run `fui sp help` only if the live endpoint truly still takes old params.
|
|
289
221
|
|
|
290
222
|
---
|
|
291
223
|
|
|
292
|
-
## 4.
|
|
224
|
+
## 4. Response format
|
|
293
225
|
|
|
294
|
-
### 4.1
|
|
226
|
+
### 4.1 One SELECT → array
|
|
295
227
|
|
|
296
228
|
```sql
|
|
297
229
|
SELECT StudentID, FullName, GPA FROM tblStudent WHERE ClassID = @ClassID
|
|
@@ -301,14 +233,14 @@ SELECT StudentID, FullName, GPA FROM tblStudent WHERE ClassID = @ClassID
|
|
|
301
233
|
{
|
|
302
234
|
"data": [
|
|
303
235
|
{ "StudentID": "SV001", "FullName": "Nguyen Van A", "GPA": 3.5 },
|
|
304
|
-
{ "StudentID": "SV002", "FullName": "Tran Thi B",
|
|
236
|
+
{ "StudentID": "SV002", "FullName": "Tran Thi B", "GPA": 3.2 }
|
|
305
237
|
]
|
|
306
238
|
}
|
|
307
239
|
```
|
|
308
240
|
|
|
309
|
-
### 4.2
|
|
241
|
+
### 4.2 Multiple SELECTs → array of arrays
|
|
310
242
|
|
|
311
|
-
|
|
243
|
+
Each `SELECT` becomes one sub-array in `data`:
|
|
312
244
|
|
|
313
245
|
```sql
|
|
314
246
|
SELECT TotalCount = COUNT(*) FROM tblStudent WHERE ClassID = @ClassID
|
|
@@ -327,23 +259,23 @@ SELECT StudentID, FullName FROM tblStudent WHERE ClassID = @ClassID
|
|
|
327
259
|
}
|
|
328
260
|
```
|
|
329
261
|
|
|
330
|
-
|
|
262
|
+
In module.json, read sub-arrays by index:
|
|
263
|
+
|
|
331
264
|
```json
|
|
332
265
|
"OUT": "studentList",
|
|
333
266
|
"CALLBACK": { "EXE": "vueData.total = vueData.studentList[0][0].TotalCount; vueData.students = vueData.studentList[1]" }
|
|
334
267
|
```
|
|
335
268
|
|
|
336
|
-
### 4.3 `convert_to_object` —
|
|
269
|
+
### 4.3 `convert_to_object` — row → object
|
|
337
270
|
|
|
338
|
-
|
|
271
|
+
Returns an object instead of an array. **Many SELECTs** may use it; all merge into one response object.
|
|
339
272
|
|
|
340
|
-
> ⚠️
|
|
273
|
+
> ⚠️ When a SELECT has `convert_to_object` **and** a `json_data` column with a JSON string, it must return **exactly 1 row**. More than 1 → tAPI returns `{}`.
|
|
341
274
|
|
|
342
|
-
|
|
343
|
-
- `convert_to_object = '
|
|
344
|
-
- `convert_to_object = ''` → merge thẳng vào root object
|
|
275
|
+
- `convert_to_object = 'key'` → nested object under that key
|
|
276
|
+
- `convert_to_object = ''` → merged into root
|
|
345
277
|
|
|
346
|
-
**
|
|
278
|
+
**Ex 1 — named key + root merge:**
|
|
347
279
|
|
|
348
280
|
```sql
|
|
349
281
|
SELECT convert_to_object = 'sinhvien',
|
|
@@ -365,7 +297,7 @@ SELECT convert_to_object = '',
|
|
|
365
297
|
}
|
|
366
298
|
```
|
|
367
299
|
|
|
368
|
-
**
|
|
300
|
+
**Ex 2 — `json_data` overrides same-name fields** (parsed and merged after SQL columns, so `json_data` wins, e.g. `ProjectName`):
|
|
369
301
|
|
|
370
302
|
```sql
|
|
371
303
|
SELECT convert_to_object = '',
|
|
@@ -385,9 +317,7 @@ SELECT convert_to_object = '',
|
|
|
385
317
|
}
|
|
386
318
|
```
|
|
387
319
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
**Ví dụ 3 — Nhiều SELECT cùng `convert_to_object = ''` đều merge vào root:**
|
|
320
|
+
**Ex 3 — multiple `convert_to_object = ''` SELECTs all merge into root:**
|
|
391
321
|
|
|
392
322
|
```sql
|
|
393
323
|
SELECT convert_to_object = '',
|
|
@@ -412,18 +342,16 @@ SELECT convert_to_object = '',
|
|
|
412
342
|
}
|
|
413
343
|
```
|
|
414
344
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
### 4.4 `[json_data:FieldName]` — Convert chuỗi JSON thành object
|
|
345
|
+
### 4.4 `[json_data:FieldName]` — JSON string column → object
|
|
418
346
|
|
|
419
|
-
|
|
347
|
+
Return a JSON-string column as an object:
|
|
420
348
|
|
|
421
349
|
```sql
|
|
422
350
|
SELECT PartID, PartName, [json_data:FileInfo] = FileInfo
|
|
423
351
|
FROM tblPart WHERE PartID = @url1_PartID
|
|
424
352
|
```
|
|
425
353
|
|
|
426
|
-
tAPI
|
|
354
|
+
tAPI parses it into a nested object:
|
|
427
355
|
|
|
428
356
|
```json
|
|
429
357
|
{
|
|
@@ -433,17 +361,15 @@ tAPI tự động parse cột có alias `json_data:FieldName` thành nested JSON
|
|
|
433
361
|
}
|
|
434
362
|
```
|
|
435
363
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
> Tên sau dấu `:` (`FileInfo`) là tên field trong response. Tên cột SQL (`FileInfo` trong `= FileInfo`) là tên cột thực trên bảng.
|
|
364
|
+
DB column stays a string. Name after `:` = response field; after `=` = real column.
|
|
439
365
|
|
|
440
366
|
---
|
|
441
367
|
|
|
442
|
-
## 5.
|
|
368
|
+
## 5. Error handling in SP
|
|
443
369
|
|
|
444
|
-
|
|
370
|
+
All errors use `RAISERROR` with severity **16**.
|
|
445
371
|
|
|
446
|
-
###
|
|
372
|
+
### Normal errors (validation, data constraints)
|
|
447
373
|
|
|
448
374
|
```sql
|
|
449
375
|
RAISERROR(N'Dữ liệu không hợp lệ', 16, 1)
|
|
@@ -454,7 +380,7 @@ RETURN
|
|
|
454
380
|
{ "Message": "Dữ liệu không hợp lệ" }
|
|
455
381
|
```
|
|
456
382
|
|
|
457
|
-
###
|
|
383
|
+
### Unauthorized — prefix `[Unauthorized]` → HTTP 401
|
|
458
384
|
|
|
459
385
|
```sql
|
|
460
386
|
IF @sys_SystemRight < 2
|
|
@@ -468,34 +394,33 @@ END
|
|
|
468
394
|
{ "Message": "Bạn không có quyền trên chức năng này." }
|
|
469
395
|
```
|
|
470
396
|
|
|
471
|
-
**
|
|
472
|
-
- Luôn dùng severity `16` — không dùng `11`, `14`, hay giá trị khác
|
|
473
|
-
- Luôn có `RETURN` ngay sau `RAISERROR` để dừng SP
|
|
474
|
-
- Prefix `N` bắt buộc cho Unicode tiếng Việt
|
|
475
|
-
- **Mọi lỗi liên quan đến quyền (thiếu `SystemRight`/`FunctionRight`) phải mở message bằng `[Unauthorized]`** — tAPI đọc chuỗi này để trả HTTP status `401` thay vì `200`/`500` mặc định; client (`errorMess()` trong `fastproject.js`) rẽ nhánh xử lý riêng theo status `401` (redirect login nếu message chứa "token", ngược lại hiện lỗi quyền). tAPI tự cắt `[Unauthorized]` khỏi `Message` trả về client — text người dùng thấy không có tiền tố này. Lỗi validation/ràng buộc dữ liệu thông thường (ví dụ trên) **không** dùng prefix này.
|
|
397
|
+
**Mandatory:**
|
|
476
398
|
|
|
477
|
-
|
|
399
|
+
- Always severity `16` — never `11`, `14` or anything else.
|
|
400
|
+
- Always `RETURN` right after `RAISERROR`.
|
|
401
|
+
- `N` prefix required for Vietnamese Unicode.
|
|
402
|
+
- **Every permission error (missing `SystemRight`/`FunctionRight`) must start with `[Unauthorized]`** → HTTP `401` instead of `200`/`500`; client `errorMess()` (`fastproject.js`) redirects to login if message contains "token", else shows a permission error. tAPI strips the prefix from `Message`. Validation errors **don't** use it.
|
|
403
|
+
|
|
404
|
+
> Detailed permission checks (5 patterns, `getSystemRight`, check order, message conventions): [tapi-permission-patterns.md](tapi-permission-patterns.md).
|
|
478
405
|
|
|
479
406
|
---
|
|
480
407
|
|
|
481
|
-
## 6.
|
|
408
|
+
## 6. SP design rules
|
|
482
409
|
|
|
483
|
-
###
|
|
410
|
+
### Naming
|
|
484
411
|
|
|
485
412
|
```
|
|
486
413
|
spAPI_{Entity}{Action}
|
|
487
414
|
```
|
|
488
415
|
|
|
489
|
-
| Action
|
|
490
|
-
|
|
491
|
-
| `Select` / `List`
|
|
492
|
-
| `Get`
|
|
493
|
-
| `Insert` / `Add`
|
|
494
|
-
| `Update` / `Edit`
|
|
495
|
-
| `Delete` / `Remove` |
|
|
496
|
-
| `AUTH_Select`
|
|
497
|
-
|
|
498
|
-
**Ví dụ chuẩn:**
|
|
416
|
+
| Action | Meaning |
|
|
417
|
+
| ------------------- | ----------------------- |
|
|
418
|
+
| `Select` / `List` | List query |
|
|
419
|
+
| `Get` | One record's detail |
|
|
420
|
+
| `Insert` / `Add` | Create |
|
|
421
|
+
| `Update` / `Edit` | Update |
|
|
422
|
+
| `Delete` / `Remove` | Delete |
|
|
423
|
+
| `AUTH_Select` | Public query (no token) |
|
|
499
424
|
|
|
500
425
|
```sql
|
|
501
426
|
spAPI_StudentList -- GET danh sách sinh viên
|
|
@@ -506,7 +431,7 @@ spAPI_StudentDelete -- POST xoá (url1 = StudentID)
|
|
|
506
431
|
spAPI_AUTH_CourseList -- Danh sách môn học công khai
|
|
507
432
|
```
|
|
508
433
|
|
|
509
|
-
### Wiring
|
|
434
|
+
### Wiring in FUI module.json
|
|
510
435
|
|
|
511
436
|
```json
|
|
512
437
|
"fetchStudents": {
|
|
@@ -532,18 +457,18 @@ spAPI_AUTH_CourseList -- Danh sách môn học công khai
|
|
|
532
457
|
|
|
533
458
|
---
|
|
534
459
|
|
|
535
|
-
## 7.
|
|
536
|
-
|
|
537
|
-
1.
|
|
538
|
-
2.
|
|
539
|
-
3. `@sys_UserID`
|
|
540
|
-
4.
|
|
541
|
-
5.
|
|
542
|
-
6.
|
|
543
|
-
7.
|
|
544
|
-
8. **
|
|
545
|
-
9. **
|
|
546
|
-
9b.
|
|
547
|
-
9c. **
|
|
548
|
-
10. **File GET/UPLOAD**: prefix `spAPIFILE_`,
|
|
549
|
-
11. **
|
|
460
|
+
## 7. SP design checklist
|
|
461
|
+
|
|
462
|
+
1. `spAPI_` prefix mandatory — missing means API can't call it.
|
|
463
|
+
2. Add `AUTH_` for public endpoints (login page, lookup data).
|
|
464
|
+
3. Always include `@sys_UserID` in SPs that write data (audit trail).
|
|
465
|
+
4. No `SELECT *` — list columns.
|
|
466
|
+
5. Check permissions at SP start if needed, with `RAISERROR` + `RETURN` — see [tapi-permission-patterns.md](tapi-permission-patterns.md).
|
|
467
|
+
6. Multiple SELECTs → client reads by index `data[0]`, `data[1]`.
|
|
468
|
+
7. Single record → use `convert_to_object` instead of `data[0][0]`.
|
|
469
|
+
8. **No `GRANT EXECUTE` in the .sql file** — the SP body runs to end of batch and tAPI has no `GO` support, so a GRANT after `END` is **swallowed into the SP body** (runs every call, grants nothing, no error). `fui sp deploy` grants and confirms via `sys.database_permissions` — read its `✓`/`❗` line ([verification.md](verification.md#security)).
|
|
470
|
+
9. **Never put `sys_*` params in module.json `IN`** — tAPI injects them.
|
|
471
|
+
9b. **Headers** → `@sys_header_{HeaderName}`, **each `-` → `_`**; `-` is a syntax error, brackets don't help (§2). Log only, never gate permissions.
|
|
472
|
+
9c. **Binding never errors** (missing → `NULL`, extra → ignored): check `IN` names with `fui sp help`. `DEFAULT` is useless; use `SET @x = ISNULL(@x, <giá trị>)`.
|
|
473
|
+
10. **File GET/UPLOAD**: prefix `spAPIFILE_`, binary column alias `fileContent`, params `@sys_FileContent`/`@sys_FileName`, standard table `tblFileData` — see [tapi-file-api.md](tapi-file-api.md). Don't infer from training data.
|
|
474
|
+
11. **Any ALTER/UPDATE of a deployed SP** (params, logic, anything) → **MUST clear tAPI cache** via `fui sp help` (§3.1). `fui sp deploy` does it (once; ignore failure); only ALTER via `fui exec` needs it manually.
|