Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions .github/PROMOTIONAL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Promotional Materials for ymsdk

Ready-to-post content for promoting ymsdk across platforms.

---

## Reddit r/golang Post

**Title:** ymsdk — Lightweight Go SDK for Yandex Messenger Bot API

**Body:**

Hi everyone! I'd like to share **ymsdk** — a Go SDK for the Yandex Messenger Bot API.

### Why another messenger SDK?

Yandex Messenger is widely used across CIS companies, but had no proper Go SDK with modern patterns. ymsdk fills this gap with:

- **Type-safe models** — `ChatID`, `UserLogin`, `MessageID` prevent mix-ups at compile time
- **Automatic retry** — exponential backoff with configurable strategy
- **Rate limit handling** — respects `Retry-After` headers automatically
- **Service-oriented architecture** — separate packages for messages, chats, polls, updates, files, users
- **Minimal deps** — only `go.uber.org/zap` for structured logging
- **Debug middleware** — full HTTP request/response inspection

### Quick example

```go
cs := client.New(ym.Config{Token: os.Getenv("YM_TOKEN")})
msg, err := cs.Messages.SendToChat(ctx, chatID, "Hello!", nil)
```

Links:
- GitHub: https://github.com/rekurt/ymsdk
- pkg.go.dev: https://pkg.go.dev/github.com/rekurt/ymsdk
- Go Report Card: https://goreportcard.com/report/github.com/rekurt/ymsdk

Feedback and contributions welcome!

---

## Dev.to / Habr Article Draft

**Title:** Building a Type-Safe Go SDK for Yandex Messenger Bot API

**Tags:** go, golang, sdk, yandex, bot, messenger

**Outline:**

1. **Introduction** — Why Yandex Messenger needs a Go SDK
2. **Architecture** — Service-oriented design, dependency injection via `*ym.Client`
3. **Type Safety** — How distinct type aliases (`ChatID`, `UserLogin`) prevent bugs
4. **Retry & Rate Limiting** — Exponential backoff implementation, `Retry-After` handling
5. **Error Handling** — `APIError` with `ErrorKind`, sentinel errors, `errors.Is/As` patterns
6. **Debug Logging** — Middleware architecture with zap, HTTP body inspection
7. **Getting Started** — Code examples with aggregator and individual services
8. **Testing** — `FakeDoer` mock pattern, table-driven tests
9. **Conclusion** — Links, call for contributions

---

## Twitter/X Post

ymsdk — lightweight Go SDK for Yandex Messenger Bot API 🤖

✅ Type-safe models
✅ Auto retry with exponential backoff
✅ Rate limit handling
✅ Service-oriented architecture
✅ MIT licensed

github.com/rekurt/ymsdk

#golang #go #sdk #yandex #bot #opensource

---

## Telegram Post (for Go communities)

🚀 **ymsdk** — Go SDK для Yandex Messenger Bot API

Типобезопасные модели, автоматический retry с exponential backoff, обработка rate limit, сервис-ориентированная архитектура.

```go
cs := client.New(ym.Config{Token: os.Getenv("YM_TOKEN")})
msg, _ := cs.Messages.SendToChat(ctx, chatID, "Hello!", nil)
```

🔗 GitHub: github.com/rekurt/ymsdk
📖 Docs: pkg.go.dev/github.com/rekurt/ymsdk

MIT • Minimal deps • 50+ linters CI

---

## LinkedIn Post

I'm excited to share **ymsdk** — an open-source Go SDK for the Yandex Messenger Bot API.

As Yandex Messenger grows in adoption across enterprises, developers need reliable tools to build integrations. ymsdk provides:

• Type-safe API with compile-time safety
• Automatic retry with exponential backoff
• Rate limit handling respecting Retry-After headers
• Service-oriented architecture for clean separation
• Comprehensive error handling with structured error types
• Debug middleware for HTTP inspection

The SDK follows Go community best practices: minimal dependencies, table-driven tests, 50+ linter rules, and full pkg.go.dev documentation.

Check it out: https://github.com/rekurt/ymsdk

#golang #opensource #sdk #yandex #development
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ jobs:
name: coverage-report
path: coverage.out

- name: Upload to Codecov
uses: codecov/codecov-action@v5
with:
files: coverage.out
fail_ci_if_error: false

build:
name: Build
runs-on: ubuntu-latest
Expand Down
44 changes: 44 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- Package-level documentation (`doc.go`) for all service subpackages
- Example tests for pkg.go.dev documentation
- Codecov integration for test coverage reporting
- CONTRIBUTING.md, CODE_OF_CONDUCT.md, SECURITY.md
- GitHub Issue and PR templates
- Features section in README (RU + EN)
- CI/CD/coverage badges in README

### Fixed
- `Update.ToMessage` nil dereference on missing fields
- Webhook example request validation hardened

## [0.0.2] - 2025-12-08

### Added
- MIT License
- Go version upgrade to 1.25.1
- pkg.go.dev documentation links

## [0.0.1] - 2025-12-08

