Go Design

Info Icon

OSS Comparison

For a comparison between the Speakeasy Go SDK and some popular open-source generators, see this page.

Speakeasy Go SDKs are designed to be easy to use and easy to debug. Various decisions were made that guide the design of the SDK; these include:

  • Minimal dependencies and relying on the Go standard library as much as possible.
  • Struct tags and reflection-based (de)serializers to define how the types we generate are correctly serialized based on the OpenAPI document.
  • Pointers for optional objects including fields, parameters, and response and request bodies to ensure the user can differentiate between a field not being set and a field being set to a zero value.
  • A utils package that improves readability by bundling the methods for configuring the SDK and serializing/deserializing the types we generate into a shared package, avoiding the need to duplicate in each method.

Examples

Guardrails

Easy-to-use Go SDKs that minimize the time to 200 should reduce the opportunity for users to send requests that don't match the API spec.

To that end, Go SDKs generated by Speakeasy convey maximal information to the end user and, where possible, actively restrict inputs.

Here's the Pet model generated by Swagger CodeGen (opens in a new tab) using the Swagger Petstore OpenAPI schema (opens in a new tab):

package swagger
 
type Pet struct {
	Id        int64     `json:"id,omitempty"`
	Name      string    `json:"name"`
	Category  *Category `json:"category,omitempty"`
	PhotoUrls []string  `json:"photoUrls"`
	Tags      []Tag     `json:"tags,omitempty"`
	// pet status in the store
	Status string `json:"status,omitempty"`
}
  • Required parameters are only differentiated from optional parameters by the presence of the omitempty annotation.
  • Despite Status having only three valid values (available, pending, and sold) in the OpenAPI spec, it is represented as a string.

Compare this to the Pet model generated by Speakeasy:

package shared
 
type PetStatusEnum string
 
const (
	PetStatusEnumAvailable PetStatusEnum = "available"
	PetStatusEnumPending   PetStatusEnum = "pending"
	PetStatusEnumSold      PetStatusEnum = "sold"
)
 
type Pet struct {
	Category  *Category      `json:"category,omitempty"`
	ID        *int64         `json:"id,omitempty"`
	Name      string         `json:"name"`
	PhotoUrls []string       `json:"photoUrls"`
	Status    *PetStatusEnum `json:"status,omitempty"`
	Tags      []Tag          `json:"tags,omitempty"`
}
  • Optional parameters are indicated by pointers, permitting them to evaluate as nil. This is especially useful when the model is received as the response from an API call, as the user can distinguish between unset (nil) and the default.
  • TheStatus parameter is an enum, guiding the user to provide one of the three permissible values.

Authorization

Communicating authorization methods can be tricky, especially when there are multiple methods of authenticating and different styles of authorization for various endpoints, as in the Swagger Petstore OpenAPI schema (opens in a new tab).

Here's an example of how Speakeasy handles a request with a specific authentication scheme:

package operations
 
type FindPetsByStatusStatusEnum string
 
// ...
 
type FindPetsByStatusQueryParams struct {
	Status *FindPetsByStatusStatusEnum `queryParam:"style=form,explode=true,name=status"`
}
 
type FindPetsByStatusSecurity struct {
	PetstoreAuth shared.SchemePetstoreAuth `security:"scheme,type=oauth2"`
}
 
type FindPetsByStatusRequest struct {
	QueryParams FindPetsByStatusQueryParams
	Security    FindPetsByStatusSecurity
}
 
type FindPetsByStatusResponse struct {
	Body        []byte
	ContentType string
	Pets        []shared.Pet
	StatusCode  int64
}

Note that the exact type of authentication required (shared.SchemePetstoreAuth) is specified in the request.

Compare that to the code generated by Swagger CodeGen (opens in a new tab):

type PetApiFindPetsByStatusOpts struct {
	Status optional.String
}

Security must be set through the Context passed into the FindPetsByStatus method, and nowhere is it communicated what style of authentication is required for each endpoint.

Getter Methods

In addition to the fields, Speakeasy generates getter methods for each field, allowing users to access the fields by chaining getters without having to worry about nil.

Here are a couple of the getter methods generated for the Pet model:

func (o *Pet) GetCategory() *Category {
    if o == nil {
        return nil
    }
    return o.Category
}
 
func (o *Pet) GetName() string {
    if o == nil {
        return ""
    }
    return o.Name
}

The nil check allows these methods to be safely chained to simplify code that doesn't need all the extra checking. For example,

client := sdk.NewClient()
pet, err := client.Pet.GetPetByID(17)
if err != nil {
	// TODO handle error
}
petCategory := pet.GetCategory().GetName()

The above code will not panic, regardless of what the API returns. This remains true despite skipping error handling with the TODO comment, and would also be the case if there were an error that resulted in pet == nil. If the optional Category is not set, the getter generated for that model will also do the same nil check and avoid triggering a panic.

If you have any feedback or want to suggest improvements or ask for a new feature, please get in touch in the #client-sdks channel in our public Slack (opens in a new tab).