Giter Site home page Giter Site logo

planetscale / planetscale-go Goto Github PK

View Code? Open in Web Editor NEW
125.0 9.0 10.0 1.05 MB

Go client library to access the PlanetScale API

Home Page: https://www.planetscale.com

License: Apache License 2.0

Go 99.85% Makefile 0.15%
go mysql database planetscale vitess

planetscale-go's Introduction

planetscale-go Go Reference Build status

Go package to access the PlanetScale API.

Install

go get github.com/planetscale/planetscale-go/planetscale

Usage

Here is an example application using the PlanetScale Go client. You can create and manage your service tokens via our pscale CLI with the pscale service-token subcommand.

package main

import (
	"context"
	"log"
	"os"
	"time"

	"github.com/planetscale/planetscale-go/planetscale"
)

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// Create a new PlanetScale API client with the given service token.
	client, err := planetscale.NewClient(
		planetscale.WithServiceToken("token-id", os.Getenv("PLANETSCALE_TOKEN")),
	)
	if err != nil {
		log.Fatalf("failed to create client: %v", err)
	}

	// Create a new database.
	_, err = client.Databases.Create(ctx, &planetscale.CreateDatabaseRequest{
		Organization: "my-org",
		Name:         "my-awesome-database",
		Notes:        "This is a test DB created via the planetscale-go API library",
	})
	if err != nil {
		log.Fatalf("failed to create database: %v", err)
	}

	// List all databases for the given organization.
	databases, err := client.Databases.List(ctx, &planetscale.ListDatabasesRequest{
		Organization: "my-org",
	})
	if err != nil {
		log.Fatalf("failed to list databases: %v", err)
	}

	log.Printf("found %d databases:", len(databases))
	for _, db := range databases {
		log.Printf("  - %q: %s", db.Name, db.Notes)
	}

	// Delete a database.
	_, err = client.Databases.Delete(ctx, &planetscale.DeleteDatabaseRequest{
		Organization: "my-org",
		Database:     "my-awesome-database",
	})
	if err != nil {
		log.Fatalf("failed to delete database: %v", err)
	}
}

planetscale-go's People

Contributors

croaky avatar dbussink avatar dependabot[bot] avatar dgraham avatar fatih avatar frouioui avatar iheanyi avatar jtcunning avatar kevinschoonover avatar marwan-at-work avatar mattrobenolt avatar mdlayher avatar mscoutermarsh avatar nickvanw avatar no-itsbackpack avatar notfelineit avatar sorcererxw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

planetscale-go's Issues

Access token vs service token

Given the following:

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/planetscale/planetscale-go/planetscale"
	"github.com/planetscale/planetscale-go/planetscale/dbutil"
)

func main() {
	token := os.Getenv("PLANETSCALE_TOKEN")
	ctx := context.Background()
	client, _ := planetscale.NewClient(
		planetscale.WithAccessToken(token),
	)
	dialCfg := &dbutil.DialConfig{
		Organization: "croaky",
		Database:     "go",
		Branch:       "main",
		Client:       client,
	}
	db, err := dbutil.Dial(ctx, dialCfg)
	if err != nil {
		log.Fatalln(err)
	}
	var version string
	_ = db.QueryRow("SELECT VERSION()").Scan(&version)
	fmt.Println(version)
}

And go.mod:

module psdb

go 1.16

require github.com/planetscale/planetscale-go v0.27.0

This works as expected:

% PLANETSCALE_TOKEN=$(cat ~/.config/planetscale/access-token) go run main.go
8.0.23

But using a service token per these docs results in an error result from dbutil.Dial:

% pscale service-token create

  NAME           TOKEN                                     
 -------------- ------------------------------------------ 
  redacted-name redacted-token

psdb-go main % pscale service-token add-access redacted-name connect_production_branch --database go
  DATABASE   ACCESSES                   
 ---------- --------------------------- 
  go         connect_production_branch  

% PLANETSCALE_TOKEN=redacted-token go run main.go
2021/05/24 12:11:04 internal error, please open an issue to github.com/planetscale/planetscale-go
exit status 1

Should a service token work here? Thanks!

Improve the repo layout by creating a subfolder for the API

Currently, we dump all the Go code into the root repo dir. The benefit is that people can import the API in this form:

go get github.com/planetscale/planetscale-go

And start using like this:

// create a new PlanetScale API client with the given access token
client, _ := planetscale.NewClient(
	planetscale.WithAccessToken(token),
)

However, as we see now, the root dir started to become larger and larger. We're probably going to extend this API with many new features in the future. To make sure the repo is clean and comfortable to read, I suggest we put the Go source code under a new folder:

go get github.com/planetscale/planetscale-go/planetscale

# or
go get github.com/planetscale/planetscale-go/psdb

I know that the URL reads longs, but the usage from the user's perspective will not change. They will still use it in this form:

// create a new PlanetScale API client with the given access token
client, _ := planetscale.NewClient(
	planetscale.WithAccessToken(token),
)

The benefits are:

  • We're not going to pollute the root dir
  • The repo will be easy to manage, and the Go source code will not be mixed with non-Go code
  • The ability to introduce a new API if needed, i.e.: github.com/planetscale/planetscale-go/flux

This is also how all the other major Go API's are currently organized:

401 Unauthorized returns nondescript error

If the API returns a 401, like if a bad token is passed into the client constructor, all errors will appear as internal error, response body doesn't match error type signature.

This is caused by the error message being non-standard from the API in:

// json.Unmarshal doesn't return an error if the response
// body has a different protocol then "ErrorResponse". We
// check here to make sure that errorRes is populated. If
// not, we return the full response back to the user, so
// they can debug the issue.
// TODO(fatih): fix the behavior on the API side
if *errorRes == (errorResponse{}) {
return &Error{
msg: "internal error, response body doesn't match error type signature",
Code: ErrInternal,
Meta: map[string]string{
"body": string(out),
"http_status": http.StatusText(res.StatusCode),
},
}
}

