A Go client library for the EVE Online ESI API, generated from the official OpenAPI specification.
This library is a spiritual successor to the original goesi package, updated to support CCP's OpenAPI 3.x+ specification. When CCP migrated ESI to OpenAPI 3.0+, a new code generation approach was needed to maintain compatibility with the updated specification format.
go get github.com/fnt-eve/goesi-openapipackage main
import (
"context"
"log"
"github.com/fnt-eve/goesi-openapi"
)
func main() {
ctx := context.Background()
// Create client for public endpoints
client := goesi.NewPublicESIClient("MyApp/1.0 ([email protected])")
// Get system information
system, _, err := client.UniverseAPI.GetUniverseSystemsSystemId(ctx, 30000142).Execute()
if err != nil {
log.Fatal(err)
}
log.Printf("System: %s", system.GetName())
}package main
import (
"context"
"log"
"os"
"github.com/fnt-eve/goesi-openapi"
)
func main() {
ctx := context.Background()
// Set up OAuth2
clientID := os.Getenv("ESI_CLIENT_ID")
redirectURL := "http://localhost:8080/callback"
// Create JWT key function for token validation
keyFunc, err := goesi.ESIDefaultKeyfunc(ctx)
if err != nil {
log.Fatal(err)
}
// Create OAuth2 config
config, err := goesi.NewConfig(clientID, redirectURL, &keyFunc)
if err != nil {
log.Fatal(err)
}
// Get authorization URL with requested scopes
state := "random-state-string"
scopes := []string{goesi.ScopeLocationReadLocationV1}
authURL := config.AuthURL(state, scopes)
log.Printf("Visit: %s", authURL)
// Exchange code for token (after user authorization)
// var code string // Get this from the callback
// token, claims, err := config.Exchange(ctx, code, state, state)
// if err != nil {
// log.Fatal(err)
// }
// Create authenticated client
// client := goesi.NewAuthenticatedESIClient(ctx, config, token, "MyApp/1.0 ([email protected])")
}ESI uses OAuth2 with PKCE. The authentication flow:
- Create config with client ID and redirect URL
- Generate auth URL with requested scopes and redirect user to authorize
- Exchange code for access token
- Use token to make authenticated API calls
- Refresh token when it expires
The library includes constants for all ESI scopes:
scopes := []string{
goesi.ScopeLocationReadLocationV1,
goesi.ScopeAssetsReadAssetsV1,
goesi.ScopeSkillsReadSkillsV1,
goesi.ScopeCorporationsReadBlueprintsV1,
// ... many more
}Access tokens are JWTs containing character information. The Exchange method returns both the token and parsed claims:
// Exchange authorization code for token and claims
token, claims, err := config.Exchange(ctx, code, state, state)
if err != nil {
log.Fatal(err)
}
// Extract character information from claims
characterID, err := claims.CharacterID() // int32
characterName := claims.Name // string
scopes := claims.Scopes // []stringThe generated client provides access to all ESI endpoints through API groups:
client := goesi.NewPublicESIClient("MyApp/1.0 ([email protected])")
// Character information
client.CharacterAPI.GetCharactersCharacterId(ctx, characterID)
// Market data
client.MarketAPI.GetMarketsRegionIdOrders(ctx, regionID)
// Universe data
client.UniverseAPI.GetUniverseSystemsSystemId(ctx, systemID)
// Corporation data
client.CorporationAPI.GetCorporationsCorporationId(ctx, corporationID)
// Alliance data
client.AllianceAPI.GetAlliancesAllianceId(ctx, allianceID)data, response, err := client.CharacterAPI.GetCharactersCharacterId(ctx, characterID).Execute()
if err != nil {
if apiErr, ok := err.(*esi.GenericOpenAPIError); ok {
log.Printf("API Error: %s", apiErr.Error())
log.Printf("Response: %s", apiErr.Body())
} else {
log.Printf("Other error: %v", err)
}
return
}// Check if token needs refresh
if goesi.IsExpired(token) {
newToken, newClaims, err := config.RefreshToken(ctx, token)
if err != nil {
log.Fatal("Token refresh failed:", err)
}
token = newToken
claims = newClaims
}
// Store/load tokens (stores only the oauth2.Token, not claims)
tokenJSON, _ := goesi.TokenToJSON(token)
// Store tokenJSON in database/file
// Later: restore token and parse claims
storedToken, _ := goesi.TokenFromJSON(tokenJSON)
claims, err := config.ParseClaims(storedToken)
if err != nil {
log.Fatal("Failed to parse claims:", err)
}ESI rate limits:
- 20 requests/second for authenticated requests
- 10 requests/second for public requests
The client automatically includes required headers like X-Compatibility-Date.
See examples/ directory:
basic-oauth2/- Complete OAuth2 flow with authenticated clientcontext-auth/- Context-based authentication patterntoken-persistence/- Token serialization and TokenSource usage
The client is generated from the ESI OpenAPI specification:
make generateThis downloads the latest ESI spec, generates the client code, and runs post-processing scripts.
go build ./...
go test ./...
go run examples/oauth2_example.goESI requires all requests to include a User-Agent header with contact information:
userAgent := "MyEVEApp/1.0 ([email protected])"
client := goesi.NewPublicESIClient(userAgent)Format: AppName/Version (contact-email)
The examples require an ESI application registration:
Visit EVE Developers to create an application and get a Client ID.
export ESI_CLIENT_ID="your-client-id-from-developers-portal"go run examples/basic-oauth2/main.go
go run examples/context-auth/main.gogolang.org/x/oauth2- OAuth2 clientgithub.com/golang-jwt/jwt/v5- JWT token parsinggithub.com/MicahParks/keyfunc/v3- JWT key validation
- Go 1.24+
- Valid ESI application registration
MIT License - see LICENSE file.
Not affiliated with CCP Games. EVE Online is a trademark of CCP hf.