parent
858d552240
commit
d77d28b101
34
README.md
34
README.md
@ -6,7 +6,7 @@ go-discogs is a Go client library for the [Discogs API](https://www.discogs.com/
|
||||
|
||||
The lib is under MIT but be sure you are familiar with [Discogs API Terms of Use](https://support.discogs.com/hc/en-us/articles/360009334593-API-Terms-of-Use).
|
||||
|
||||
### Feauteres
|
||||
### Features
|
||||
* Database
|
||||
* [Releases](#releases)
|
||||
* Release Rating
|
||||
@ -17,6 +17,11 @@ The lib is under MIT but be sure you are familiar with [Discogs API Terms of Use
|
||||
* Label
|
||||
* All Label Releases
|
||||
* [Search](#search)
|
||||
* [User Collection](#user-collection)
|
||||
* Collection Folders
|
||||
* Folder
|
||||
* Collection Items by Folder
|
||||
* Collection Items by Release
|
||||
|
||||
Install
|
||||
--------
|
||||
@ -30,7 +35,7 @@ First of all import library and init client variable. According to discogs api d
|
||||
import "github.com/irlndts/go-discogs"
|
||||
```
|
||||
|
||||
Some requests require authentification (as any user). According to [Discogs](https://www.discogs.com/developers/#page:authentication,header:authentication-discogs-auth-flow), to send requests with Discogs Auth, you have two options: sending your credentials in the query string with key and secret parameters or a [token parameter](https://www.discogs.com/settings/developers).
|
||||
Some requests require authentication (as any user). According to [Discogs](https://www.discogs.com/developers/#page:authentication,header:authentication-discogs-auth-flow), to send requests with Discogs Auth, you have two options: sending your credentials in the query string with key and secret parameters or a [token parameter](https://www.discogs.com/settings/developers).
|
||||
|
||||
```go
|
||||
client, err := discogs.New(&discogs.Options{
|
||||
@ -88,3 +93,28 @@ Example
|
||||
fmt.Println(r.Title)
|
||||
}
|
||||
```
|
||||
|
||||
#### User Collection
|
||||
|
||||
Query a users [collection](https://www.discogs.com/developers#page:user-collection).
|
||||
|
||||
##### Collection Folders
|
||||
Example
|
||||
```go
|
||||
collection, err := client.CollectionFolders("my_user")
|
||||
```
|
||||
##### Folder
|
||||
Example
|
||||
```go
|
||||
folder, err := client.Folder("my_user", 0)
|
||||
```
|
||||
##### Collection Items by Folder
|
||||
Example
|
||||
```go
|
||||
items, err := client.CollectionItemsByFolder("my_user", 0, &Pagination{Sort: "artist", SortOrder: "desc", PerPage: 2})
|
||||
```
|
||||
##### Collection Items by Release
|
||||
Example
|
||||
```go
|
||||
items, err := client.CollectionItemsByRelease("my_user", 12934893)
|
||||
```
|
||||
|
@ -26,11 +26,13 @@ type Options struct {
|
||||
|
||||
// Discogs is an interface for making Discogs API requests.
|
||||
type Discogs interface {
|
||||
CollectionService
|
||||
DatabaseService
|
||||
SearchService
|
||||
}
|
||||
|
||||
type discogs struct {
|
||||
CollectionService
|
||||
DatabaseService
|
||||
SearchService
|
||||
}
|
||||
@ -62,6 +64,7 @@ func New(o *Options) (Discogs, error) {
|
||||
}
|
||||
|
||||
return discogs{
|
||||
newCollectionService(o.URL + "/users"),
|
||||
newDatabaseService(o.URL, cur),
|
||||
newSearchService(o.URL + "/database/search"),
|
||||
}, nil
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
const (
|
||||
testUserAgent = "UnitTestClient/0.0.2"
|
||||
testUsername = "test_user"
|
||||
testToken = ""
|
||||
)
|
||||
|
||||
|
@ -19,4 +19,7 @@ var (
|
||||
ErrUnauthorized = &Error{"authentication required"}
|
||||
ErrCurrencyNotSupported = &Error{"currency does not supported"}
|
||||
ErrUserAgentInvalid = &Error{"invalid user-agent"}
|
||||
ErrInvalidReleaseID = &Error{"invalid release id"}
|
||||
ErrInvalidSortKey = &Error{"invalid sort key"}
|
||||
ErrInvalidUsername = &Error{"invalid username"}
|
||||
)
|
||||
|
@ -78,6 +78,7 @@ type Format struct {
|
||||
Descriptions []string `json:"descriptions"`
|
||||
Name string `json:"name"`
|
||||
Qty string `json:"qty"`
|
||||
Text string `json:"text,omitempty"`
|
||||
}
|
||||
|
||||
// Company ...
|
||||
@ -130,8 +131,8 @@ type Page struct {
|
||||
|
||||
// URLsList ...
|
||||
type URLsList struct {
|
||||
Last string `json:"last"`
|
||||
Next string `json:"next"`
|
||||
Last string `json:"last,omitempty"`
|
||||
Next string `json:"next,omitempty"`
|
||||
}
|
||||
|
||||
// Version ...
|
||||
@ -188,7 +189,9 @@ type ReleaseSource struct {
|
||||
|
||||
// Pagination ...
|
||||
type Pagination struct {
|
||||
Sort string // year, title, format
|
||||
// TODO(irlndts): validate requested Sort
|
||||
Sort string // year, title, format etc
|
||||
// TODO(irlndts): validate requested SortOrder
|
||||
SortOrder string // asc, desc
|
||||
Page int
|
||||
PerPage int
|
||||
|
File diff suppressed because one or more lines are too long
135
user_collection.go
Normal file
135
user_collection.go
Normal file
@ -0,0 +1,135 @@
|
||||
package discogs
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// CollectionService is an interface to work with collection.
|
||||
type CollectionService interface {
|
||||
// Retrieve a list of folders in a user’s collection.
|
||||
// If folder_id is not 0, authentication as the collection owner is required.
|
||||
CollectionFolders(username string) (*CollectionFolders, error)
|
||||
// Retrieve a list of items in a folder in a user’s collection.
|
||||
// If folderID is not 0, authentication with token is required.
|
||||
CollectionItemsByFolder(username string, folderID int, pagination *Pagination) (*CollectionItems, error)
|
||||
// Retrieve the user’s collection folders which contain a specified release.
|
||||
// The releaseID must be non-zero.
|
||||
CollectionItemsByRelease(username string, releaseID int) (*CollectionItems, error)
|
||||
// Retrieve metadata about a folder in a user’s collection.
|
||||
Folder(username string, folderID int) (*Folder, error)
|
||||
}
|
||||
|
||||
type collectionService struct {
|
||||
url string
|
||||
}
|
||||
|
||||
func newCollectionService(url string) CollectionService {
|
||||
return &collectionService{
|
||||
url: url,
|
||||
}
|
||||
}
|
||||
|
||||
// Folder serves folder response from discogs.
|
||||
type Folder struct {
|
||||
ID int `json:"id"`
|
||||
Count int `json:"count"`
|
||||
Name string `json:"name"`
|
||||
ResourceURL string `json:"resource_url"`
|
||||
}
|
||||
|
||||
func (s *collectionService) Folder(username string, folderID int) (*Folder, error) {
|
||||
if username == "" {
|
||||
return nil, ErrInvalidUsername
|
||||
}
|
||||
var folder *Folder
|
||||
err := request(s.url+"/"+username+"/collection/folders/"+strconv.Itoa(folderID), nil, &folder)
|
||||
return folder, err
|
||||
}
|
||||
|
||||
// CollectionFolders serves collection response from discogs.
|
||||
type CollectionFolders struct {
|
||||
Folders []Folder `json:"folders"`
|
||||
}
|
||||
|
||||
func (s *collectionService) CollectionFolders(username string) (*CollectionFolders, error) {
|
||||
if username == "" {
|
||||
return nil, ErrInvalidUsername
|
||||
}
|
||||
var collection *CollectionFolders
|
||||
err := request(s.url+"/"+username+"/collection/folders", nil, &collection)
|
||||
return collection, err
|
||||
}
|
||||
|
||||
// CollectionItemSource ...
|
||||
type CollectionItemSource struct {
|
||||
ID int `json:"id"`
|
||||
BasicInformation BasicInformation `json:"basic_information"`
|
||||
DateAdded string `json:"date_added"`
|
||||
FolderID int `json:"folder_id,omitempty"`
|
||||
InstanceID int `json:"instance_id"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
Rating int `json:"rating"`
|
||||
}
|
||||
|
||||
// BasicInformation ...
|
||||
type BasicInformation struct {
|
||||
ID int `json:"id"`
|
||||
Artists []ArtistSource `json:"artists"`
|
||||
CoverImage string `json:"cover_image"`
|
||||
Formats []Format `json:"formats"`
|
||||
Labels []LabelSource `json:"labels"`
|
||||
Genres []string `json:"genres"`
|
||||
MasterID int `json:"master_id"`
|
||||
MasterURL *string `json:"master_url"`
|
||||
ResourceURL string `json:"resource_url"`
|
||||
Styles []string `json:"styles"`
|
||||
Thumb string `json:"thumb"`
|
||||
Title string `json:"title"`
|
||||
Year int `json:"year"`
|
||||
}
|
||||
|
||||
// CollectionItems list of items in a user’s collection
|
||||
type CollectionItems struct {
|
||||
Pagination Page `json:"pagination"`
|
||||
Items []CollectionItemSource `json:"releases"`
|
||||
}
|
||||
|
||||
// valid sort keys
|
||||
// https://www.discogs.com/developers#page:user-collection,header:user-collection-collection-items-by-folder
|
||||
var validItemsByFolderSort = map[string]struct{}{
|
||||
"": struct{}{},
|
||||
"label": struct{}{},
|
||||
"artist": struct{}{},
|
||||
"title": struct{}{},
|
||||
"catno": struct{}{},
|
||||
"format": struct{}{},
|
||||
"rating": struct{}{},
|
||||
"added": struct{}{},
|
||||
"year": struct{}{},
|
||||
}
|
||||
|
||||
func (s *collectionService) CollectionItemsByFolder(username string, folderID int, pagination *Pagination) (*CollectionItems, error) {
|
||||
if username == "" {
|
||||
return nil, ErrInvalidUsername
|
||||
}
|
||||
if pagination != nil {
|
||||
if _, ok := validItemsByFolderSort[pagination.Sort]; !ok {
|
||||
return nil, ErrInvalidSortKey
|
||||
}
|
||||
}
|
||||
var items *CollectionItems
|
||||
err := request(s.url+"/"+username+"/collection/folders/"+strconv.Itoa(folderID)+"/releases", pagination.params(), &items)
|
||||
return items, err
|
||||
}
|
||||
|
||||
func (s *collectionService) CollectionItemsByRelease(username string, releaseID int) (*CollectionItems, error) {
|
||||
if username == "" {
|
||||
return nil, ErrInvalidUsername
|
||||
}
|
||||
if releaseID == 0 {
|
||||
return nil, ErrInvalidReleaseID
|
||||
}
|
||||
var items *CollectionItems
|
||||
err := request(s.url+"/"+username+"/collection/releases/"+strconv.Itoa(releaseID), nil, &items)
|
||||
return items, err
|
||||
}
|
174
user_collection_test.go
Normal file
174
user_collection_test.go
Normal file
@ -0,0 +1,174 @@
|
||||
package discogs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func CollectionServer(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
switch r.URL.Path {
|
||||
case "/users/" + testUsername + "/collection/folders":
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if _, err := io.WriteString(w, collectionJson); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
case "/users/" + testUsername + "/collection/folders/0":
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if _, err := io.WriteString(w, folderJson); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
case "/users/" + testUsername + "/collection/folders/0/releases":
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if _, err := io.WriteString(w, collectionItemsByFolderJson); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
case "/users/" + testUsername + "/collection/releases/12934893":
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if _, err := io.WriteString(w, collectionItemsByRelease); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCollectionServiceFolder(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(CollectionServer))
|
||||
defer ts.Close()
|
||||
|
||||
d := initDiscogsClient(t, &Options{URL: ts.URL})
|
||||
|
||||
folder, err := d.Folder(testUsername, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get folder: %s", err)
|
||||
}
|
||||
|
||||
json, err := json.Marshal(folder)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal folder: %s", err)
|
||||
}
|
||||
|
||||
compareJson(t, string(json), folderJson)
|
||||
}
|
||||
|
||||
func TestCollectionServiceCollectionFolders(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(CollectionServer))
|
||||
defer ts.Close()
|
||||
|
||||
d := initDiscogsClient(t, &Options{URL: ts.URL})
|
||||
|
||||
collection, err := d.CollectionFolders(testUsername)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get collection: %s", err)
|
||||
}
|
||||
|
||||
json, err := json.Marshal(collection)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal collection: %s", err)
|
||||
}
|
||||
|
||||
compareJson(t, string(json), collectionJson)
|
||||
}
|
||||
|
||||
func TestCollectionServiceCollectionItemsByFolder(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(CollectionServer))
|
||||
defer ts.Close()
|
||||
|
||||
d := initDiscogsClient(t, &Options{URL: ts.URL})
|
||||
|
||||
items, err := d.CollectionItemsByFolder(testUsername, 0, &Pagination{Sort: "artist", SortOrder: "desc", PerPage: 2})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get collection items: %s", err)
|
||||
}
|
||||
|
||||
json, err := json.Marshal(items)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal collection items: %s", err)
|
||||
}
|
||||
|
||||
compareJson(t, string(json), collectionItemsByFolderJson)
|
||||
}
|
||||
|
||||
func TestCollectionServiceCollectionItemsByFolderError(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(CollectionServer))
|
||||
defer ts.Close()
|
||||
|
||||
d := initDiscogsClient(t, &Options{URL: ts.URL})
|
||||
|
||||
_, err := d.CollectionItemsByFolder(testUsername, 0, &Pagination{Sort: "invalid"})
|
||||
if err != ErrInvalidSortKey {
|
||||
t.Fatalf("err got=%s; want=%s", err, ErrInvalidSortKey)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCollectionServiceCollectionItemsByRelease(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(CollectionServer))
|
||||
defer ts.Close()
|
||||
|
||||
d := initDiscogsClient(t, &Options{URL: ts.URL})
|
||||
|
||||
items, err := d.CollectionItemsByRelease(testUsername, 12934893)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get collection items: %s", err)
|
||||
}
|
||||
|
||||
json, err := json.Marshal(items)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal collection items: %s", err)
|
||||
}
|
||||
|
||||
compareJson(t, string(json), collectionItemsByRelease)
|
||||
}
|
||||
|
||||
func TestCollectionServiceCollectionItemsByReleaseErrors(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(CollectionServer))
|
||||
defer ts.Close()
|
||||
d := initDiscogsClient(t, &Options{URL: ts.URL})
|
||||
|
||||
type testCase struct {
|
||||
username string
|
||||
releaseID int
|
||||
err error
|
||||
}
|
||||
|
||||
testCases := map[string]testCase{
|
||||
"invalid username": testCase{
|
||||
username: "",
|
||||
releaseID: 1,
|
||||
err: ErrInvalidUsername,
|
||||
},
|
||||
"invalid release id": testCase{
|
||||
username: "test-username",
|
||||
releaseID: 0,
|
||||
err: ErrInvalidReleaseID,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
_, err := d.CollectionItemsByRelease(tc.username, tc.releaseID)
|
||||
if err != tc.err {
|
||||
t.Fatalf("err got=%s; want=%s", err, tc.err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user