> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Upgrade the Go API client to version 3

> Keep your Go API client up to date to benefit from improvements and bug fixes.

export const Legacy = ({title, href}) => {
  return <Note>

    This page documents an earlier version of the API client.
    For the latest version, see <a href={href}>{title}</a>.

    </Note>;
};

<Legacy title="Upgrade" href="/doc/libraries/sdk/upgrade/go" />

The Go API client follows [semantic versioning](http://semver.org).

## Upgrade to version 3

The design of the latest version of the Go client is almost the same as the earlier version to make upgrading as smooth as possible.
This new version is compatible with the same Go versions as before (from 1.8 up to the most recent Go version).

## Dependency upgrade

Because the package structure of the Go API client has changed between versions 2 and 3,
you can't change the dependency version without updating your code.
The major change is the removal of the `algoliasearch/` sub-package in favor of the `algolia/search/` one.
Before upgrading the package version,
replace all `algoliasearch/` imports and `algoliasearch.` package prefixes with their `algolia/search/` and `search.` counterparts.

Since the introduction of versioned modules in Go 1.11,
Go retrieves dependencies automatically every time you run `go build` or `go test`.

To import a specific version of the Go client:

```sh Command line icon=square-terminal theme={"system"}
go get github.com/algolia/algoliasearch-client-go/v3@v3.Y.Z
```

You should migrate your project to use Go modules.
If you're still using `dep` as a dependency manager you can update the package as usual:

```sh Command line icon=square-terminal theme={"system"}
# Change the `version` field of the
# `github.com/algolia/algoliasearch-client-go` constraint of your `Gopkg.toml`
# file to `3.X.Y` with your editor of choice.
vim Gopkg.toml

# Run `dep` as follows to automatically update the `Gopkg.lock` file with
# the most recent minor version of the Algolia Go client.
dep ensure
```

## Client instantiation

### Search client instantiation

Replace the instantiation of the search client as shown below.

```go Go icon=code theme={"system"}
// Before
client := algoliasearch.NewClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
index := client.InitIndex("INDEX_NAME")

// After
client := search.NewClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
index := client.InitIndex("INDEX_NAME")

// Using configuration
client := search.NewClientWithConfig(search.Configuration{
    AppID: "ALGOLIA_APPLICATION_ID", // Mandatory
    APIKey: "ALGOLIA_API_KEY", // Mandatory
    Hosts: []string{ ... },            // Optional
    Requester: customRequester,        // Optional
    ReadTimeout: 5 * time.Second,      // Optional
    WriteTimeout: 30 * time.Second,    // Optional
    Headers: map[string]string{ ... }, // Optional
})
```

### Analytics client instantiation

Replace the instantiation of the analytics client as shown below.

```go Go icon=code theme={"system"}
// Before
client := algoliasearch.NewClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY").InitAnalytics()

// After
client := analytics.NewClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")

// Using configuration
client := analytics.NewClientWithConfig(search.Configuration{
    AppID: "ALGOLIA_APPLICATION_ID",        // Mandatory
    APIKey: "ALGOLIA_API_KEY",              // Mandatory
    Hosts: []string{ ... },            // Optional
    Requester: customRequester,        // Optional
    ReadTimeout: 5 * time.Second,      // Optional
    WriteTimeout: 30 * time.Second,    // Optional
    Region: region.US                  // Optional
    Headers: map[string]string{ ... }, // Optional
})
```

### Insights client instantiation

Replace the instantiation of the analytics client as shown below.

```go Go icon=code theme={"system"}
// Before
client := algoliasearch.NewClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY").InitInsights()

// After
client := insights.NewClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
userClient := client.User("UserToken")

// Using configuration
client := insights.NewClientWithConfig(search.Configuration{
    AppID: "ALGOLIA_APPLICATION_ID",        // Mandatory
    APIKey: "ALGOLIA_API_KEY",              // Mandatory
    Hosts: []string{ ... },            // Optional
    Requester: customRequester,        // Optional
    ReadTimeout: 5 * time.Second,      // Optional
    WriteTimeout: 30 * time.Second,    // Optional
    Region: region.US                  // Optional
    Headers: map[string]string{ ... }, // Optional
})
```

## Functional options as optional parameters

One of the biggest change is the addition of functional options,
[as coined by Dave Cheney](https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis)
to ease the manipulation of Algolia parameters.

For instance, when searching through some index records, instead of passing
parameters with a custom `algoliasearch.Map`, you can now use the
following syntax:

```go Go icon=code theme={"system"}
// Before
index.Search(
    "query",
    algoliasearch.Map{
        "attributesToRetrieve": []string{"objectID", "title"},
        "hitsPerPage": 3,
    },
})

// After
index.Search("query",
    opt.AttributesToRetrieve("objectID", "title"),
    opt.HitsPerPage(3),
)
```

This gives the advantage of better discoverability and improved type-safety,
as all options are now typed.

## `algoliasearch.Object` and `algoliasearch.Map` removed

The tedious part of migrating from version 2 to version 2 is to remove all `algoliasearch.Map` and `algoliasearch.Object` references.
Those objects are aliases on top of `map[string]interface{}`, which handled known types internally.
From a developer perspective, this wasn't great.
You had to transform all user structures into those custom types.

Since version 3, user-defined structures are now first-class citizens.

As an example, take this before/after snippet of code explaining how to save an
object to an Algolia index:

```go Go icon=code theme={"system"}
type Book struct {
	Title    string `json:"title"`
	Year     string `json:"year"`
	ObjectID string `json:"objectID"`
}

book := Book{
	Title:    "It",
	Year:     1986,
	ObjectID: "12345",
}

// Before
object := algoliasearch.Object{
	"title":    book.Title,
	"year":     book.Year,
	"objectID": book.ObjectID,
}
index.AddObject(object)

// After
index.SaveObject(book)
```

Now, because objects are user-defined structures,
the Go API client can't return them from functions,
due to the lack of generics.
The approach taken is the same as the `json.Unmarshal` function from the standard library:
any function which may return a user-defined object expects an extra parameter passed as a reference.

Again, as an example, take this before/after snippet of code explaining how to
retrieve a deserialized object from an Algolia index:

```go Go icon=code theme={"system"}
type Book struct {
	Title    string `json:"title"`
	Year     string `json:"year"`
	ObjectID string `json:"objectID"`
}

// Before:
// the returned object is an `algoliasearch.Object`.
obj, err := index.GetObject(book.ObjectID)
fmt.Println(obj["title"])

// After:
// the object contained in the response payload is unmarshalled directly into
// the given reference, here an instance of a `Book` structure
var b Book
err := index.GetObject(book.ObjectID, &b)
fmt.Println(b.Title)
```

Note that you can actually use Go maps and any serializable object.

## Set and get `Settings`

In version 2, handling settings wasn't convenient.
This difficulty was mainly due to `GetSettings` returning a `Settings` structure whereas
`SetSettings` was expecting an `algoliasearch.Map` (alias for `map[string]interface{}`).

Because of this, a `Settings.ToMap` function let users get a `algoliasearch.Map`,
which `SetSettings` uses.
This `algoliasearch.Map` couldn't transform into `Settings` without lots of work.
Also, it's hard to compare both objects against each other.

Version 3 gets rid of the `algoliasearch.Map` representation for the settings,
which lets you now change `GetSettings` and `SetSettings` as such:

```go Go icon=code theme={"system"}
// Before
settings, err := index.GetSettings()
settingsAsMap := settings.ToMap()
settingsAsMap["replicas"] = []string{"replica1", "replica2"}
index.SetSettings(settingsAsMap)

// After
settings, err := index.GetSettings()
settings.Replicas = opt.Replicas("replica1", "replica2")
index.SetSettings(settings)
```

## Waitable responses

To wait for indexing operation to complete,
you had to explicitly call `index.WaitTask()` with the appropriate response's `TaskID` field.
You had to know about the existence of the `TaskID` field and to learn how it works with `index.WaitTask`.

More importantly, it was difficult to wait concurrently on the different tasks.

Most of other methods weren't waitable.
For instance, there was no solution to wait for the completion of key or analytics-related operations.

Since version 3, all response objects triggering asynchronous operations on Algolia's side now have a `Wait()` method.
Each method hides its own logic on how to wait for its own underlying operation to complete.

To address the last issue,
being able to wait on multiple tasks concurrently,
version 3 introduces a new object: `wait.Group`.
You can use it as follows:

```go Go icon=code theme={"system"}
g := wait.Group()

res1, err := index.SaveObjects(...)
g.Collect(res1)

res2, err := index.SetSettings(...)
res3, err := index.SaveRules(...)
g.Collect(res2, res3)

// `g.Wait()` call will block until both the `SaveObjects`, `SetSettings` and
// `SaveRules` operations terminates.
err = g.Wait()
```

Whenever operations are close to each other,
`wait.Wait(...)` is also provided as a shortcut.

```go Go icon=code theme={"system"}
res1, err := index.SaveObjects(...)
res2, err := index.SetSettings(...)
res3, err := index.SaveRules(...)

err = wait.Wait(res1, res2, res3)
```

## New `debug` package

This release also replaces the debug approach,
which was using `ALGOLIA_DEBUG` environment variable values to control global level of debug messages.

In version 3, you can guard specific places of the code by `debug.Enable()`/ `debug.Disable()` calls,
to pretty-print raw JSON request and response payloads and other specific debug information to users.
You can use it as follows:

```go Go icon=code theme={"system"}
debug.Enable()
res, err := index.SaveObject(map[string]string{"objectID": "one"})
debug.Disable()
```

Which would print on the standard output:

```txt theme={"system"}
> ALGOLIA DEBUG request:
        method="POST"
        url="https://ALGOLIA_APPLICATION_ID.algolia.net/1/indexes/test"
        body=
        {
          "objectID": "one"
        }
> ALGOLIA DEBUG response:
        body=
        {
          "createdAt": "2019-04-12T15:57:21.669Z",
          "taskID": 11054870692,
          "objectID": "one"
        }
```

## New methods

* `Client.MultipleBatch`: perform batches across different indices. Previously `Client.Batch`
* `Client.MultipleGetObjects`: retrieve objects by objectID across different indices
* `Index.BrowseObjects`: produce an iterator over all objects matching the query parameters
* `Index.BrowseRules`: produce an iterator over all rules matching the query parameters
* `Index.BrowseSynonyms`: produce an iterator over all synonyms matching the query parameters

## Removed methods

* `*`: replace with `opt.ExtraHeader(...)` or `opt.ExtraURLParam(...)` as [functional options](#functional-options-as-optional-parameters)
* `AnalyticsClient.WaitTask`: replace by invoking [response objects' `.Wait`](#waitable-responses) method directly
* `Client.AddUserKey`: replace with `Client.AddAPIKey`
* `Client.Batch`: replace with `Client.MultipleBatch`
* `Client.ClearIndex`: replace with `Index.Clear`
* `Client.DeleteIndex`: replace with `Index.Delete`
* `Client.DeleteUserKey`: replace with `Client.DeleteAPIKey`
* `Client.GetStatus`: replace with `Index.GetStatus`
* `Client.GetUserKey`: replace with `Client.GetAPIKey`
* `Client.InitAnalytics`: replace with `analytics.NewClient`
* `Client.InitInsights`: replace with `insights.NewClient`
* `Client.ListKeys`: replace with `Client.ListAPIKeys`
* `Client.SetAnalyticsTimeout`: replace with `context.WithTimeout` as a [functional option](#functional-options-as-optional-parameters)
* `Client.SetExtraHeader`: replace with `opt.ExtraHeader` as a [functional option](#functional-options-as-optional-parameters)
* `Client.SetHTTPClient`: replace with proper `Requester` in `search.NewClientWithConfig`
* `Client.SetMaxIdleConnsPerHosts`: replace with proper `Requester` in `search.NewClientWithConfig`
* `Client.SetReadTimeout`: replace with `context.WithTimeout` as a [functional option](#functional-options-as-optional-parameters)
* `Client.SetTimeout`: replace with `context.WithTimeout` as a [functional option](#functional-options-as-optional-parameters)
* `Client.SetWriteTimeout`: replace with `context.WithTimeout` as a [functional option](#functional-options-as-optional-parameters)
* `Client.UpdateUserKey`: replace with `Client.AddAPIKey`
* `Client.WaitTask`: replace by invoking [response objects' `.Wait`](#waitable-responses) method directly
* `Index.AddAPIKey`: replace with `Client.AddAPIKey`
* `Index.AddObject`: replace with `Index.SaveObject`
* `Index.AddObject`: replace with `Index.SaveObject`
* `Index.AddObjects`: replace with `Index.SaveObjects(..., opt.AutoGenerateObjectIDIfNotExist(true))`
* `Index.AddSynonym`: replace with `Index.SaveSynonym`
* `Index.AddUserKey`: replace with `Client.AddAPIKey`
* `Index.BatchRules`: replace with `Index.SaveRules`
* `Index.BatchSynonyms`: replace with `Index.SaveSynonyms`
* `Index.BrowseAll`: replace with `Index.BrowseObjects`
* `Index.Browse`: replace with `Index.BrowseObjects`
* `Index.Copy`: replace with `Client.Copy`
* `Index.DeleteAPIKey`: replace with `Client.DeleteAPIKey`
* `Index.DeleteByQuery`: replace with `Index.DeleteBy`
* `Index.DeleteUserKey`: replace with `Client.DeleteAPIKey`
* `Index.GetAPIKey`: replace with `Client.GetAPIKey`
* `Index.GetObjectsAttrs`: replace with `Index.GetObjects(..., opt.AttributesToRetrieve(...))`
* `Index.GetUserKey`: replace with `Client.GetAPIKey`
* `Index.ListKeys`: replace with `Client.ListAPIKeys`
* `Index.MoveTo`: replace with `Client.Move`
* `Index.Move`: replace with `Client.Move`
* `Index.PartialUpdateObjectNoCreate`: replace with `Index.PartialUpdateObject(..., opt.CreateIfNotExists(false))`
* `Index.PartialUpdateObjectsNoCreate`: replace with `Index.PartialUpdateObjects(..., opt.CreateIfNotExists(false))`
* `Index.ScopedCopy`: replace with `Client.Copy(..., opt.Scopes(...))`
* `Index.SearchFacet`: replace with `Index.SearchForFacetValues`
* `Index.UpdateAPIKey`: replace with `Client.UpdateAPIKey`
* `Index.UpdateObject`: replace with `Index.SaveObject`
* `Index.UpdateObjects`: replace with `Index.SaveObjects`
* `Index.UpdateUserKey`: replace with `Client.UpdateAPIKey`
