Skip to content

Commit 6c1cc7f

Browse files
committed
Implemented the files API's
1 parent 1842a3a commit 6c1cc7f

7 files changed

Lines changed: 305 additions & 4 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ import "github.com/NdoleStudio/lemonsqueezy-go"
4141
- **Variants**
4242
- `GET /v1/variants/:id`: Retrieve a variant
4343
- `GET /v1/variants`: List all variants
44+
- **Files**
45+
- `GET /v1/files/:id`: Retrieve a file
46+
- `GET /v1/files`: List all files
4447
- **Subscriptions**
4548
- `PATCH /v1/subscriptions/:id`: Update a subscription
4649
- `GET /v1/subscriptions/:id`: Retrieve a subscription

client.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ type Client struct {
2828
Customers *CustomersService
2929
Products *ProductsService
3030
Variants *VariantsService
31+
Files *FilesService
3132
}
3233

3334
// New creates and returns a new Client from a slice of Option.
@@ -53,6 +54,7 @@ func New(options ...Option) *Client {
5354
client.Customers = (*CustomersService)(&client.common)
5455
client.Products = (*ProductsService)(&client.common)
5556
client.Variants = (*VariantsService)(&client.common)
57+
client.Files = (*FilesService)(&client.common)
5658

5759
return client
5860
}

file.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package client
2+
3+
import "time"
4+
5+
// FileAttributes represents a digital good that can be downloaded by a customer after the product has been purchased.
6+
type FileAttributes struct {
7+
VariantID int `json:"variant_id"`
8+
Identifier string `json:"identifier"`
9+
Name string `json:"name"`
10+
Extension string `json:"extension"`
11+
DownloadURL string `json:"download_url"`
12+
Size int `json:"size"`
13+
SizeFormatted string `json:"size_formatted"`
14+
Version string `json:"version"`
15+
Sort int `json:"sort"`
16+
Status string `json:"status"`
17+
CreatedAt time.Time `json:"createdAt"`
18+
UpdatedAt time.Time `json:"updatedAt"`
19+
}
20+
21+
// ApiResponseRelationshipsFile relationships of a file
22+
type ApiResponseRelationshipsFile struct {
23+
Variant ApiResponseLinks `json:"variant"`
24+
}
25+
26+
// FileApiResponse is the api response for one file
27+
type FileApiResponse = ApiResponse[FileAttributes, ApiResponseRelationshipsFile]
28+
29+
// FilesApiResponse is the api response for a list of files.
30+
type FilesApiResponse = ApiResponseList[FileAttributes, ApiResponseRelationshipsFile]

file_service.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package client
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"net/http"
7+
)
8+
9+
// FilesService is the API client for the `/v1/files` endpoint
10+
type FilesService service
11+
12+
// Get returns the file with the given ID.
13+
//
14+
// https://docs.lemonsqueezy.com/api/files#retrieve-a-file
15+
func (service *FilesService) Get(ctx context.Context, fileID string) (*FileApiResponse, *Response, error) {
16+
response, err := service.client.do(ctx, http.MethodGet, "/v1/files/"+fileID)
17+
if err != nil {
18+
return nil, response, err
19+
}
20+
21+
file := new(FileApiResponse)
22+
if err = json.Unmarshal(*response.Body, file); err != nil {
23+
return nil, response, err
24+
}
25+
26+
return file, response, nil
27+
}
28+
29+
// List returns a paginated list of files.
30+
//
31+
// https://docs.lemonsqueezy.com/api/files#list-all-files
32+
func (service *FilesService) List(ctx context.Context) (*FilesApiResponse, *Response, error) {
33+
response, err := service.client.do(ctx, http.MethodGet, "/v1/files")
34+
if err != nil {
35+
return nil, response, err
36+
}
37+
38+
files := new(FilesApiResponse)
39+
if err = json.Unmarshal(*response.Body, files); err != nil {
40+
return nil, response, err
41+
}
42+
43+
return files, response, nil
44+
}

