Какие знаешь хорошие практики работы с context.WithValue

Ответ

Используйте context.WithValue только для передачи данных, связанных с запросом или транзакцией, таких как ID запроса, аутентификационные токены или метаданные. Не передавайте через контекст обязательные параметры функций или зависимости (например, базы данных, логгеры) — это усложняет API, делает код менее явным и затрудняет тестирование.

Ключи контекста должны быть неэкспортируемыми (например, type ctxKey string или type contextKey int), чтобы избежать коллизий между пакетами. Рекомендуется использовать пустые структуры (struct{}) или неэкспортируемые типы для ключей, чтобы гарантировать уникальность. Значения, передаваемые через контекст, должны быть неизменяемыми и потокобезопасными.

Пример:

type ctxKey string

const requestIDKey ctxKey = "requestID"

func WithRequestID(ctx context.Context, id string) context.Context {
    return context.WithValue(ctx, requestIDKey, id)
}

func GetRequestID(ctx context.Context) (string, bool) {
    if v := ctx.Value(requestIDKey); v != nil {
        if s, ok := v.(string); ok {
            return s, true
        }
    }
    return "", false
}

Важно: Всегда проверяйте тип извлеченного значения из контекста с помощью type assertion с ok (как в GetRequestID), чтобы избежать паники, если значение отсутствует или имеет неожиданный тип.