Skip to content

Instantly share code, notes, and snippets.

@cbluth
Forked from cnjax/pocketbase.go
Created June 8, 2023 11:44
Show Gist options
  • Save cbluth/c53a15fbafb4d0c5446ff9e9844db09a to your computer and use it in GitHub Desktop.
Save cbluth/c53a15fbafb4d0c5446ff9e9844db09a to your computer and use it in GitHub Desktop.

Revisions

  1. @cnjax cnjax revised this gist Mar 26, 2023. 1 changed file with 4 additions and 6 deletions.
    10 changes: 4 additions & 6 deletions pocketbase.go
    Original file line number Diff line number Diff line change
    @@ -3,11 +3,10 @@ package pocketbase
    import (
    "errors"
    "fmt"
    "time"

    "github.com/duke-git/lancet/v2/convertor"
    "github.com/go-resty/resty/v2"
    "golang.org/x/sync/singleflight"
    "time"
    )

    var ErrInvalidResponse = errors.New("invalid response")
    @@ -176,12 +175,12 @@ func (c *Client) auth() error {
    resp, err := c.client.R().
    SetHeader("Content-Type", "application/json").
    SetBody(map[string]interface{}{
    "email": c.email,
    "identity": c.email,
    "password": c.password,
    }).
    SetResult(&authResponse{}).
    SetHeader("Authorization", "").
    Post(c.url + "/api/admins/auth-via-email")
    Post(c.url + "/api/admins/auth-with-password")

    if err != nil {
    return nil, fmt.Errorf("[auth] can't send request to pocketbase %w", err)
    @@ -196,9 +195,8 @@ func (c *Client) auth() error {
    }

    auth := *resp.Result().(*authResponse)
    c.client.SetHeader("Authorization", "Admin "+auth.Token)
    c.client.SetHeader("Authorization", "Bearer "+auth.Token)
    c.tokenValid = time.Now().Add(60 * time.Minute)

    return nil, nil
    })
    return err
  2. @r--w r--w created this gist Nov 5, 2022.
    205 changes: 205 additions & 0 deletions pocketbase.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,205 @@
    package pocketbase

    import (
    "errors"
    "fmt"
    "time"

    "github.com/duke-git/lancet/v2/convertor"
    "github.com/go-resty/resty/v2"
    "golang.org/x/sync/singleflight"
    )

    var ErrInvalidResponse = errors.New("invalid response")

    type Client struct {
    client *resty.Client
    email string
    password string
    url string
    tokenValid time.Time
    tokenSingle singleflight.Group
    }

    type (
    authResponse struct {
    Token string `json:"token"`
    }

    Params struct {
    Page int
    Size int
    Filters string
    Sort string
    }
    )

    func NewClient(url, email, password string) *Client {
    client := resty.New()
    client.
    // SetDebug(true).
    SetRetryCount(3).
    SetRetryWaitTime(3 * time.Second).
    SetRetryMaxWaitTime(10 * time.Second)

    return &Client{
    client: client,
    url: url,
    email: email,
    password: password,
    tokenSingle: singleflight.Group{},
    }
    }

    func (c *Client) Update(collection string, id string, body any) error {
    if err := c.auth(); err != nil {
    return err
    }

    request := c.client.R().
    SetHeader("Content-Type", "application/json").
    SetPathParam("collection", collection).
    SetBody(body)

    resp, err := request.Patch(c.url + "/api/collections/{collection}/records/" + id)
    if err != nil {
    return fmt.Errorf("[update] can't send update request to pocketbase, err %w", err)
    }
    if resp.IsError() {
    return fmt.Errorf("[update] pocketbase returned status: %d, msg: %s, err %w",
    resp.StatusCode(),
    resp.String(),
    ErrInvalidResponse,
    )
    }

    return nil
    }

    func (c *Client) Create(collection string, body any) error {
    if err := c.auth(); err != nil {
    return err
    }

    request := c.client.R().
    SetHeader("Content-Type", "application/json").
    SetPathParam("collection", collection).
    SetBody(body)

    resp, err := request.Post(c.url + "/api/collections/{collection}/records")
    if err != nil {
    return fmt.Errorf("[create] can't send update request to pocketbase, err %w", err)
    }

    if resp.IsError() {
    return fmt.Errorf("[create] pocketbase returned status: %d, msg: %s, body: %s, err %w",
    resp.StatusCode(),
    resp.String(),
    fmt.Sprintf("%+v", body), // TODO remove that after debugging
    ErrInvalidResponse,
    )
    }

    return nil
    }

    func (c *Client) Delete(collection string, id string) error {
    if err := c.auth(); err != nil {
    return err
    }

    request := c.client.R().
    SetHeader("Content-Type", "application/json").
    SetPathParam("collection", collection).
    SetPathParam("id", id)

    resp, err := request.Delete(c.url + "/api/collections/{collection}/records/{id}")
    if err != nil {
    return fmt.Errorf("[delete] can't send update request to pocketbase, err %w", err)
    }

    if resp.IsError() {
    return fmt.Errorf("[delete] pocketbase returned status: %d, msg: %s, err %w",
    resp.StatusCode(),
    resp.String(),
    ErrInvalidResponse,
    )
    }

    return nil
    }

    func (c *Client) List(collection string, params Params) ([]byte, error) {
    if err := c.auth(); err != nil {
    return []byte{}, err
    }

    request := c.client.R().
    SetHeader("Content-Type", "application/json").
    SetPathParam("collection", collection)

    if params.Page > 0 {
    request.SetQueryParam("page", convertor.ToString(params.Page))
    }
    if params.Size > 0 {
    request.SetQueryParam("perPage", convertor.ToString(params.Size))
    }
    if params.Filters != "" {
    request.SetQueryParam("filter", params.Filters)
    }
    if params.Sort != "" {
    request.SetQueryParam("sort", params.Sort)
    }

    resp, err := request.Get(c.url + "/api/collections/{collection}/records")
    if err != nil {
    return []byte{}, fmt.Errorf("[list] can't send update request to pocketbase, err %w", err)
    }

    if resp.IsError() {
    return []byte{}, fmt.Errorf("[list] pocketbase returned status: %d, msg: %s, err %w",
    resp.StatusCode(),
    resp.String(),
    ErrInvalidResponse,
    )
    }

    return resp.Body(), nil
    }

    func (c *Client) auth() error {
    _, err, _ := c.tokenSingle.Do("auth", func() (interface{}, error) {
    if time.Now().Before(c.tokenValid) {
    return nil, nil
    }

    resp, err := c.client.R().
    SetHeader("Content-Type", "application/json").
    SetBody(map[string]interface{}{
    "email": c.email,
    "password": c.password,
    }).
    SetResult(&authResponse{}).
    SetHeader("Authorization", "").
    Post(c.url + "/api/admins/auth-via-email")

    if err != nil {
    return nil, fmt.Errorf("[auth] can't send request to pocketbase %w", err)
    }

    if resp.IsError() {
    return nil, fmt.Errorf("[auth] pocketbase returned status: %d, msg: %s, err %w",
    resp.StatusCode(),
    resp.String(),
    ErrInvalidResponse,
    )
    }

    auth := *resp.Result().(*authResponse)
    c.client.SetHeader("Authorization", "Admin "+auth.Token)
    c.tokenValid = time.Now().Add(60 * time.Minute)

    return nil, nil
    })
    return err
    }