feat(bookstack-api-9xo): implement BooksService List and Get
Add listResponse generic type and ListOptions.queryString() helper. Implement BooksService.List with pagination support and Get with proper error handling. Include mock server tests.
This commit is contained in:
parent
43b8aac9a5
commit
c241399cab
5 changed files with 155 additions and 33 deletions
102
books_test.go
Normal file
102
books_test.go
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
package bookstack
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBooksService_List(t *testing.T) {
|
||||
c := testClient(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("method = %s, want GET", r.Method)
|
||||
}
|
||||
if r.URL.Path != "/api/books" {
|
||||
t.Errorf("path = %s, want /api/books", r.URL.Path)
|
||||
}
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
"data": []map[string]any{
|
||||
{"id": 1, "name": "Book One", "slug": "book-one"},
|
||||
{"id": 2, "name": "Book Two", "slug": "book-two"},
|
||||
},
|
||||
"total": 2,
|
||||
})
|
||||
})
|
||||
|
||||
books, err := c.Books.List(context.Background(), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if len(books) != 2 {
|
||||
t.Fatalf("got %d books, want 2", len(books))
|
||||
}
|
||||
if books[0].Name != "Book One" {
|
||||
t.Errorf("books[0].Name = %q, want %q", books[0].Name, "Book One")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBooksService_List_WithOptions(t *testing.T) {
|
||||
c := testClient(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
q := r.URL.Query()
|
||||
if q.Get("count") != "10" {
|
||||
t.Errorf("count = %q, want 10", q.Get("count"))
|
||||
}
|
||||
if q.Get("offset") != "20" {
|
||||
t.Errorf("offset = %q, want 20", q.Get("offset"))
|
||||
}
|
||||
if q.Get("sort") != "-name" {
|
||||
t.Errorf("sort = %q, want -name", q.Get("sort"))
|
||||
}
|
||||
json.NewEncoder(w).Encode(map[string]any{"data": []any{}, "total": 0})
|
||||
})
|
||||
|
||||
_, err := c.Books.List(context.Background(), &ListOptions{
|
||||
Count: 10,
|
||||
Offset: 20,
|
||||
Sort: "-name",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBooksService_Get(t *testing.T) {
|
||||
c := testClient(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/api/books/42" {
|
||||
t.Errorf("path = %s, want /api/books/42", r.URL.Path)
|
||||
}
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
"id": 42, "name": "My Book", "slug": "my-book",
|
||||
})
|
||||
})
|
||||
|
||||
book, err := c.Books.Get(context.Background(), 42)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if book.ID != 42 {
|
||||
t.Errorf("ID = %d, want 42", book.ID)
|
||||
}
|
||||
if book.Name != "My Book" {
|
||||
t.Errorf("Name = %q, want %q", book.Name, "My Book")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBooksService_Get_NotFound(t *testing.T) {
|
||||
c := testClient(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
"error": map[string]string{"message": "Book not found"},
|
||||
})
|
||||
})
|
||||
|
||||
_, err := c.Books.Get(context.Background(), 999)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
if !errors.Is(err, ErrNotFound) {
|
||||
t.Error("expected ErrNotFound")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue