Skip to content

Commit

Permalink
Merge pull request #2 from nao1215/nchika/add-public-apis
Browse files Browse the repository at this point in the history
Add GET /api/trades
  • Loading branch information
nao1215 authored Aug 3, 2024
2 parents 5bebda3 + 97f5fbc commit da9d111
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 32 deletions.
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
[![All Contributors](https://img.shields.io/badge/all_contributors-0-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->

[![Go Reference](https://pkg.go.dev/badge/github.com/nao1215/coincheck.svg)](https://pkg.go.dev/github.com/nao1215/coincheck)
![Coverage](https://raw.githubusercontent.com/nao1215/octocovs-central-repo/main/badges/nao1215/coincheck/coverage.svg)
[![MultiPlatformUnitTest](https://github.com/nao1215/coincheck/actions/workflows/unit_test.yml/badge.svg)](https://github.com/nao1215/coincheck/actions/workflows/unit_test.yml)
[![reviewdog](https://github.com/nao1215/coincheck/actions/workflows/reviewdog.yml/badge.svg)](https://github.com/nao1215/coincheck/actions/workflows/reviewdog.yml)
[![gitleaks](https://github.com/nao1215/coincheck/actions/workflows/gitleak.yml/badge.svg)](https://github.com/nao1215/coincheck/actions/workflows/gitleak.yml)


>[!IMPORTANT]
> This library is under development and is not yet ready for production use.
Expand All @@ -12,8 +19,8 @@ The coincheck package is a client for the API provided by Coincheck, Inc., which
- Private API: Requires authentication using the API Key and API Secret issued by the Coincheck service.

The coincheck package supports both Public and Private APIs.
- [Official API documentation](https://coincheck.com/documents/exchange/api)
- [Official API client](https://github.com/coincheckjp/coincheck-go)
- [Coincheck official API documentation](https://coincheck.com/documents/exchange/api)
- [Coincheck official API client](https://github.com/coincheckjp/coincheck-go)

## Supported OS and go version

Expand Down Expand Up @@ -78,7 +85,8 @@ If you want to execute the Private API, you need to create a client with the API

| API | Method Name |Description |
| :--- | :--- | :--- |
| GET /api/ticker | GetTicker() | Check latest ticker information |
| GET /api/ticker | GetTicker() | Check latest ticker information. |
| GET /api/trades | GetTrades() | You can get current order transactions. |

### Private API

Expand Down
20 changes: 20 additions & 0 deletions coincheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ package coincheck

import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
Expand Down Expand Up @@ -108,3 +110,21 @@ func (c *Client) createRequest(ctx context.Context, input createRequestInput) (*
req.Header.Add("cache-control", "no-cache")
return req, nil
}

// Do sends an HTTP request and returns an HTTP response.
func (c *Client) do(req *http.Request, output any) error {
resp, err := c.client.Do(req)
if err != nil {
return withPrefixError(err)
}
defer resp.Body.Close() //nolint: errcheck // ignore error

if resp.StatusCode != http.StatusOK {
return withPrefixError(fmt.Errorf("unexpected status code=%d", resp.StatusCode))
}

if err := json.NewDecoder(resp.Body).Decode(output); err != nil {
return withPrefixError(err)
}
return nil
}
11 changes: 11 additions & 0 deletions order.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package coincheck

// OrderType represents the order type.
type OrderType string

const (
// OrderTypeBuy is the order type of buy.
OrderTypeBuy OrderType = "buy"
// OrderTypeSell is the order type of sell.
OrderTypeSell OrderType = "sell"
)
26 changes: 26 additions & 0 deletions pagenation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package coincheck

// Pagination represents the pagination of coincheck API.
// It is possible to get by dividing the data.
type Pagination struct {
// Limit is the number of data to get.
Limit int `json:"limit"`
// PaginationOrder is the order of the data. You can specify "desc" or "asc".
PaginationOrder PaginationOrder `json:"order"`
// StartingAfter is the ID of the data to start getting.
// Greater than the specified ID. For example, if you specify 3, you will get data from ID 4.
StartingAfter int `json:"starting_after,omitempty"`
// EndingBefore is the ID of the data to end getting.
// Less than the specified ID. For example, if you specify 3, you will get data up to ID 2.
EndingBefore int `json:"ending_before,omitempty"`
}

// PaginationOrder represents the order of the pagination.
type PaginationOrder string

const (
// PaginationOrderDesc is the order of the pagination in descending order.
PaginationOrderDesc PaginationOrder = "desc"
// PaginationOrderAsc is the order of the pagination in ascending order.
PaginationOrderAsc PaginationOrder = "asc"
)
17 changes: 2 additions & 15 deletions ticker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package coincheck

import (
"context"
"encoding/json"
"fmt"
"net/http"
)

Expand Down Expand Up @@ -76,20 +74,9 @@ func (c *Client) GetTicker(ctx context.Context, input GetTickerInput) (*GetTicke
return nil, err
}

resp, err := c.client.Do(req)
if err != nil {
return nil, withPrefixError(err)
}
defer resp.Body.Close() //nolint: errcheck // ignore error

if resp.StatusCode != http.StatusOK {
fmt.Println(req.URL)
return nil, withPrefixError(fmt.Errorf("unexpected status code=%d", resp.StatusCode))
}

var output GetTickerResponse
if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
return nil, withPrefixError(err)
if err := c.do(req, &output); err != nil {
return nil, err
}
return &output, nil
}
60 changes: 60 additions & 0 deletions trade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package coincheck

import (
"context"
"net/http"
)

// GetTradesInput represents the input parameter for GetTrades
type GetTradesInput struct {
// Pair is the pair of the currency. e.g. btc_jpy.
Pair Pair
}

// GetTradesResponse represents the output from GetTrades
type GetTradesResponse struct {
// Success is a boolean value that indicates the success of the API call.
Success bool `json:"success"`
// Pagination is the pagination of the data.
Pagination Pagination `json:"pagination"`
// Data is a list of trades.
Data []Trade `json:"data"`
}

// Trade represents a trade.
type Trade struct {
// ID is the trade ID.
ID int `json:"id"`
// Amount is the amount of the trade.
Amount float64 `json:"amount"`
// Rate is the rate of the trade.
Rate float64 `json:"rate"`
// Pair is the pair of the currency.
Pair Pair `json:"pair"`
// OrderType is the order type.
OrderType OrderType `json:"order_type"`
// CreatedAt is the creation time of the trade.
CreatedAt string `json:"created_at"`
}

// GetTrades returns a list of trades (order transactions).
// API: GET /api/trades
// Visibility: Public
func (c *Client) GetTrades(ctx context.Context, input GetTradesInput) (*GetTradesResponse, error) {
req, err := c.createRequest(ctx, createRequestInput{
method: http.MethodGet,
path: "/api/trades",
queryParam: map[string]string{
"pair": string(input.Pair),
},
})
if err != nil {
return nil, err
}

var output GetTradesResponse
if err := c.do(req, &output); err != nil {
return nil, err
}
return &output, nil
}
125 changes: 125 additions & 0 deletions trade_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package coincheck

import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"

"github.com/google/go-cmp/cmp"
)

func TestClient_GetTrades(t *testing.T) {
t.Run("In the case of a successful GET /api/trades request", func(t *testing.T) {
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
wantMethod := http.MethodGet
if got := r.Method; got != wantMethod {
t.Errorf("Method: got %v, want %v", got, wantMethod)
}

wantEndpoint := "/api/trades"
if got := r.URL.Path; got != wantEndpoint {
t.Errorf("Endpoint: got %v, want %v", got, wantEndpoint)
}

wantPair := PairETCJPY
if got := r.URL.Query().Get("pair"); got != wantPair.String() {
t.Errorf("Pair: got %v, want %v", got, wantPair)
}

result := GetTradesResponse{
Success: true,
Pagination: Pagination{
Limit: 1,
PaginationOrder: "desc",
StartingAfter: 0,
EndingBefore: 0,
},
Data: []Trade{
{
ID: 1,
Amount: 1,
Rate: 1000000,
Pair: PairETCJPY,
OrderType: OrderTypeBuy,
CreatedAt: "2021-01-01T00:00:00Z",
},
{
ID: 2,
Amount: 2,
Rate: 2000000,
Pair: PairETCJPY,
OrderType: OrderTypeSell,
CreatedAt: "2021-01-02T00:00:00Z",
},
},
}
if err := json.NewEncoder(w).Encode(result); err != nil {
t.Fatal(err)
}
}))

client, err := NewClient(WithBaseURL(testServer.URL))
if err != nil {
t.Fatal(err)
}

input := GetTradesInput{
Pair: PairETCJPY,
}
got, err := client.GetTrades(context.Background(), input)
if err != nil {
t.Fatal(err)
}

want := &GetTradesResponse{
Success: true,
Pagination: Pagination{
Limit: 1,
PaginationOrder: PaginationOrderDesc,
StartingAfter: 0,
EndingBefore: 0,
},
Data: []Trade{
{
ID: 1,
Amount: 1,
Rate: 1000000,
Pair: PairETCJPY,
OrderType: OrderTypeBuy,
CreatedAt: "2021-01-01T00:00:00Z",
},
{
ID: 2,
Amount: 2,
Rate: 2000000,
Pair: PairETCJPY,
OrderType: OrderTypeSell,
CreatedAt: "2021-01-02T00:00:00Z",
},
},
}
if diff := cmp.Diff(want, got); diff != "" {
printDiff(t, diff)
}
})

t.Run("In the case of a failed GET /api/trades request", func(t *testing.T) {
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
}))

client, err := NewClient(WithBaseURL(testServer.URL))
if err != nil {
t.Fatal(err)
}

input := GetTradesInput{
Pair: PairETCJPY,
}
if _, err = client.GetTrades(context.Background(), input); err == nil {
t.Fatal("err must not be nil")
}
})
}
16 changes: 2 additions & 14 deletions withdraw.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package coincheck

import (
"context"
"encoding/json"
"fmt"
"net/http"
)

Expand Down Expand Up @@ -46,19 +44,9 @@ func (c *Client) GetBankAccounts(ctx context.Context) (*GetBankAccountsResponse,
return nil, err
}

resp, err := c.client.Do(req)
if err != nil {
return nil, withPrefixError(err)
}
defer resp.Body.Close() //nolint: errcheck // ignore error

if resp.StatusCode != http.StatusOK {
return nil, withPrefixError(fmt.Errorf("unexpected status code=%d", resp.StatusCode))
}

var output GetBankAccountsResponse
if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
return nil, withPrefixError(err)
if err := c.do(req, &output); err != nil {
return nil, err
}
return &output, nil
}

0 comments on commit da9d111

Please sign in to comment.