You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bathyscaphe/internal/indexer/client/client.go

142 lines
3.8 KiB
Go

package client
import (
"encoding/base64"
"fmt"
"github.com/go-resty/resty/v2"
"strconv"
"time"
)
//go:generate mockgen -destination=../client_mock/client_mock.go -package=client_mock . Client
const (
// PaginationPageHeader is the header to determinate current page in paginated endpoint
PaginationPageHeader = "X-Pagination-Page"
// PaginationSizeHeader is the header to determinate page size in paginated endpoint
PaginationSizeHeader = "X-Pagination-Size"
// PaginationCountHeader is the header to determinate total count of element in paginated endpoint
PaginationCountHeader = "X-Pagination-Count"
// PaginationPageQueryParam is the query parameter used to set current page in paginated endpoint
PaginationPageQueryParam = "pagination-page"
// PaginationSizeQueryParam is the query parameter used to set page size in paginated endpoint
PaginationSizeQueryParam = "pagination-size"
)
// ResourceDto represent a resource as given by the API
type ResourceDto struct {
URL string `json:"url"`
Body string `json:"body"`
Time time.Time `json:"time"`
Title string `json:"title"`
Meta map[string]string `json:"meta"`
Description string `json:"description"`
Headers map[string]string `json:"headers"`
}
// CredentialsDto represent the credential when logging in the API
type CredentialsDto struct {
Username string `json:"username"`
Password string `json:"password"`
}
// ResSearchParams is the search params used
type ResSearchParams struct {
URL string
Keyword string
StartDate time.Time
EndDate time.Time
WithBody bool
PageSize int
PageNumber int
// TODO allow searching by meta
// TODO allow searching by headers
}
// Client is the interface to interact with the indexer API
type Client interface {
SearchResources(params *ResSearchParams) ([]ResourceDto, int64, error)
ScheduleURL(url string) error
}
type client struct {
httpClient *resty.Client
baseURL string
}
func (c *client) SearchResources(params *ResSearchParams) ([]ResourceDto, int64, error) {
targetEndpoint := fmt.Sprintf("%s/v1/resources?", c.baseURL)
req := c.httpClient.R()
if params.URL != "" {
b64URL := base64.URLEncoding.EncodeToString([]byte(params.URL))
req.SetQueryParam("url", b64URL)
}
if params.Keyword != "" {
req.SetQueryParam("keyword", params.Keyword)
}
if !params.StartDate.IsZero() {
req.SetQueryParam("start-date", params.StartDate.Format(time.RFC3339))
}
if !params.EndDate.IsZero() {
req.SetQueryParam("end-date", params.EndDate.Format(time.RFC3339))
}
if params.PageNumber != 0 {
req.Header.Set(PaginationPageHeader, strconv.Itoa(params.PageNumber))
}
if params.PageSize != 0 {
req.Header.Set(PaginationSizeHeader, strconv.Itoa(params.PageSize))
}
var resources []ResourceDto
req.SetResult(&resources)
res, err := req.Get(targetEndpoint)
if err != nil {
return nil, 0, err
}
count, err := strconv.ParseInt(res.Header().Get(PaginationCountHeader), 10, 64)
if err != nil {
return nil, 0, err
}
return resources, count, nil
}
func (c *client) ScheduleURL(url string) error {
targetEndpoint := fmt.Sprintf("%s/v1/urls", c.baseURL)
req := c.httpClient.R()
req.SetHeader("Content-Type", "application/json")
req.SetBody(fmt.Sprintf("\"%s\"", url))
_, err := req.Post(targetEndpoint)
return err
}
// NewClient create a new API client using given details
func NewClient(baseURL, token string) Client {
httpClient := resty.New()
httpClient.SetAuthScheme("Bearer")
httpClient.SetAuthToken(token)
httpClient.OnAfterResponse(func(c *resty.Client, r *resty.Response) error {
if r.StatusCode() > 302 {
return fmt.Errorf("error when making HTTP request: %s", r.Status())
}
return nil
})
client := &client{
httpClient: httpClient,
baseURL: baseURL,
}
return client
}