The response from the API is:

{"error":"invalid_token","error_description":"The access token is invalid","state":"unauthorized"}

The TODO is almost a year old. Is it worth adding a 2nd (deprecated) ErrorResponse type to handle this other structure?

Expose a way to create a PlanetScale Client using the same auth method as the CLI

From within planetscale/cli, everything as far as reading a config file and yanking an access token out of the OS keyring is locked away in internal packages internal to the CLI.

If I want to use this library in code, in theory, I'd like to instantiate a client that leverages my system's auth in a similar fashion. Whether this is fully depending on the config file pscale CLI writes, or just sharing some mechanism to yank an already auth'd token out of the keyring would be super nice.

This would allow tooling outside of pscale to "just work" without requiring use of the CLI.

Maybe just necessary for the keyring access being one of the constructor arguments?

client, err := planetscale.NewClient(
	planetscale.WithSystemKeyring(...),
)

or something similar is what I'm thinking. I'd like to leverage this rather than extract it and set it as an env var or pass as a flag to something else.

Thoughts?

service-token to create branch

I have created a service token to create a new branch but I am getting "not found" when I use it. Same code is working with access token.

How to generate access token?

The only option seems to be using pscale auth, UI only generates service tokens. We're integrating cloud APIs to collect asset data at Resmo we normally prefer OAuth or API keys and ask user to generate one for us. Planetscale also seems to have Oauth but it seems to be only for device, CLI m2m authentication?

Tasks

No tasks being tracked yet.

Listing regions errors with "requires authentication"

Hello,

I got a service token created which has been validated as working with other API operations.

Trying to list regions:

regions, err := d.client.Regions.List(ctx, &planetscale.ListRegionsRequest{})
	if err != nil {
		fmt.Print(err.Error())
		return
	}

however this fails with

Requires authentication

I've enabled all permissions across the db and org for my service token but still returns this error. Am I doing something wrong probably or is this an actual issue with the sdk/API?

Update: I might need to go through the d.client.Organizations.ListRegions func instead, but then I don't get the difference between the two?

panic: runtime error

my source code

package main

import (
	"context"
	"os"
	"fmt"

	"github.com/planetscale/planetscale-go/planetscale"
)

func main() {
	token := os.Getenv("PLANETSCALE_TOKEN")
	name := os.Getenv("PLANETSCALE_TOKEN_NAME")

	ctx := context.Background()

	// create a new PlanetScale API client with the given access token
	client, _ := planetscale.NewClient(
		planetscale.WithServiceToken(name, token),
	)
	databases, _ := client.Databases.List(ctx, &planetscale.ListDatabasesRequest{
		Organization: "my-org",
	})
	fmt.Printf("Found %d databases\n", len(databases))
}

given error

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x30 pc=0x3bd15d]

Add ability to have an optional name when creating a backup

POST /organizations/{organization}/databases/{database}/branches/{branch}/backups endpoint to create a backup supports a body param for name that would be useful for Terraform providers to be able to use from planetscale-go.

API reference for endpoint: https://api-docs.planetscale.com/reference/create-a-backup

Handy link to backups.go code:

path := backupsAPIPath(createReq.Organization, createReq.Database, createReq.Branch)

Might consider adding the option to pass in retention_unit and retention_value too.

Help getting a simple API example working please

The example in the README uses an access token, but I cannot find how to create one of those?

So, instead I'm trying to use the service token.

But, then I'm getting errors:

  • Regions.List gives Requires Authentication
  • Organizations.ListRegions gives Not Found

I'm stuck and obviously doing something silly / wrong. Can you please help explain how to get a simple API example working?

BTW, my ultimate goal is to create a Steampipe plugin.

Thanks!

Here is my code:

package main                                                                                                                                                                             
  
import (
  "context"
  "fmt"
    
  "github.com/planetscale/planetscale-go/planetscale"
) 
    
func main() {
  
  ctx := context.Background()
    
  // create a new PlanetScale API client with the given access token
  client, err := planetscale.NewClient(
    planetscale.WithServiceToken("nw-test-2", "pscale_tkn_SECRET"),
  )
  if err != nil {
    panic(err)
  } 
  
  // Error: Requires authentication
  regions, err := client.Regions.List(ctx, &planetscale.ListRegionsRequest{})
  if err != nil {
    panic(err)
  }
  fmt.Printf("Found %d regions\n", len(regions))
  for _, i := range regions {
    fmt.Printf("Name: %q\n", i.Name)
    fmt.Printf("Location: %q\n", i.Location)
  }
    
  // Error: Not Found
  orgRegions, err := client.Organizations.ListRegions(ctx, &planetscale.ListOrganizationRegionsRequest{
    Organization: "steampipe",
  })
  if err != nil {
    panic(err)
  }
  fmt.Printf("Found %d orgRegions\n", len(orgRegions))
  for _, i := range orgRegions {
    fmt.Printf("Name: %q\n", i.Name)
    fmt.Printf("Location: %q\n", i.Location)
  }
}

"please open an issue to github.com/planetscale/planetscale-go with the following output:"

I am just doing what the CLI tells me to:

C:\Users\Jan\Documents\throwaway\planetscale  ([email protected])
ฮป pscale backup create fk-test main
Error: internal error, please open an issue to github.com/planetscale/planetscale-go with the following output:

{"status":500,"error":"Internal Server Error"}

Probably not super useful output in the CLI, that probably comes from

msg: "internal error, please open an issue to github.com/planetscale/planetscale-go",
and indicates there might be some unhandled errors in this library.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.