Last active
April 6, 2018 21:17
-
-
Save packrat386/ae58241024c869545a3b02174d5d09c9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// pacakge iface is a comparison of two different interfaces for a client | |
// to a simple REST API. Assume I had access to both `GET /resource`, which | |
// returns a list of all resources (which may be empty), and `GET /resource/:id`, | |
// which returns the resource with the given ID, OR a 404 if no resource | |
// has that ID. Additionally, since these are http requests they could also | |
// fail with some other non-200 status code for a variety of reasons, and | |
// we want to be able to distinguish between a request that failed and a | |
// resource not existing. | |
// | |
// The issue I find is that using pointers is nicer in the case of getting a | |
// single resource, since you can return to indicate that you successfully | |
// found nothing. However, for the collection of resources, the interface is | |
// equally usable (in part because you can return nil for a slice), and | |
// using pointers where we don't need to is needlessly complex. And to make | |
// things even more difficult, to use pointers for one but not the other | |
// seems likely to confuse the user. | |
package iface | |
import ( | |
"errors" | |
"fmt" | |
) | |
// ErrNotFound indicates a request succeeded | |
var ErrNotFound = errors.New("not found") | |
// Resource is some REST Resource | |
type Resource struct { | |
Data string | |
} | |
// Concrete returns only the resource itself | |
type Concrete interface { | |
// GetOne returns a single Resource if it exists. If no resource | |
// with that ID is found it returns ErrNotFound. If the request | |
// fails for a different reason it returns a different error. If | |
// it returns an error the Resource is just a zero-valued Resource | |
GetOne(id string) (Resource, error) | |
// GetAll returns all the resources. If there were no resources | |
// for some reason it returns an empty slice. If the request | |
// fails it returns an error. If it returns an error then the | |
// []Resource is nil. | |
GetAll() ([]Resource, error) | |
} | |
func UseConcreteOne(c Concrete) error { | |
resource, err := c.GetOne("someid") | |
if err == ErrNotFound { | |
fmt.Println("/resource/someid doesn't exist") | |
return nil | |
} else if err != nil { | |
fmt.Println("Something broke!") | |
return err | |
} | |
fmt.Println("Got what we wanted: ", resource.Data) | |
return nil | |
} | |
func UseConcreteAll(c Concrete) error { | |
resources, err := c.GetAll() | |
if err != nil { | |
fmt.Println("Something broke~") | |
} | |
for _, r := range resources { | |
fmt.Println("Got what we wanted: ", r.Data) | |
} | |
return nil | |
} | |
// Pointer returns only pointers to the resource | |
type Pointer interface { | |
// GetOne returns a single Resource if it exists. If no resource | |
// with that ID is found, it returns nil and no error. If the | |
// request fails it returns an error and the *Resource is nil | |
GetOne(id string) (*Resource, error) | |
// GetAll returns all the resources. If there were no resources | |
// for some reason it returns an empty slice. If the request | |
// fails it returns an error. If it returns an error then the | |
// []*Resource is nil | |
GetAll() ([]*Resource, error) | |
} | |
func UsePointerOne(p Pointer) error { | |
resource, err := p.GetOne("someid") | |
if err != nil { | |
fmt.Println("Something broke!") | |
return err | |
} | |
if resource == nil { | |
fmt.Println("/resource/someid doesn't exist") | |
return nil | |
} | |
fmt.Println("Got what we wanted: ", resource.Data) | |
return nil | |
} | |
func UsePointerAll(p Pointer) error { | |
resources, err := p.GetAll() | |
if err != nil { | |
fmt.Println("Something broke~") | |
} | |
for _, r := range resources { | |
fmt.Println("Got what we wanted: ", r.Data) | |
} | |
return nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment