Russian | English
Go client for the HeadHunter API: typed OpenAPI sub-clients and an hhru.New facade for shared headers, optional OAuth bearer, default query parameters, and retries on 429 / 503. Package docs on pkg.go.dev (badge above).
Russian documentation: README.md and README.ru.md.
- Why this library
- Install
- Quick start
- Runnable examples
- Application token (client credentials)
- User token and auto-refresh
- Options: retries and limits
- Pagination
- Observability and API errors
- Maintainers: regenerate
gen/ - Integration tests
- Versioning
- OpenAPI types and methods — less manual URL/query/header wiring; four generated clients (employer, applicant, public, app).
- HH rules in one place — required
HH-User-Agent, optional defaulthost/locale, Bearer viaTokenSource, optional overload retries, optional request rate limit, request/response hooks. - Long-running services —
NewRefreshingTokenSourcerefreshes access tokens under a mutex;hhru.Newstays stateless; you pass oneTokenSource. - Reproducibility —
api/openapi.ymlandgen/are committed; CI checks codegen drift.
go get github.com/Zoomish/go-hhru-apiimport (
"context"
"github.com/Zoomish/go-hhru-api"
"github.com/Zoomish/go-hhru-api/gen/public"
)
c, err := hhru.New(hhru.Options{
HHUserAgent: "MyService/1.0 (mailto:you@example.com)",
DefaultHost: "hh.ru",
})
if err != nil {
panic(err)
}
host := public.GetCountriesParamsHostHhRu
resp, err := c.Public.GetCountriesWithResponse(context.Background(), &public.GetCountriesParams{
HHUserAgent: c.HHUserAgent(),
Host: &host,
})HH-User-Agent is also applied by the request editor when missing; many *Params still expect HHUserAgent — use c.HHUserAgent().
From the repository root.
Public dictionaries (no OAuth):
go run ./examples/public_countries
go run ./examples/public_locales
go run ./examples/public_areas
go run ./examples/public_industries
go run ./examples/public_languages
go run ./examples/public_position_suggest
go run ./examples/public_position_suggest -text "backend engineer"Client options (DefaultHost, DefaultLocale, MaxRetries):
go run ./examples/custom_optionsOAuth:
export HH_CLIENT_ID=… HH_CLIENT_SECRET=…
go run ./examples/app_tokenexport HH_CLIENT_ID=… HH_CLIENT_SECRET=…
export HH_INITIAL_TOKEN_JSON_PATH=/path/to/token.json
go run ./examples/refreshing_tokenThe token file must match TokenResponse (access_token, refresh_token, expires_in) after the user OAuth flow. Examples support -hh-user-agent or HH_USER_AGENT.
tok, err := hhru.ExchangeClientCredentials(ctx, http.DefaultClient,
hhru.TokenEndpoint(hhru.DefaultBaseURL),
"MyService/1.0 (mailto:you@example.com)",
clientID, clientSecret,
)
c, err := hhru.New(hhru.Options{
HHUserAgent: "MyService/1.0 (mailto:you@example.com)",
TokenSource: hhru.AccessToken(tok.AccessToken),
})Refresh via ExchangeRefreshToken with grant_type=refresh_token (optional client_id / client_secret).
After OAuth you typically have access_token, refresh_token, and expires_in. Pass the first token response into NewRefreshingTokenSource and use it as TokenSource with hhru.New.
initial := &hhru.TokenResponse{
AccessToken: accessFromOAuth,
RefreshToken: refreshFromOAuth,
ExpiresIn: expiresInSeconds,
}
ts, err := hhru.NewRefreshingTokenSource(http.DefaultClient,
hhru.TokenEndpoint(hhru.DefaultBaseURL),
"MyService/1.0 (mailto:you@example.com)",
clientID, clientSecret,
initial,
)
if err != nil {
panic(err)
}
c, err := hhru.New(hhru.Options{
HHUserAgent: "MyService/1.0 (mailto:you@example.com)",
TokenSource: ts,
})Application-only client_credentials tokens do not use this refresh path; re-issue with AccessToken.
Options.MaxRetries— retries for safe requests on429/503honoringRetry-Afterand exponential backoff; ifRetryBackoffMin/RetryBackoffMaxare set, sleep duration is clamped to that range.Options.MaxRequestsPerSecond— soft limit on outgoing request starts (even spacing).Options.RequestHook/Options.ResponseHook— hooks before send and after response headers (body not read; useful for logging and tracing).
PagesUntil runs page = start, start+1, … until the callback returns continueNext == false or an error.
- Parse typical HH JSON errors with
ParseAPIErrorandAPIError(e.g.RequestIDwhen present). - For tests, use
NewRefreshingTokenSourceWithOptionswithClockinRefreshingSourceOptions.
Requires Go and network for tool modules:
make generateSee CONTRIBUTING.md for tests and the integration build tag. Spec: api/openapi.yml. CI: .github/workflows/.
go test -short ./...— fast path without live HH calls (token_refresh_test.gouseshttptest).- Live API:
go test -tags=integration -timeout 5m ./integration(omit-short). WithHH_TEST_CLIENT_IDandHH_TEST_CLIENT_SECRETfrom dev.hh.ru, the OAuth scenario runs as well. - Manual workflow:
.github/workflows/integration-tests.yml(workflow_dispatch).
Semantic versioning after v1. Until then, minors may break when openapi.yml or gen/ changes. See CHANGELOG.md.
Publishing: pushing a v* tag runs .github/workflows/release.yml: the same checks as CI (composite action), then a GitHub Release. Details in CONTRIBUTING.md.