I’m pleased to announce the Couchbase Go SDK 2.0 Alpha. This new SDK brings in a series of changes across all of the Couchbase SDKs that the team has been putting together. The new SDKs bring a completely new API which is simpler, future proof and integrates with the latest ecosystem developments.
Version 2.0 of the Go SDK aligns with new features to Couchbase Server that extend off of the traditional Bucket interface: support for Scopes and Collection. Additionally, it consolidates and refines the interface – improving cross-SDK conformance.
New Couchbase Server Features: Scopes and Collections
In previous Couchbase Server versions Buckets were used as logical, user-named entities that group items. This allowed them to be accessed, indexed, replicated, and access-controlled. This was really the only means of achieving multi-tenancy using Couchbase Server and came with some limitations: Buckets themselves are fairly resource intensive and a cluster can only efficiently manage a finite number of buckets. For modern micro-service architectures, or really any architecture where multi-tenancy was needed, this made for some challenges when serving a large amount of tenants. This is solved in a future version of Couchbase Server by the concepts of Scopes and Collections.
A Scope represents a unit of multi tenancy and is built of Collections. A Collection is effectively a unique name for a group of documents. Within a Scope a Collection name must be unique, but the same Collection name can be used across multiple Scopes. Every Bucket contains a default Scope with the name ā_defaultā with an identifier of 0 (zero) which contains a default Collection named ā_defaultā with its accompanying identifier of 0 (zero).
This has the effect of moving Key/Value operations which were in the Bucket context for SDK 1.0 into the Collection context for SDK 2.0. Cross Bucket operations such as Search, Analytics and N1QL are now done at the Cluster level.
Couchbase Server 6.5 will support Scopes and Collections as a part of “Developer Preview”, Developer Preview is notĀ supported for use in production. In the meantime, SDK 2.0 also supports Couchbase 5.0 and higher by using the default Scope and Collection.
Highlights of the SDK 2.0 API
The focus on this alpha is to provide the API to use Couchbase Server with Key/Value operations, N1QL, search, and analytics queries, as well as views. It contains the familiar Cluster and Bucket logical structures as well as the new Scope and Collections structures. Highlights can be grouped into two sections. The first is the new API which has been revamped across all SDKs to provide simpler, more future proof access patterns. The second is Go SDK specific enhancements.
Key Value API Improvements
The API has been significantly slimmed down and reworked so that the individual method calls are easier to find and more uniform. For Go this means we no longer need to have multiple calls for similar, but different, functions. We’ve also slimmed down the number of parameters required in some functions.
For example, in SDK 1.0 there were method signatures like:
1 2 3 |
func (b *Bucket) Insert(key string, value interface{}, expiry uint32) (Cas, error) func (b *Bucket) InsertDura(key string, value interface{}, expiry uint32, replicateTo, persistTo uint) (Cas, error) func (b *Bucket) Get(key string, valuePtr interface{}) (Cas, error) |
In SDK 2.0 this has changed to:
1 2 |
func (c *Collection) Insert(key string, val interface{}, opts *InsertOptions) (*MutationResult, error) func (c *Collection) Get(key string, opts *GetOptions) (*GetResult, error) |
Each method returns a *Result and has an optional parameter called *Options. Anything required for an operation to work is a parameter and optional properties (like the timeout, the durability requirements, the cas value etc…) have all been moved into options blocks. This has lead to fewer “overloaded” functions and a simpler overall API. Mutation type operation results contain things like CAS values and Mutation Token. For Fetch type operations the results contain ways to get your value and document expiration (if requested).
Options block are structs that look like:
1 2 3 4 5 6 7 8 9 10 11 |
type InsertOptions struct { ParentSpanContext opentracing.SpanContext Timeout time.Duration Context context.Context // The expiration length in seconds Expiration uint32 PersistTo uint ReplicateTo uint DurabilityLevel DurabilityLevel Encoder Encode } |
This provides much more flexibility at an operation level than the previous API. This means that previously if you wanted to do an insert with persist toĀ set then you had to do InsertDura("key", "value", 0, 0, 1) , now it’s just Insert("key", "value", &InsertOptions{PersistTo: 1})Ā .
We now have support for context.Context for cancellation. What this means is that you can use things like take the context from your HTTP handler and supply it straight into your gocb operation, so you have the same cancellation structure used throughout your HTTP request handler. If you don’t want to use Context for timeouts then don’t worry, you can just use the TimeoutĀ option instead.
Query API Improvements
The query APIs, much like the Key Value API, now useĀ *Options blocks for optional query properties. Previously the APIs looked like:
1 2 3 4 |
func (c *Cluster) ExecuteN1qlQuery(q *N1qlQuery, params interface{}) (QueryResults, error) func (c *Cluster) ExecuteAnalyticsQuery(q *AnalyticsQuery, params interface{}) (AnalyticsResults, error) func (c *Cluster) ExecuteSearchQuery(q *SearchQuery) (SearchResults, error) func (b *Bucket) ViewQuery(designDoc string, viewName string, opts *ViewOptions) (*ViewResults, error) |
It now looks like:
1 2 3 4 |
func (c *Cluster) Query(statement string, opts *QueryOptions) (*QueryResults, error) func (c *Cluster) AnalyticsQuery(statement string, opts *AnalyticsQueryOptions) (*AnalyticsResults, error) func (c *Cluster) SearchQuery(q SearchQuery, opts *SearchQueryOptions) (*SearchResults, error) func (b *Bucket) ViewQuery(designDoc string, viewName string, opts *ViewOptions) (*ViewResults, error) |
The options blocks for these are too big to include here but they look, and work, similar to the Key Value example above. We’ve also improved API consistency across the query services by updating how results are accessed. We’re still working on custom transcoding of these results. All of the services now also use streaming to retrieve the results under the hood, this means that you can query for huge datasets without having to worry about running out of memory.
Error Handling Improvements
Previously, we exposed sentinel errors (e.g. if err == gocb.ErrKeyNotFound ) that you had to match against if your operation returned an error and you had specific error types that you needed to handle. We’ve changed this, we now expose errors as types and also provide helper functions for categorising errors. You can now do if gocb.IsKeyNotFound(err), or type assert the entire error kvErr := err.(gocb.KeyValueError)Ā and get access to underlying context about the error if you need that too.
Getting Started
You can start using all of these enhancements by doing: go get github.com/couchbase/gocb@v2.0.0-alpha.3
Once you have the SDK then you can connect to a cluster, open a bucket and use the default collection. For now, unless you use the Developer Preview mode in Couchbase Server 6.5 then you’ll only be able use the default collection.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
cluster, err := gocb.Connect("localhost", gocb.ClusterOptions{Authenticator: gocb.PasswordAuthenticator{ Username: "username", Password: "password", }}) if err != nil { panic("error connecting to cluster:" + err.Error()) } bucket := cluster.Bucket("bucket-name", nil) collection := bucket.DefaultCollection(nil) // Now you can perform operations: upsertResult, err := collection.Upsert("somekey", "somevalue", &gocb.UpsertOptions{Timeout: 10*time.Millisecond}) if err != nil { panic(err) } fmt.Println(upsertResult.Cas()) getResult, err := collection.Get("somekey", nil) if err != nil { panic(err) } var myValue string err = getResult.Content(&myValue) if err != nil { panic(err) } ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond) defer cancel() results, err := cluster.Query("SELECT `bucket-name`.* from `bucket-name` LIMIT 10", &gocb.QueryOptions{ Context: ctx, }) if err != nil { panic(err) } var myQueryValue interface{} for results.Next(&myQueryValue) { } err = results.Close() if err != nil { panic(err) } |
Note that bucket open no longer returns an error, although this is still where connecting occurs. Instead, we defer returning errors until the first operation. In the future you will be able to check the health of the bucket connection before performing operations.
If you want to learn more, please take a look into our newĀ documentationĀ which is starting to come together as well.
The API is pretty new, and alpha, so is still subject to change – although it shouldn’t change drastically. We’d really appreciate all feedback and bug reports to make this the best SDK we have ever delivered. This is your chance to help shape the future of the Couchbase Go SDK.
How do we version?
All SDKs subscribe to the Semantic Versioning 2.0.0 Specification (SemVer) where for any given version number MAJOR.MINOR.PATCH, the version is incremented when:
MAJOR version when you make incompatible API changes,
MINOR version when you add functionality in a backwards-compatible manner, and
PATCH version when you make backwards-compatible bug fixes.
Additionally, for pre-releases and build metadata we add extensions to the SemVer Specification as allowed by it. For example, our early drops of SDK 2.0 use the alpha designation plus an increment for the alpha version. For example, our initial SDK 2.0 early previews used the following SemVer compliant version: 2.0.0-alpha.1 . The next pre-release after the alpha releases will be 2.0.0-beta.1 . Finally, a fully supported GA release will be 2.0.0 . In general, expect breaking changes between alpha versions. Breaking changes should not happen (but in some cases may be necessary) once beta is released.
Cover image by Maria Letta as a part of theĀ free gophers pack.