files_service_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package client
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"testing"
7+
8+
"github.com/NdoleStudio/lemonsqueezy-go/internal/helpers"
9+
"github.com/NdoleStudio/lemonsqueezy-go/internal/stubs"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestFilesService_Get(t *testing.T) {
14+
// Setup
15+
t.Parallel()
16+
17+
// Arrange
18+
server := helpers.MakeTestServer(http.StatusOK, stubs.FileGetResponse())
19+
client := New(WithBaseURL(server.URL))
20+
21+
// Act
22+
file, response, err := client.Files.Get(context.Background(), "1")
23+
24+
// Assert
25+
assert.Nil(t, err)
26+
27+
assert.Equal(t, http.StatusOK, response.HTTPResponse.StatusCode)
28+
assert.Equal(t, stubs.FileGetResponse(), *response.Body)
29+
assert.Equal(t, "1", file.Data.ID)
30+
31+
// Teardown
32+
server.Close()
33+
}
34+
35+
func TestFilesService_GetWithError(t *testing.T) {
36+
// Setup
37+
t.Parallel()
38+
39+
// Arrange
40+
server := helpers.MakeTestServer(http.StatusInternalServerError, nil)
41+
client := New(WithBaseURL(server.URL))
42+
43+
// Act
44+
_, response, err := client.Files.Get(context.Background(), "1")
45+
46+
// Assert
47+
assert.NotNil(t, err)
48+
49+
assert.Equal(t, http.StatusInternalServerError, response.HTTPResponse.StatusCode)
50+
51+
// Teardown
52+
server.Close()
53+
}
54+
55+
func TestFilesService_List(t *testing.T) {
56+
// Setup
57+
t.Parallel()
58+
59+
// Arrange
60+
server := helpers.MakeTestServer(http.StatusOK, stubs.FilesListResponse())
61+
client := New(WithBaseURL(server.URL))
62+
63+
// Act
64+
files, response, err := client.Files.List(context.Background())
65+
66+
// Assert
67+
assert.Nil(t, err)
68+
69+
assert.Equal(t, http.StatusOK, response.HTTPResponse.StatusCode)
70+
assert.Equal(t, stubs.FilesListResponse(), *response.Body)
71+
assert.Equal(t, 2, len(files.Data))
72+
73+
// Teardown
74+
server.Close()
75+
}
76+
77+
func TestFilesService_ListWithError(t *testing.T) {
78+
// Setup
79+
t.Parallel()
80+
81+
// Arrange
82+
server := helpers.MakeTestServer(http.StatusInternalServerError, nil)
83+
client := New(WithBaseURL(server.URL))
84+
85+
// Act
86+
_, response, err := client.Files.List(context.Background())
87+
88+
// Assert
89+
assert.NotNil(t, err)
90+
91+
assert.Equal(t, http.StatusInternalServerError, response.HTTPResponse.StatusCode)
92+
93+
// Teardown
94+
server.Close()
95+
}

go.mod

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@ module github.com/NdoleStudio/lemonsqueezy-go
22

33
go 1.19
44

5-
require (
6-
github.com/davecgh/go-spew v1.1.1
7-
github.com/stretchr/testify v1.8.1
8-
)
5+
require github.com/stretchr/testify v1.8.1
96

107
require (
8+
github.com/davecgh/go-spew v1.1.1 // indirect
119
github.com/pmezard/go-difflib v1.0.0 // indirect
1210
gopkg.in/yaml.v3 v3.0.1 // indirect
1311
)

