You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AGENTS.md
+89-66Lines changed: 89 additions & 66 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,9 +12,9 @@ There are two main components:
12
12
## Build System
13
13
14
14
-**Build tool**: Apache Maven via Maven Wrapper (`./mvnw`)
15
-
-**Java target**: Source and target compatibility is Java 1.8 (OpenJDK 8+)
16
-
-**Group ID**: `com.slack.api`
17
-
-**Current version**: Check`<version>` in root `pom.xml`
15
+
-**Java target**: Source and target compatibility is Java 1.8 (OpenJDK 8+) — see `pom.xml` properties `maven.compiler.source` and `maven.compiler.target`
16
+
-**Group ID**: `com.slack.api` — see `pom.xml``<groupId>`
17
+
-**Current version**: See`<version>` in root `pom.xml` (also reflected in `*LibraryVersion.java` files generated by `scripts/set_version.sh`)
18
18
19
19
### Key Commands
20
20
@@ -50,7 +50,7 @@ Some modules are excluded on JDK 8 (Jakarta EE modules, GCF, Helidon, http4k, Mi
50
50
51
51
## Module Architecture
52
52
53
-
All published modules use group ID `com.slack.api` and are released to Maven Central simultaneously.
53
+
All published modules use group ID `com.slack.api`(see `pom.xml``<groupId>`) and are released to Maven Central simultaneously. The complete list of modules is defined in root `pom.xml``<modules>` section.
54
54
55
55
### Foundation Modules
56
56
@@ -131,39 +131,43 @@ All published modules use group ID `com.slack.api` and are released to Maven Cen
131
131
132
132
## Key Dependencies
133
133
134
-
| Library | Version Property | Notes |
135
-
|---------|-----------------|-------|
136
-
| OkHttp |`okhttp.version` (4.x) | HTTP client |
134
+
All dependency versions are managed in root `pom.xml``<properties>` section.
135
+
136
+
| Library | Version Property | Notes |
137
+
|---------|------------------|-------|
138
+
| OkHttp |`okhttp.version`| HTTP client |
137
139
| Gson |`gson.version`| JSON serialization; uses `LOWER_CASE_WITH_UNDERSCORES` field naming via `GsonFactory.createSnakeCase()`|
138
-
| SLF4J |`slf4j.version`(1.7.x) | Logging facade. **Do not upgrade to v2** - see issue #1034|
140
+
| SLF4J |`slf4j.version`| Logging facade. **Do not upgrade to v2** - see issue #1034|
139
141
| Lombok |`lombok.version`| Used extensively for `@Data`, `@Builder`, `@Slf4j`|
140
-
| Kotlin |`kotlin.version`(1.9.x) | API/language version pinned to 1.6 for backward compat |
141
-
| JUnit |`junit.version`(4.x) |**JUnit 4, not 5**|
| Hamcrest |`hamcrest.version`| Used for test assertions |
144
146
147
+
**Note**: Always check `pom.xml``<properties>` for actual current versions.
148
+
145
149
## Code Conventions
146
150
147
151
### Java Style
148
152
149
-
-**Java 8 compatibility is mandatory**. Do not use Java 9+ APIs (e.g., `List.of()`, `Map.of()`, `var`, `HttpClient`, text blocks).
153
+
-**Java 8 compatibility is mandatory** (see `pom.xml``maven.compiler.source` and `maven.compiler.target` = 1.8). Do not use Java 9+ APIs (e.g., `List.of()`, `Map.of()`, `var`, `HttpClient`, text blocks).
150
154
- Lombok annotations are used pervasively: `@Data`, `@Builder`, `@Slf4j`, `@EqualsAndHashCode(callSuper = false)`.
151
-
- JSON field naming uses **snake_case** via Gson's `LOWER_CASE_WITH_UNDERSCORES` policy. Java fields are camelCase.
155
+
- JSON field naming uses **snake_case** via Gson's `LOWER_CASE_WITH_UNDERSCORES` policy (see `slack-api-client/src/main/java/com/slack/api/util/json/GsonFactory.java`). Java fields are camelCase.
152
156
- Logging uses SLF4J via Lombok's `@Slf4j` (gives you a `log` field).
153
157
- Checked exceptions: API methods throw `IOException` and `SlackApiException`.
154
158
155
159
### Naming Conventions
156
160
157
-
- Request classes: `{MethodName}Request` with `@Data @Builder` and implementing `SlackApiRequest`
158
-
- Response classes: `{MethodName}Response` with `@Data` and implementing `SlackApiTextResponse`
159
-
- API method constants: `Methods.java` has `public static final String` for each API method (e.g., `USERS_INFO = "users.info"`)
161
+
- Request classes: `{MethodName}Request` with `@Data @Builder` and implementing `SlackApiRequest` (see `slack-api-client/src/main/java/com/slack/api/methods/SlackApiRequest.java`)
162
+
- Response classes: `{MethodName}Response` with `@Data` and implementing `SlackApiTextResponse` (see `slack-api-client/src/main/java/com/slack/api/methods/SlackApiTextResponse.java`)
163
+
- API method constants: `Methods.java` has `public static final String` for each API method (e.g., `USERS_INFO = "users.info"`) — see `slack-api-client/src/main/java/com/slack/api/methods/Methods.java`
160
164
- Test packages: `test_locally` for CI-safe tests, `test_with_remote_apis` for integration tests needing tokens
161
165
162
166
### JSON Serialization
163
167
164
-
- Use `GsonFactory.createSnakeCase()` for most Slack APIs (snake_case JSON keys)
168
+
- Use `GsonFactory.createSnakeCase()` for most Slack APIs (snake_case JSON keys with `LOWER_CASE_WITH_UNDERSCORES` policy)
165
169
- Use `GsonFactory.createCamelCase()` for SCIM APIs
166
-
- The factory is in `slack-api-client/src/main/java/com/slack/api/util/json/GsonFactory.java`
170
+
- The factory implementation is in `slack-api-client/src/main/java/com/slack/api/util/json/GsonFactory.java`
167
171
168
172
## Model Types (`slack-api-model`)
169
173
@@ -219,7 +223,7 @@ public class ChannelCreatedEvent implements Event {
219
223
220
224
- Use `@Data`, `@Builder`, `@NoArgsConstructor`, `@AllArgsConstructor`, `@EqualsAndHashCode(callSuper = false)` on concrete types.
221
225
- Define `public static final String TYPE` (or `TYPE_NAME`) and `private final String type = TYPE;`.
222
-
- Java fields are camelCase; Gson's `LOWER_CASE_WITH_UNDERSCORES` policy maps them to snake_case JSON automatically.
226
+
- Java fields are camelCase; Gson's `LOWER_CASE_WITH_UNDERSCORES` policy (see `GsonFactory.java`) maps them to snake_case JSON automatically.
223
227
- Use `@SerializedName` only when the Slack API field name does not follow snake_case convention.
224
228
- Do **not** initialize `List` fields to empty collections — Slack sometimes returns errors with empty arrays, and null vs empty has semantic meaning.
225
229
@@ -299,41 +303,13 @@ public class ConversationsRequestSharedInviteApproveRequest implements SlackApiR
299
303
}
300
304
```
301
305
302
-
A simpler request class (for `conversations.requestSharedInvite.deny`):
* ID of the requested shared channel invite to deny.
322
-
*/
323
-
privateString inviteId;
324
-
325
-
/**
326
-
* Optional message explaining why the request to invite was denied.
327
-
*/
328
-
privateString message;
329
-
}
330
-
```
306
+
For simpler methods without nested objects, the same pattern applies but without the inner `@Data` classes (e.g., `ConversationsRequestSharedInviteDenyRequest` has only `token`, `inviteId`, and `message` fields).
The response class implements `SlackApiTextResponse` and uses `@Data`. Every response must include the standard fields (`ok`, `warning`, `error`, `needed`, `provided`, `httpResponseHeaders`). Add any method-specific response fields from the API docs:
312
+
The response class implements `SlackApiTextResponse` and uses `@Data`. Every response must include the standard fields defined by the `SlackApiTextResponse` interface (`ok`, `warning`, `error`, `needed`, `provided`, `httpResponseHeaders`). Add any method-specific response fields from the API docs:
Look up the rate limit tier from the API docs and add a `setRateLimitTier` call in the appropriate alphabetical position:
442
+
Look up the rate limit tier from the API docs (or check `metadata/web-api/rate_limit_tiers.json` for existing patterns) and add a `setRateLimitTier` call in the appropriate alphabetical position:
Add the method name and its tier in alphabetical order within the JSON object:
453
+
Add the method name and its tier in alphabetical order within the JSON object. This file is the source of truth for rate limit tiers and should match the tier set in `MethodsRateLimits.java`:
The `MockSlackApiServer` used in tests serves mock responses from JSON files in this directory. Every API method **must** have a corresponding JSON fixture file, or tests will fail with `NoSuchFileException` / HTTP 500. The file name is the full API method name with dots (e.g., `conversations.requestSharedInvite.approve.json`).
465
+
466
+
The mock server reads these files and replaces `"ok": false,` with `"ok": true,` automatically, so the fixture should always have `"ok": false`. See existing files in this directory for examples:
467
+
468
+
```json
469
+
{
470
+
"ok": false,
471
+
"error": "",
472
+
"needed": "",
473
+
"provided": "",
474
+
"warning": ""
475
+
}
476
+
```
477
+
478
+
### 13. Add tests and update `MethodsTest`
485
479
486
480
#### Add method-specific tests
487
481
488
-
File: `slack-api-client/src/test/java/test_locally/api/methods/ConversationsTest.java` (or the relevant existing test file for the API category)
482
+
File: `slack-api-client/src/test/java/test_locally/api/methods/{Category}Test.java` (the test file matching the top-level API namespace, e.g., `AppsTest.java` for `apps.*`, `ConversationsTest.java` for `conversations.*`)
489
483
490
484
Test both sync and async variants using the configurator lambda pattern:
491
485
@@ -507,25 +501,54 @@ public void conversationsRequestSharedInviteApprove_async() throws Exception {
This test validates that every known Slack API method has a corresponding `Methods.java` constant and rate limit entry. Update the `methods` string and the endpoint count comment to include the new method names. If the method names are not already in the list, add them in the correct alphabetical position.
504
+
This test validates that every known Slack API method has a corresponding constant in `Methods.java` and rate limit entry in `metadata/web-api/rate_limit_tiers.json`. Update the `methods` string and the endpoint count comment to include the new method names. If the method names are not already in the list, add them in the correct alphabetical position.
505
+
506
+
### 14. Add imports to all modified files
507
+
508
+
Each file that references the new Request and Response classes needs corresponding import statements. When modifying the following files, add imports for both the new Request and Response classes:
509
+
510
+
-`MethodsClient.java` — import both `request` and `response` classes
511
+
-`AsyncMethodsClient.java` — import both `request` and `response` classes
512
+
-`MethodsClientImpl.java` — import both `request` and `response` classes
513
+
-`AsyncMethodsClientImpl.java` — import both `request` and `response` classes
514
+
-`RequestFormBuilder.java` — import the `request` class only
515
+
516
+
Place each new import adjacent to the existing imports from the same `apps.*` (or equivalent) package, in alphabetical order.
517
+
518
+
### 15. Verify
519
+
520
+
Before considering the work complete, run the tests. The `slack-api-client` module depends on `slack-api-model`, so you must install all modules locally first if they haven't been built yet:
521
+
522
+
```bash
523
+
# Install all modules locally (required before running single-module tests)
524
+
./scripts/install_local.sh
525
+
526
+
# Run the specific tests for the new method and the coverage test
527
+
./mvnw test -pl slack-api-client '-Dtest=test_locally.api.methods.AppsTest,test_locally.api.MethodsTest'
528
+
```
529
+
530
+
Note: `install_local.sh` may fail on unrelated example modules (e.g., `bolt-quarkus-examples`). This is fine as long as `slack-api-client` and its dependencies (`slack-api-model`) install successfully.
511
531
512
532
### Summary checklist
513
533
514
534
When adding a new Slack API method, make sure you have:
515
535
516
536
-[ ] Looked up the method docs at `https://docs.slack.dev/reference/methods/{method.name}`
517
-
-[ ] Added the method constant in `Methods.java`
518
-
-[ ] Created the Request class in `request/{category}/`
519
-
-[ ] Created the Response class in `response/{category}/`
520
-
-[ ] Added two overloads in `MethodsClient.java`
521
-
-[ ] Added two overloads in `AsyncMethodsClient.java`
522
-
-[ ] Implemented both overloads in `MethodsClientImpl.java`
523
-
-[ ] Implemented both overloads in `AsyncMethodsClientImpl.java`
524
-
-[ ] Added `toForm()` in `RequestFormBuilder.java`
525
-
-[ ] Added rate limit tier in `MethodsRateLimits.java`
537
+
-[ ] Added the method constant in `slack-api-client/src/main/java/com/slack/api/methods/Methods.java`
538
+
-[ ] Created the Request class in `slack-api-client/src/main/java/com/slack/api/methods/request/{category}/`
539
+
-[ ] Created the Response class in `slack-api-client/src/main/java/com/slack/api/methods/response/{category}/`
540
+
-[ ] Added two overloads in `slack-api-client/src/main/java/com/slack/api/methods/MethodsClient.java`
541
+
-[ ] Added two overloads in `slack-api-client/src/main/java/com/slack/api/methods/AsyncMethodsClient.java`
542
+
-[ ] Implemented both overloads in `slack-api-client/src/main/java/com/slack/api/methods/impl/MethodsClientImpl.java`
543
+
-[ ] Implemented both overloads in `slack-api-client/src/main/java/com/slack/api/methods/impl/AsyncMethodsClientImpl.java`
544
+
-[ ] Added `toForm()` in `slack-api-client/src/main/java/com/slack/api/methods/RequestFormBuilder.java`
545
+
-[ ] Added rate limit tier in `slack-api-client/src/main/java/com/slack/api/methods/MethodsRateLimits.java`
526
546
-[ ] Added rate limit entry in `metadata/web-api/rate_limit_tiers.json`
527
-
-[ ] Added sync and async tests in `test_locally/api/methods/`
528
-
-[ ] Updated the endpoint list and count in `MethodsTest.java`
547
+
-[ ] Created mock server JSON fixture in `json-logs/samples/api/{method.name}.json`
548
+
-[ ] Added sync and async tests in `slack-api-client/src/test/java/test_locally/api/methods/{Category}Test.java`
549
+
-[ ] Updated the endpoint list and count in `slack-api-client/src/test/java/test_locally/api/MethodsTest.java`
550
+
-[ ] Added import statements for the new Request/Response classes in all modified files
551
+
-[ ] Verified tests pass: `./mvnw test -pl slack-api-client '-Dtest=test_locally.api.methods.{Category}Test,test_locally.api.MethodsTest'`
529
552
530
553
## Testing
531
554
@@ -587,7 +610,7 @@ Releases publish all modules simultaneously to Maven Central via Sonatype.
587
610
588
611
-**Snapshot**: Version must end with `-SNAPSHOT`. Run `scripts/set_version.sh 1.x.y-SNAPSHOT` then `scripts/release.sh`
589
612
-**Stable**: Run `scripts/set_version.sh 1.x.y` then `scripts/release.sh`. Requires JDK 17, GPG signing, and Sonatype credentials in `~/.m2/settings.xml`
590
-
- Version is set across all `pom.xml` files AND three generated version classes:
613
+
- Version is set across all `pom.xml` files AND three generated version classes (generated by `scripts/set_version.sh`):
0 commit comments