+package main
+
+import (
+ "crypto/tls"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+)
+
+type BookStackApi struct {
+ BaseURL string
+ TokenID string
+ TokenSecret string
+}
+
+func NewBookStackApi(baseUrl string, tokenId string, tokenSecret string) *BookStackApi {
+ api := &BookStackApi{
+ BaseURL: baseUrl,
+ TokenID: tokenId,
+ TokenSecret: tokenSecret,
+ }
+
+ return api
+}
+
+func (bs BookStackApi) authHeader() string {
+ return fmt.Sprintf("Token %s:%s", bs.TokenID, bs.TokenSecret)
+}
+
+func (bs BookStackApi) getRequest(method string, urlPath string, data map[string]string) *http.Request {
+ method = strings.ToUpper(method)
+ completeUrlStr := fmt.Sprintf("%s/api/%s", strings.TrimRight(bs.BaseURL, "/"), strings.TrimLeft(urlPath, "/"))
+
+ queryValues := url.Values{}
+ for k, v := range data {
+ queryValues.Add(k, v)
+ }
+ encodedData := queryValues.Encode()
+
+ r, err := http.NewRequest(method, completeUrlStr, strings.NewReader(encodedData))
+ if err != nil {
+ panic(err)
+ }
+
+ r.Header.Add("Authorization", bs.authHeader())
+
+ if method != "GET" && method != "HEAD" {
+ r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
+ r.Header.Add("Content-Length", strconv.Itoa(len(encodedData)))
+ } else {
+ r.URL.RawQuery = encodedData
+ }
+
+ return r
+}
+
+func (bs BookStackApi) doRequest(method string, urlPath string, data map[string]string) []byte {
+ client := &http.Client{
+ Transport: &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+ },
+ }
+ r := bs.getRequest(method, urlPath, data)
+ res, err := client.Do(r)
+ if err != nil {
+ panic(err)
+ }
+
+ defer res.Body.Close()
+
+ body, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ panic(err)
+ }
+
+ return body
+}
+
+func (bs BookStackApi) getFromListResponse(responseData []byte, models any) ListResponse {
+ var response ListResponse
+
+ if err := json.Unmarshal(responseData, &response); err != nil {
+ panic(err)
+ }
+
+ if err := json.Unmarshal(response.Data, models); err != nil {
+ panic(err)
+ }
+
+ return response
+}
+
+func (bs BookStackApi) GetBooks(count int, page int) ([]Book, int) {
+ var books []Book
+
+ data := bs.doRequest("GET", "/books", getPagingParams(count, page))
+ response := bs.getFromListResponse(data, &books)
+
+ return books, response.Total
+}
+
+func (bs BookStackApi) GetChapters(count int, page int) ([]Chapter, int) {
+ var chapters []Chapter
+
+ data := bs.doRequest("GET", "/chapters", getPagingParams(count, page))
+ response := bs.getFromListResponse(data, &chapters)
+
+ return chapters, response.Total
+}
+
+func (bs BookStackApi) GetPages(count int, page int) ([]Page, int) {
+ var pages []Page
+
+ data := bs.doRequest("GET", "/pages", getPagingParams(count, page))
+ response := bs.getFromListResponse(data, &pages)
+
+ return pages, response.Total
+}
+
+func (bs BookStackApi) GetPage(id int) Page {
+ var page Page
+
+ data := bs.doRequest("GET", fmt.Sprintf("/pages/%d", id), nil)
+ if err := json.Unmarshal(data, &page); err != nil {
+ panic(err)
+ }
+
+ return page
+}
+
+func getPagingParams(count int, page int) map[string]string {
+ return map[string]string{
+ "count": strconv.Itoa(count),
+ "offset": strconv.Itoa(count * (page - 1)),
+ }
+}