### Added
- Initial release of Yandex Messenger Bot API Go SDK
- Core HTTP client with retry logic and exponential backoff
- Service-oriented architecture: messages, chats, polls, updates, users, files, self
- Type-safe models: `ChatID`, `UserLogin`, `MessageID`, `ThreadID`, `PollID`
- Error handling with `APIError`, sentinel errors, rate limit support
- Polling and webhook update modes
- Debug logging middleware with zap integration
- 6 runnable examples: basic_send, poller, poll_bot, webhook, integration, debug_logger

[Unreleased]: https://github.com/rekurt/ymsdk/compare/v0.0.2...HEAD
[0.0.2]: https://github.com/rekurt/ymsdk/compare/v0.0.1...v0.0.2
[0.0.1]: https://github.com/rekurt/ymsdk/releases/tag/v0.0.1
1 change: 1 addition & 0 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
[![Go Report Card](https://goreportcard.com/badge/github.com/rekurt/ymsdk)](https://goreportcard.com/report/github.com/rekurt/ymsdk)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Go Version](https://img.shields.io/github/go-mod/go-version/rekurt/ymsdk)](go.mod)
[![codecov](https://codecov.io/gh/rekurt/ymsdk/branch/master/graph/badge.svg)](https://codecov.io/gh/rekurt/ymsdk)

Lightweight Go client for Yandex Messenger Bot API with typed models, built-in retry, and services for core API methods. Docs: https://pkg.go.dev/github.com/rekurt/ymsdk

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
[![Go Report Card](https://goreportcard.com/badge/github.com/rekurt/ymsdk)](https://goreportcard.com/report/github.com/rekurt/ymsdk)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Go Version](https://img.shields.io/github/go-mod/go-version/rekurt/ymsdk)](go.mod)
[![codecov](https://codecov.io/gh/rekurt/ymsdk/branch/master/graph/badge.svg)](https://codecov.io/gh/rekurt/ymsdk)

Легковесный Go-клиент для Yandex Messenger Bot API с типобезопасными моделями, встроенным retry и сервисами для всех основных методов API. Документация: https://pkg.go.dev/github.com/rekurt/ymsdk

Expand Down
44 changes: 44 additions & 0 deletions client/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package client_test

import (
"fmt"
"os"

"github.com/rekurt/ymsdk/client"
"github.com/rekurt/ymsdk/client/ym"
"github.com/rekurt/ymsdk/client/ym/ymerrors"
)

func ExampleNew() {
cs := client.New(ym.Config{
Token: os.Getenv("YM_TOKEN"),
ErrorHandling: ymerrors.ErrorHandlingConfig{
RetryStrategy: ymerrors.RetryStrategy{
MaxAttempts: 3,
RetryNetwork: true,
},
RateLimitHandling: ymerrors.RateLimitHandling{
UseRetryAfter: true,
},
},
})

fmt.Println(cs.Messages != nil)
fmt.Println(cs.Chats != nil)
fmt.Println(cs.Polls != nil)
// Output:
// true
// true
// true
}

func ExampleWrap() {
cl := ym.NewClient(ym.Config{Token: "my-token"})
cs := client.Wrap(cl)

fmt.Println(cs.Client != nil)
fmt.Println(cs.Updates != nil)
// Output:
// true
// true
}
41 changes: 41 additions & 0 deletions client/ym/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ym_test

import (
"fmt"
"os"
"time"

"github.com/rekurt/ymsdk/client/ym"
"github.com/rekurt/ymsdk/client/ym/ymerrors"
)

func ExampleNewClient() {
cl := ym.NewClient(ym.Config{
Token: os.Getenv("YM_TOKEN"),
})

fmt.Println(cl != nil)
// Output:
// true
}

func ExampleNewClient_withRetry() {
cl := ym.NewClient(ym.Config{
Token: os.Getenv("YM_TOKEN"),
ErrorHandling: ymerrors.ErrorHandlingConfig{
RetryStrategy: ymerrors.RetryStrategy{
MaxAttempts: 3,
InitialBackoff: 500 * time.Millisecond,
MaxBackoff: 10 * time.Second,
RetryNetwork: true,
},
RateLimitHandling: ymerrors.RateLimitHandling{
UseRetryAfter: true,
},
},
})

fmt.Println(cl != nil)
// Output:
// true
}
40 changes: 40 additions & 0 deletions client/ym/ymerrors/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package ymerrors_test

import (
"errors"
"fmt"

"github.com/rekurt/ymsdk/client/ym/ymerrors"
)

func ExampleAPIError() {
err := &ymerrors.APIError{
Kind: ymerrors.KindRateLimited,
HTTPStatus: 429,
Description: "Too many requests",
}

fmt.Println(err.Error())
fmt.Println(errors.Is(err, ymerrors.ErrRateLimited))
// Output:
// yandex-messenger/apierror: kind=1 http=429: Too many requests
// true
}

func ExampleAPIError_unwrap() {
apiErr := &ymerrors.APIError{
Kind: ymerrors.KindInvalidToken,
HTTPStatus: 403,
Description: "Invalid token",
}

// Use errors.As to extract the structured error.
var target *ymerrors.APIError
if errors.As(apiErr, &target) {
fmt.Println("HTTP status:", target.HTTPStatus)
fmt.Println("Description:", target.Description)
}
// Output:
// HTTP status: 403
// Description: Invalid token
}
Loading