|
|
|
@ -12,7 +12,16 @@ var (
|
|
|
|
|
defaultAPI = "https://openlibrary.org/api/books" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// Client
|
|
|
|
|
var ( |
|
|
|
|
// FormatError marks errors with provided book identifers
|
|
|
|
|
FormatError = fmt.Errorf("identifier in wrong format") |
|
|
|
|
// NetworkError marks errors with the connection to the OpenLibrary API
|
|
|
|
|
NetworkError = fmt.Errorf("network error") |
|
|
|
|
// NotFoundError marks an empty response from the OpenLibrary API
|
|
|
|
|
NotFoundError = fmt.Errorf("book not found") |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// Client provides OpenLibrary Books API query methods
|
|
|
|
|
type Client struct { |
|
|
|
|
httpClient http.Client |
|
|
|
|
apipath string |
|
|
|
@ -33,9 +42,9 @@ func (c *Client) SetAPIPath(p string) {
|
|
|
|
|
// GetByISBN fetches details for a book based on its ISBN10 or ISBN13.
|
|
|
|
|
func (c *Client) GetByISBN(k string) (*BookDetails, error) { |
|
|
|
|
if k == "" { |
|
|
|
|
return nil, fmt.Errorf("ISBN cannot be empty") |
|
|
|
|
return nil, fmt.Errorf("%w: ISBN cannot be empty", FormatError) |
|
|
|
|
} else if len(k) != 10 && len(k) != 13 { |
|
|
|
|
return nil, fmt.Errorf("ISBN must be either 10 or 13 digits") |
|
|
|
|
return nil, fmt.Errorf("%w: ISBN must be either 10 or 13 digits", FormatError) |
|
|
|
|
} |
|
|
|
|
key := "ISBN:" + k |
|
|
|
|
return c.fetch(key) |
|
|
|
@ -44,7 +53,7 @@ func (c *Client) GetByISBN(k string) (*BookDetails, error) {
|
|
|
|
|
// GetByOCLC fetches details for a book based on its WorldCat OCLC number.
|
|
|
|
|
func (c *Client) GetByOCLC(k string) (*BookDetails, error) { |
|
|
|
|
if k == "" { |
|
|
|
|
return nil, fmt.Errorf("OCLC cannot be empty") |
|
|
|
|
return nil, fmt.Errorf("%w: OCLC cannot be empty", FormatError) |
|
|
|
|
} |
|
|
|
|
key := "OCLC:" + k |
|
|
|
|
return c.fetch(key) |
|
|
|
@ -53,7 +62,7 @@ func (c *Client) GetByOCLC(k string) (*BookDetails, error) {
|
|
|
|
|
// GetByLCCN fetches details for a book based on its Library of Congress Control Number.
|
|
|
|
|
func (c *Client) GetByLCCN(k string) (*BookDetails, error) { |
|
|
|
|
if k == "" { |
|
|
|
|
return nil, fmt.Errorf("LCCN cannot be empty") |
|
|
|
|
return nil, fmt.Errorf("%w: LCCN cannot be empty", FormatError) |
|
|
|
|
} |
|
|
|
|
key := "LCCN:" + k |
|
|
|
|
return c.fetch(key) |
|
|
|
@ -62,7 +71,7 @@ func (c *Client) GetByLCCN(k string) (*BookDetails, error) {
|
|
|
|
|
// GetByOLID fetches details for a book based on its OpenLibrary ID number.
|
|
|
|
|
func (c *Client) GetByOLID(k string) (*BookDetails, error) { |
|
|
|
|
if k == "" { |
|
|
|
|
return nil, fmt.Errorf("OLID cannot be empty") |
|
|
|
|
return nil, fmt.Errorf("%w: OLID cannot be empty", FormatError) |
|
|
|
|
} |
|
|
|
|
key := "OLID:" + k |
|
|
|
|
return c.fetch(key) |
|
|
|
@ -82,7 +91,7 @@ func (c *Client) fetch(key string) (*BookDetails, error) {
|
|
|
|
|
} |
|
|
|
|
u, err := url.Parse(h) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
return nil, fmt.Errorf("%w: %v", NetworkError, err) |
|
|
|
|
} |
|
|
|
|
u.RawQuery = url.Values{ |
|
|
|
|
"bibkeys": []string{key}, |
|
|
|
@ -92,26 +101,26 @@ func (c *Client) fetch(key string) (*BookDetails, error) {
|
|
|
|
|
|
|
|
|
|
resp, err := c.httpClient.Get(u.String()) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
return nil, fmt.Errorf("%w: %v", NetworkError, err) |
|
|
|
|
} |
|
|
|
|
defer resp.Body.Close() |
|
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK { |
|
|
|
|
return nil, fmt.Errorf("received non-200 status code: %d", resp.StatusCode) |
|
|
|
|
return nil, fmt.Errorf("%w: received non-200 status code: %d", NetworkError, resp.StatusCode) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var result response |
|
|
|
|
b, err := io.ReadAll(resp.Body) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
return nil, fmt.Errorf("%w: %v", NetworkError, err) |
|
|
|
|
} |
|
|
|
|
if err = json.Unmarshal(b, &result); err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
return nil, fmt.Errorf("%w: %v", NetworkError, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
details, ok := result[key] |
|
|
|
|
if !ok { |
|
|
|
|
return nil, fmt.Errorf("book not found") |
|
|
|
|
return nil, NotFoundError |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return &details, nil |
|
|
|
|