package client
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
type APIClient struct {
client *http.Client
endpoint string
}
type Config struct {
Endpoint string
}
type ClientError struct {
error
}
var ErrorNotFound = &ClientError{fmt.Errorf("not found")}
func NewAPIClient(conf Config) (*APIClient, error) {
if conf.Endpoint == "" {
return nil, fmt.Errorf("endpoint is required")
}
cli := APIClient{
client: http.DefaultClient,
endpoint: conf.Endpoint,
}
return &cli, nil
}
func newRequest(method, path string, body io.Reader) (*http.Request, error) {
req, err := http.NewRequest(method, path, body)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
req.Header.Set("User-Agent", "api-client-go:v0")
return req, nil
}
func (c *APIClient) DoGET(path string) ([]byte, error) {
req, err := newRequest("GET", c.endpoint+path, nil)
if err != nil {
return nil, err
}
resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusNotFound {
return nil, ErrorNotFound
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode >= 400 {
return nil, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, body)
}
return body, err
}
func (c *APIClient) DoPOST(path string, data interface{}) ([]byte, error) {
dataBytes, err := json.Marshal(data)
if err != nil {
return nil, err
}
req, err := newRequest("POST", c.endpoint+path, bytes.NewBuffer(dataBytes))
if err != nil {
return nil, err
}
resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusNotFound {
return nil, ErrorNotFound
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode >= 400 {
return nil, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, body)
}
return body, err
}
func (c *APIClient) DoPUT(path string, data interface{}) ([]byte, error) {
dataBytes, err := json.Marshal(data)
if err != nil {
return nil, err
}
req, err := newRequest("PUT", c.endpoint+path, bytes.NewBuffer(dataBytes))
if err != nil {
return nil, err
}
resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusNotFound {
return nil, ErrorNotFound
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode >= 400 {
return nil, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, body)
}
return body, err
}
func (c *APIClient) DoDELETE(path string) error {
req, err := newRequest("DELETE", c.endpoint+path, nil)
if err != nil {
return err
}
resp, err := c.client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusNotFound {
return ErrorNotFound
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
if resp.StatusCode >= 400 {
return fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, body)
}
return nil
}
package client
import (
"encoding/json"
"strconv"
"github.com/tcarreira/api-server/pkg/types"
)
type peopleClient struct {
client *APIClient
}
func (c *APIClient) People() *peopleClient {
return &peopleClient{c}
}
func (c *peopleClient) Create(p *types.Person) error {
data, err := c.client.DoPOST("/people", p)
if err != nil {
return err
}
var person types.Person
err = json.Unmarshal(data, &person)
if err != nil {
return err
}
p.ID = person.ID // update the ID with server info
return nil
}
func (c *peopleClient) Get(id int) (*types.Person, error) {
data, err := c.client.DoGET("/people/" + strconv.Itoa(id))
if err != nil {
return nil, err
}
var person types.Person
err = json.Unmarshal(data, &person)
if err != nil {
return nil, err
}
return &person, nil
}
func (c *peopleClient) List() ([]*types.Person, error) {
data, err := c.client.DoGET("/people")
if err != nil {
return nil, err
}
var people []*types.Person
err = json.Unmarshal(data, &people)
if err != nil {
return nil, err
}
return people, nil
}
func (c *peopleClient) Update(id int, p *types.Person) error {
data, err := c.client.DoPUT("/people/"+strconv.Itoa(id), p)
if err != nil {
return err
}
var person types.Person
err = json.Unmarshal(data, &person)
if err != nil {
return err
}
p.ID = person.ID // update the ID with server info
return nil
}
func (c *peopleClient) Delete(id int) error {
return c.client.DoDELETE("/people/" + strconv.Itoa(id))
}
package client
import (
"encoding/json"
"strconv"
"github.com/tcarreira/api-server/pkg/types"
)
type petsClient struct {
client *APIClient
}
func (c *APIClient) Pet() *petsClient {
return &petsClient{c}
}
func (c *petsClient) Create(p *types.Pet) error {
data, err := c.client.DoPOST("/pets", p)
if err != nil {
return err
}
var pet types.Pet
err = json.Unmarshal(data, &pet)
if err != nil {
return err
}
p.ID = pet.ID // update the ID with server info
return nil
}
func (c *petsClient) Get(id int) (*types.Pet, error) {
data, err := c.client.DoGET("/pets/" + strconv.Itoa(id))
if err != nil {
return nil, err
}
var pet types.Pet
err = json.Unmarshal(data, &pet)
if err != nil {
return nil, err
}
return &pet, nil
}
func (c *petsClient) List() ([]*types.Pet, error) {
data, err := c.client.DoGET("/pets")
if err != nil {
return nil, err
}
var pets []*types.Pet
err = json.Unmarshal(data, &pets)
if err != nil {
return nil, err
}
return pets, nil
}
func (c *petsClient) Update(id int, p *types.Pet) error {
data, err := c.client.DoPUT("/pets/"+strconv.Itoa(id), p)
if err != nil {
return err
}
var pet types.Pet
err = json.Unmarshal(data, &pet)
if err != nil {
return err
}
p.ID = pet.ID // update the ID with server info
return nil
}
func (c *petsClient) Delete(id int) error {
return c.client.DoDELETE("/pets/" + strconv.Itoa(id))
}