internal/stubs/file.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package stubs
2+
3+
// FileGetResponse is a dummy response to the GET /v1/files/:id endpoint
4+
func FileGetResponse() []byte {
5+
return []byte(`
6+
{
7+
"jsonapi": {
8+
"version": "1.0"
9+
},
10+
"links": {
11+
"self": "https://api.lemonsqueezy.com/v1/files/1"
12+
},
13+
"data": {
14+
"type": "files",
15+
"id": "1",
16+
"attributes": {
17+
"variant_id": 168,
18+
"identifier": "6dce5ba7-76f2-481f-ad1e-9c2bec6eb0e2",
19+
"name": "my_product.zip",
20+
"extension": "zip",
21+
"download_url": "https://app.lemonsqueezy.com/download/6dce5ba7-76f2-481f-ad1e-9c2bec6eb0e2?expires=1636384018&signature=f0a9bdec44ffabf143d4689594491f42a76d773d3cc88ec23ef84d6e903e8f11",
22+
"size": 874694,
23+
"size_formatted": "854 KB",
24+
"version": "1.0.0",
25+
"sort": 1,
26+
"status": "published",
27+
"createdAt": "2021-11-05T10:22:14.000000Z",
28+
"updatedAt": "2021-11-05T16:16:33.000000Z"
29+
},
30+
"relationships": {
31+
"variant": {
32+
"links": {
33+
"related": "https://api.lemonsqueezy.com/v1/files/1/variant",
34+
"self": "https://api.lemonsqueezy.com/v1/files/1/relationships/variant"
35+
}
36+
}
37+
},
38+
"links": {
39+
"self": "https://api.lemonsqueezy.com/v1/files/1"
40+
}
41+
}
42+
}
43+
`)
44+
}
45+
46+
// FilesListResponse is a dummy response to GET /v1/files
47+
func FilesListResponse() []byte {
48+
return []byte(`
49+
{
50+
"meta": {
51+
"page": {
52+
"currentPage": 1,
53+
"from": 1,
54+
"lastPage": 1,
55+
"perPage": 10,
56+
"to": 10,
57+
"total": 10
58+
}
59+
},
60+
"jsonapi": {
61+
"version": "1.0"
62+
},
63+
"links": {
64+
"first": "https://api.lemonsqueezy.com/v1/files?page%5Bnumber%5D=1&page%5Bsize%5D=10&sort=sort",
65+
"last": "https://api.lemonsqueezy.com/v1/files?page%5Bnumber%5D=1&page%5Bsize%5D=10&sort=sort"
66+
},
67+
"data": [
68+
{
69+
"type": "files",
70+
"id": "1",
71+
"attributes": {
72+
"variant_id": 168,
73+
"identifier": "6dce5ba7-76f2-481f-ad1e-9c2bec6eb0e2",
74+
"name": "my_product.zip",
75+
"extension": "zip",
76+
"download_url": "https://app.lemonsqueezy.com/download/6dce5ba7-76f2-481f-ad1e-9c2bec6eb0e2?expires=1636383388&signature=886a63faf7215c54011accfa08578b1b687def66f767092629f263061b3a253a",
77+
"size": 874694,
78+
"size_formatted": "854 KB",
79+
"version": "1.0.0",
80+
"sort": 1,
81+
"status": "published",
82+
"createdAt": "2021-11-05T10:22:14.000000Z",
83+
"updatedAt": "2021-11-05T16:16:33.000000Z"
84+
},
85+
"relationships": {
86+
"variant": {
87+
"links": {
88+
"related": "https://api.lemonsqueezy.com/v1/files/1/variant",
89+
"self": "https://api.lemonsqueezy.com/v1/files/1/relationships/variant"
90+
}
91+
}
92+
},
93+
"links": {
94+
"self": "https://api.lemonsqueezy.com/v1/files/1"
95+
}
96+
},
97+
{
98+
"type": "files",
99+
"id": "2",
100+
"attributes": {
101+
"variant_id": 168,
102+
"identifier": "6dce5ba7-76f2-481f-ad1e-9c2bec6eb0e2",
103+
"name": "my_product.zip",
104+
"extension": "zip",
105+
"download_url": "https://app.lemonsqueezy.com/download/6dce5ba7-76f2-481f-ad1e-9c2bec6eb0e2?expires=1636383388&signature=886a63faf7215c54011accfa08578b1b687def66f767092629f263061b3a253a",
106+
"size": 874694,
107+
"size_formatted": "854 KB",
108+
"version": "1.0.0",
109+
"sort": 1,
110+
"status": "published",
111+
"createdAt": "2021-11-05T10:22:14.000000Z",
112+
"updatedAt": "2021-11-05T16:16:33.000000Z"
113+
},
114+
"relationships": {
115+
"variant": {
116+
"links": {
117+
"related": "https://api.lemonsqueezy.com/v1/files/1/variant",
118+
"self": "https://api.lemonsqueezy.com/v1/files/1/relationships/variant"
119+
}
120+
}
121+
},
122+
"links": {
123+
"self": "https://api.lemonsqueezy.com/v1/files/1"
124+
}
125+
}
126+
]
127+
}
128+
`)
129+
}

0 commit comments

Comments
 (0)