Go client
You can call the API with plain net/http, as the
example code does, or generate a typed client
from the spec. This page shows how to generate one with
oapi-codegen v2.8.0, the
generator we build and test against the spec.
The spec is published at https://developers.elephants.inc/openapi.json.
Generate the client
Section titled “Generate the client”1. Download the spec
Section titled “1. Download the spec”curl -sO https://developers.elephants.inc/openapi.jsonKeep the file in your repository, so that each change to the client shows up as a change to the spec in review.
2. Pin the generator and its runtime
Section titled “2. Pin the generator and its runtime”go get -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@v2.8.0go get github.com/oapi-codegen/runtime@v1.7.0go tool oapi-codegen then always runs that version.
3. Add the configuration
Section titled “3. Add the configuration”Save this as oapi-codegen.yml:
package: clientoutput: client/client.gogenerate: models: true client: trueoutput-options: # The default suffix, "Response", gives operation results names that # collide with schemas of the same name (signIn's result and the # SignInResponse schema, for example). response-type-suffix: HTTPResponseIt generates the models and a client into client/client.go. The suffix
keeps operation results apart from schemas with similar names: the result of
signIn is SignInHTTPResponse, and its body is the SignInResponse schema.
4. Generate
Section titled “4. Generate”mkdir -p clientgo tool oapi-codegen -config oapi-codegen.yml openapi.jsongo build ./...5. Call the API
Section titled “5. Call the API”This program lists the signed-in person’s organizations on the sandbox.
Change the client import path to your own module’s:
// Command codegen proves the generated client compiles against the// published spec: it lists your organizations on the sandbox.//// ELE_TOKEN=… go run .package main
import ( "context" "fmt" "log" "net/http" "os"
"github.com/elephants-labs/ele/developers/codegen/client")
// bearerToken sends ELE_TOKEN with every request.func bearerToken(_ context.Context, r *http.Request) error { r.Header.Set("Authorization", "Bearer "+os.Getenv("ELE_TOKEN")) return nil}
func main() { c, err := client.NewClientWithResponses("https://staging-api.elefin.net", client.WithRequestEditorFn(bearerToken)) if err != nil { log.Fatal(err) } res, err := c.ListOrganizationsWithResponse(context.Background(), &client.ListOrganizationsParams{}) if err != nil { log.Fatal(err) } if res.JSON200 == nil { log.Fatalf("unexpected response %d: %s", res.StatusCode(), res.Body) } for _, org := range res.JSON200.Data { fmt.Printf("%s (%s)\n", org.Name, org.Id) }}ELE_TOKEN=… go run .WithRequestEditorFn runs on every request; here it adds the bearer token.
Get the token as Authentication describes.
What the client gives you
Section titled “What the client gives you”- Every published operation, in two forms.
Clientreturns the raw*http.Response.ClientWithResponses, used above, also decodes the body. - One field per status. A
…WithResponsemethod returns a struct such asListOrganizationsHTTPResponse, withJSON200,JSON401and so on. The field for the status that came back is set.StatusCode()and the rawBodyare always there. The separateerrorreturn is for transport failures and for a body that does not decode. - Errors. Most error statuses decode to
*Error. Branch on.Error.Type, as Errors explains. Onstep_up_required,.Error.StepUpholds the challenge. A429body carries only.Error.Type; theRetry-Afterheader is parsed intoHeaders429.RetryAfter(it is also inHTTPResponse.Header). See Rate limits. - Optional and nullable fields are pointers, such as
*string. - Dates and IDs are
openapi_types.Dateandopenapi_types.UUID.
New values and new variants
Section titled “New values and new variants”Versioning lets Ele add enum values, such as a new
payment status, and new kinds of object, such as a new transaction type,
at any time. The generated client keeps working when that happens:
- An enum is a named
stringtype with one constant per value the spec knew, such asPaymentStatus. A value added later decodes as its string. Give everyswitchon it adefaultcase. - A union, such as
Transaction, keeps the raw JSON of each item.Discriminator()returns itstype.ValueByDiscriminator()returns the typed value, or an error for a variant your client does not know yet. A list that contains a new variant still decodes; handle that error item by item, for example by showing the transaction’s common fields or skipping it. Switch onDiscriminator()before calling anAsX()accessor such asAsCardTransaction(): on any other variant,AsX()returns a partly filled value and no error.
To decode a new variant into its type, download the spec again and regenerate. Watch the changelog.
Idempotency keys
Section titled “Idempotency keys”No operation declares Idempotency-Key as a parameter, so the generated
methods have no field for it. Pass a request editor on each write:
package main
import ( "context" "net/http"
"github.com/elephants-labs/ele/developers/codegen/client")
// withIdempotencyKey sets Idempotency-Key on one call. Create the key once// per operation and pass the same key on every retry of it.func withIdempotencyKey(key string) client.RequestEditorFn { return func(_ context.Context, r *http.Request) error { r.Header.Set("Idempotency-Key", key) return nil }}Pass withIdempotencyKey(key) as the last argument of a call, such as
ExecuteSwapWithResponse.
Create the key once per operation and reuse it on every retry. See Idempotency.
Calls not to make from a server
Section titled “Calls not to make from a server”The client includes every operation, including the ones that let a phone
answer step-up or sign a person in without a password, such as
approveChallenge and enrollApprovalCredential. Do not call them from your
server; see Keep a person in the loop.
Why not ogen
Section titled “Why not ogen”ogen v1.24.0 also generates a client from this spec, but that client checks every response against the spec it was generated from, and nothing turns the check off. A new enum value fails the check, and a new union variant fails decoding, so calls start failing as soon as Ele makes an addition that Versioning allows, until you regenerate. That includes writes that succeeded. We do not recommend it for this API.