Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[chore] Use query for GET/DELETE requests, per HTTP spec #229

Merged
merged 4 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG

## Next Release

- Update HTTP logic to use query for GET/DELETE requests and body for POST/PUT/PATCH requests

## v4.5.0 (2024-07-24)

- Add new claim-related functions: `CreateClaim`, `GetClaim`, `ListClaims`, `GetNextClaimPage` and `CancelClaim`
Expand Down
88 changes: 44 additions & 44 deletions address.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,86 +8,86 @@ import (
// AddressVerificationFieldError provides additional information on address
// validation errors.
type AddressVerificationFieldError struct {
Code string `json:"code,omitempty"`
Field string `json:"field,omitempty"`
Message string `json:"message,omitempty"`
Suggestion string `json:"suggestion,omitempty"`
Code string `json:"code,omitempty" url:"code,omitempty"`
Field string `json:"field,omitempty" url:"field,omitempty"`
Message string `json:"message,omitempty" url:"message,omitempty"`
Suggestion string `json:"suggestion,omitempty" url:"suggestion,omitempty"`
}

// AddressVerificationDetails contains extra information related to address
// verification.
type AddressVerificationDetails struct {
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
TimeZone string `json:"time_zone"`
Latitude float64 `json:"latitude,omitempty" url:"latitude,omitempty"`
Longitude float64 `json:"longitude,omitempty" url:"longitude,omitempty"`
TimeZone string `json:"time_zone,omitempty" url:"time_zone,omitempty"`
}

// AddressVerification holds data relating to address verification status.
type AddressVerification struct {
Success bool `json:"success"`
Errors []*AddressVerificationFieldError `json:"errors"`
Details *AddressVerificationDetails `json:"details"`
Success bool `json:"success,omitempty" url:"success,omitempty"`
Errors []*AddressVerificationFieldError `json:"errors,omitempty" url:"errors,omitempty"`
Details *AddressVerificationDetails `json:"details,omitempty" url:"details,omitempty"`
}

// AddressVerifications contains the result of the requested address
// verifications.
type AddressVerifications struct {
ZIP4 *AddressVerification `json:"zip4"`
Delivery *AddressVerification `json:"delivery"`
ZIP4 *AddressVerification `json:"zip4,omitempty" url:"zip4,omitempty"`
Delivery *AddressVerification `json:"delivery,omitempty" url:"delivery,omitempty"`
}

// Address objects are used to represent people, places, and organizations in a
// number of contexts.
type Address struct {
ID string `json:"id,omitempty"`
Object string `json:"object,omitempty"`
Reference string `json:"reference,omitempty"`
Mode string `json:"mode,omitempty"`
CreatedAt *DateTime `json:"created_at,omitempty"`
UpdatedAt *DateTime `json:"updated_at,omitempty"`
Street1 string `json:"street1,omitempty"`
Street2 string `json:"street2,omitempty"`
City string `json:"city,omitempty"`
State string `json:"state,omitempty"`
Zip string `json:"zip,omitempty"`
Country string `json:"country,omitempty"`
Name string `json:"name,omitempty"`
Company string `json:"company,omitempty"`
Phone string `json:"phone,omitempty"`
Email string `json:"email,omitempty"`
Residential bool `json:"residential,omitempty"`
CarrierFacility string `json:"carrier_facility,omitempty"`
FederalTaxID string `json:"federal_tax_id,omitempty"`
StateTaxID string `json:"state_tax_id,omitempty"`
Verifications *AddressVerifications `json:"verifications,omitempty"`
ID string `json:"id,omitempty" url:"id,omitempty"`
Object string `json:"object,omitempty" url:"object,omitempty"`
Reference string `json:"reference,omitempty" url:"reference,omitempty"`
Mode string `json:"mode,omitempty" url:"mode,omitempty"`
CreatedAt *DateTime `json:"created_at,omitempty" url:"created_at,omitempty"`
UpdatedAt *DateTime `json:"updated_at,omitempty" url:"updated_at,omitempty"`
Street1 string `json:"street1,omitempty" url:"street1,omitempty"`
Street2 string `json:"street2,omitempty" url:"street2,omitempty"`
City string `json:"city,omitempty" url:"city,omitempty"`
State string `json:"state,omitempty" url:"state,omitempty"`
Zip string `json:"zip,omitempty" url:"zip,omitempty"`
Country string `json:"country,omitempty" url:"country,omitempty"`
Name string `json:"name,omitempty" url:"name,omitempty"`
Company string `json:"company,omitempty" url:"company,omitempty"`
Phone string `json:"phone,omitempty" url:"phone,omitempty"`
Email string `json:"email,omitempty" url:"email,omitempty"`
Residential bool `json:"residential,omitempty" url:"residential,omitempty"`
CarrierFacility string `json:"carrier_facility,omitempty" url:"carrier_facility,omitempty"`
FederalTaxID string `json:"federal_tax_id,omitempty" url:"federal_tax_id,omitempty"`
StateTaxID string `json:"state_tax_id,omitempty" url:"state_tax_id,omitempty"`
Verifications *AddressVerifications `json:"verifications,omitempty" url:"verifications,omitempty"`
}

// CreateAddressOptions is used to specify verification options for address
// creation.
type CreateAddressOptions struct {
// TODO: These should be booleans, not strings, like the other libs
Verify []string `json:"verify,omitempty"`
VerifyStrict []string `json:"verify_strict,omitempty"`
Verify []string `json:"verify,omitempty" url:"verify,omitempty"`
VerifyStrict []string `json:"verify_strict,omitempty" url:"verify_strict,omitempty"`
}

type createAddressRequest struct {
*CreateAddressOptions
Address *Address `json:"address,omitempty"`
Address *Address `json:"address,omitempty" url:"address,omitempty"`
}

type AddressVerifyResponse struct {
Address *Address `json:"address,omitempty"`
Address *Address `json:"address,omitempty" url:"address,omitempty"`
}

// ListAddressResult holds the results from the list addresses API.
type ListAddressResult struct {
Addresses []*Address `json:"addresses,omitempty"`
Addresses []*Address `json:"addresses,omitempty" url:"addresses,omitempty"`
PaginatedCollection
}

// For some reason, the verify API returns the address in a nested dictionary.
type verifyAddressResponse struct {
Address **Address `json:"address,omitempty"`
Address **Address `json:"address,omitempty" url:"address,omitempty"`
}

// CreateAddress submits a request to create a new address, and returns the
Expand Down Expand Up @@ -115,7 +115,7 @@ func (c *Client) CreateAddress(in *Address, opts *CreateAddressOptions) (out *Ad
// allows specifying a context that can interrupt the request.
func (c *Client) CreateAddressWithContext(ctx context.Context, in *Address, opts *CreateAddressOptions) (out *Address, err error) {
req := &createAddressRequest{CreateAddressOptions: opts, Address: in}
err = c.post(ctx, "addresses", req, &out)
err = c.do(ctx, http.MethodPost, "addresses", req, &out)
return
}

Expand All @@ -127,7 +127,7 @@ func (c *Client) ListAddresses(opts *ListOptions) (out *ListAddressResult, err e
// ListAddressesWithContext performs the same operation as ListAddresses, but
// allows specifying a context that can interrupt the request.
func (c *Client) ListAddressesWithContext(ctx context.Context, opts *ListOptions) (out *ListAddressResult, err error) {
err = c.do(ctx, http.MethodGet, "addresses", c.convertOptsToURLValues(opts), &out)
err = c.do(ctx, http.MethodGet, "addresses", opts, &out)
return
}

Expand Down Expand Up @@ -172,7 +172,7 @@ func (c *Client) VerifyAddress(addressID string) (out *Address, err error) {
func (c *Client) VerifyAddressWithContext(ctx context.Context, addressID string) (out *Address, err error) {
path := "addresses/" + addressID + "/verify"
res := &verifyAddressResponse{Address: &out}
err = c.get(ctx, path, res)
err = c.do(ctx, http.MethodGet, path, nil, res)
return
}

Expand All @@ -184,7 +184,7 @@ func (c *Client) GetAddress(addressID string) (out *Address, err error) {
// GetAddressWithContext performs the same operation as GetAddress, but allows
// specifying a context that can interrupt the request.
func (c *Client) GetAddressWithContext(ctx context.Context, addressID string) (out *Address, err error) {
err = c.get(ctx, "addresses/"+addressID, &out)
err = c.do(ctx, http.MethodGet, "addresses/"+addressID, nil, &out)
return
}

Expand All @@ -198,7 +198,7 @@ func (c *Client) CreateAndVerifyAddress(in *Address, opts *CreateAddressOptions)
func (c *Client) CreateAndVerifyAddressWithContext(ctx context.Context, in *Address, opts *CreateAddressOptions) (out *Address, err error) {
req := &createAddressRequest{CreateAddressOptions: opts, Address: in}
response := AddressVerifyResponse{}
err = c.post(ctx, "addresses/create_and_verify", req, &response)
err = c.do(ctx, http.MethodPost, "addresses/create_and_verify", req, &response)
out = response.Address
return
}
17 changes: 9 additions & 8 deletions api_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,23 @@ package easypost

import (
"context"
"net/http"
)

// APIKey represents a single API key.
type APIKey struct {
Object string `json:"object,omitempty"`
Mode string `json:"mode,omitempty"`
CreatedAt *DateTime `json:"created_at,omitempty"`
Key string `json:"key,omitempty"`
Object string `json:"object,omitempty" url:"object,omitempty"`
Mode string `json:"mode,omitempty" url:"mode,omitempty"`
CreatedAt *DateTime `json:"created_at,omitempty" url:"created_at,omitempty"`
Key string `json:"key,omitempty" url:"key,omitempty"`
}

// APIKeys contains information about a list of API keys for the given user and
// any child users.
type APIKeys struct {
ID string `json:"id,omitempty"`
Children []*APIKeys `json:"children,omitempty"`
Keys []*APIKey `json:"keys,omitempty"`
ID string `json:"id,omitempty" url:"id,omitempty"`
Children []*APIKeys `json:"children,omitempty" url:"children,omitempty"`
Keys []*APIKey `json:"keys,omitempty" url:"keys,omitempty"`
}

// GetAPIKeys returns the list of API keys associated with the current user.
Expand All @@ -28,7 +29,7 @@ func (c *Client) GetAPIKeys() (out *APIKeys, err error) {
// GetAPIKeysWithContext performs the same operation as GetAPIKeys, but allows
// specifying a context that can interrupt the request.
func (c *Client) GetAPIKeysWithContext(ctx context.Context) (out *APIKeys, err error) {
err = c.get(ctx, "api_keys", &out)
err = c.do(ctx, http.MethodGet, "api_keys", nil, &out)
return
}

Expand Down
65 changes: 34 additions & 31 deletions batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,45 @@ package easypost
import (
"context"
"net/http"
"net/url"
)

// BatchStatus contains counts of statuses for the shipments in a batch.
type BatchStatus struct {
PostagePurchased int `json:"postage_purchased,omitempty"`
PostagePurchaseFailed int `json:"postage_purchase_failed,omitempty"`
QueuedForPurchase int `json:"queued_for_purchase,omitempty"`
CreationFailed int `json:"creation_failed,omitempty"`
PostagePurchased int `json:"postage_purchased,omitempty" url:"postage_purchased,omitempty"`
PostagePurchaseFailed int `json:"postage_purchase_failed,omitempty" url:"postage_purchase_failed,omitempty"`
QueuedForPurchase int `json:"queued_for_purchase,omitempty" url:"queued_for_purchase,omitempty"`
CreationFailed int `json:"creation_failed,omitempty" url:"creation_failed,omitempty"`
}

// Batch represents a batch of shipments.
type Batch struct {
ID string `json:"id,omitempty"`
Object string `json:"object,omitempty"`
Reference string `json:"reference,omitempty"`
Mode string `json:"mode,omitempty"`
CreatedAt *DateTime `json:"created_at,omitempty"`
UpdatedAt *DateTime `json:"updated_at,omitempty"`
State string `json:"state,omitempty"`
NumShipments int `json:"num_shipments,omitempty"`
Shipments []*Shipment `json:"shipments,omitempty"`
Status *BatchStatus `json:"status,omitempty"`
LabelURL string `json:"label_url,omitempty"`
ScanForm *ScanForm `json:"scan_form,omitempty"`
Pickup *Pickup `json:"pickup,omitempty"`
ID string `json:"id,omitempty" url:"id,omitempty"`
Object string `json:"object,omitempty" url:"object,omitempty"`
Reference string `json:"reference,omitempty" url:"reference,omitempty"`
Mode string `json:"mode,omitempty" url:"mode,omitempty"`
CreatedAt *DateTime `json:"created_at,omitempty" url:"created_at,omitempty"`
UpdatedAt *DateTime `json:"updated_at,omitempty" url:"updated_at,omitempty"`
State string `json:"state,omitempty" url:"state,omitempty"`
NumShipments int `json:"num_shipments,omitempty" url:"num_shipments,omitempty"`
Shipments []*Shipment `json:"shipments,omitempty" url:"shipments,omitempty"`
Status *BatchStatus `json:"status,omitempty" url:"status,omitempty"`
LabelURL string `json:"label_url,omitempty" url:"label_url,omitempty"`
ScanForm *ScanForm `json:"scan_form,omitempty" url:"scan_form,omitempty"`
Pickup *Pickup `json:"pickup,omitempty" url:"pickup,omitempty"`
}

type batchRequest struct {
Batch *Batch `json:"batch,omitempty"`
Batch *Batch `json:"batch,omitempty" url:"batch,omitempty"`
}

// ListBatchesResult holds the results from the list insurances API.
type ListBatchesResult struct {
Batch []*Batch `json:"batches,omitempty"`
Batch []*Batch `json:"batches,omitempty" url:"batches,omitempty"`
PaginatedCollection
}

type addRemoveShipmentsRequest struct {
Shipments []*Shipment `json:"shipments,omitempty"`
Shipments []*Shipment `json:"shipments,omitempty" url:"shipments,omitempty"`
}

// CreateBatch creates a new batch of shipments. It optionally accepts one or
Expand All @@ -63,7 +62,7 @@ func (c *Client) CreateBatch(in ...*Shipment) (out *Batch, err error) {
// specifying a context that can interrupt the request.
func (c *Client) CreateBatchWithContext(ctx context.Context, in ...*Shipment) (out *Batch, err error) {
req := batchRequest{Batch: &Batch{Shipments: in}}
err = c.post(ctx, "batches", req, &out)
err = c.do(ctx, http.MethodPost, "batches", req, &out)
return
}

Expand All @@ -75,7 +74,7 @@ func (c *Client) ListBatches(opts *ListOptions) (out *ListBatchesResult, err err
// ListBatchesWithContext performs the same operation as ListBatches, but
// allows specifying a context that can interrupt the request.
func (c *Client) ListBatchesWithContext(ctx context.Context, opts *ListOptions) (out *ListBatchesResult, err error) {
err = c.do(ctx, http.MethodGet, "batches", c.convertOptsToURLValues(opts), &out)
err = c.do(ctx, http.MethodGet, "batches", opts, &out)
return
}

Expand All @@ -92,7 +91,7 @@ func (c *Client) AddShipmentsToBatch(batchID string, shipments ...*Shipment) (ou
// request.
func (c *Client) AddShipmentsToBatchWithContext(ctx context.Context, batchID string, shipments ...*Shipment) (out *Batch, err error) {
req := addRemoveShipmentsRequest{Shipments: shipments}
err = c.post(ctx, "batches/"+batchID+"/add_shipments", req, &out)
err = c.do(ctx, http.MethodPost, "batches/"+batchID+"/add_shipments", req, &out)
return
}

Expand All @@ -107,7 +106,7 @@ func (c *Client) RemoveShipmentsFromBatch(batchID string, shipments ...*Shipment
// the request.
func (c *Client) RemoveShipmentsFromBatchWithContext(ctx context.Context, batchID string, shipments ...*Shipment) (out *Batch, err error) {
req := addRemoveShipmentsRequest{Shipments: shipments}
err = c.post(ctx, "batches/"+batchID+"/remove_shipments", req, &out)
err = c.do(ctx, http.MethodPost, "batches/"+batchID+"/remove_shipments", req, &out)
return
}

Expand All @@ -120,7 +119,7 @@ func (c *Client) BuyBatch(batchID string) (out *Batch, err error) {
// BuyBatchWithContext performs the same operation as BuyBatch, but allows
// specifying a context that can interrupt the request.
func (c *Client) BuyBatchWithContext(ctx context.Context, batchID string) (out *Batch, err error) {
err = c.post(ctx, "batches/"+batchID+"/buy", nil, &out)
err = c.do(ctx, http.MethodPost, "batches/"+batchID+"/buy", nil, &out)
return
}

Expand All @@ -132,7 +131,7 @@ func (c *Client) GetBatch(batchID string) (out *Batch, err error) {
// GetBatchWithContext performs the same operation as GetBatch, but allows
// specifying a context that can interrupt the request.
func (c *Client) GetBatchWithContext(ctx context.Context, batchID string) (out *Batch, err error) {
err = c.get(ctx, "batches/"+batchID, &out)
err = c.do(ctx, http.MethodGet, "batches/"+batchID, nil, &out)
return
}

Expand All @@ -145,8 +144,10 @@ func (c *Client) GetBatchLabels(batchID, format string) (out *Batch, err error)
// GetBatchLabelsWithContext performs the same operation as GetBatchLabels, but
// allows specifying a context that can interrupt the request.
func (c *Client) GetBatchLabelsWithContext(ctx context.Context, batchID, format string) (out *Batch, err error) {
params := url.Values{"file_format": []string{format}}
err = c.post(ctx, "batches/"+batchID+"/label", params, &out)
params := struct {
FileFormat string `json:"file_format,omitempty" url:"file_format,omitempty"`
}{FileFormat: format}
err = c.do(ctx, http.MethodPost, "batches/"+batchID+"/label", params, &out)
return
}

Expand All @@ -159,7 +160,9 @@ func (c *Client) CreateBatchScanForms(batchID, format string) (out *Batch, err e
// CreateBatchScanForms, but allows specifying a context that can interrupt the
// request.
func (c *Client) CreateBatchScanFormsWithContext(ctx context.Context, batchID, format string) (out *Batch, err error) {
vals := url.Values{"file_format": []string{format}}
err = c.do(ctx, http.MethodPost, "batches/"+batchID+"/scan_form", vals, &out)
params := struct {
FileFormat string `json:"file_format,omitempty" url:"file_format,omitempty"`
}{FileFormat: format}
err = c.do(ctx, http.MethodPost, "batches/"+batchID+"/scan_form", params, &out)
return
}
Loading
Loading