112 lines
2.4 KiB
Go
112 lines
2.4 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"log"
|
||
|
"net/http"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/go-kit/kit/endpoint"
|
||
|
httptransport "github.com/go-kit/kit/transport/http"
|
||
|
)
|
||
|
|
||
|
// StringService provides operations on strings.
|
||
|
type StringService interface {
|
||
|
Uppercase(string) (string, error)
|
||
|
Count(string) int
|
||
|
}
|
||
|
|
||
|
type stringService struct{}
|
||
|
|
||
|
func (stringService) Uppercase(s string) (string, error) {
|
||
|
if s == "" {
|
||
|
return "", ErrEmpty
|
||
|
}
|
||
|
return strings.ToUpper(s), nil
|
||
|
}
|
||
|
|
||
|
func (stringService) Count(s string) int {
|
||
|
return len(s)
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
svc := stringService{}
|
||
|
|
||
|
uppercaseHandler := httptransport.NewServer(
|
||
|
makeUppercaseEndpoint(svc),
|
||
|
decodeUppercaseRequest,
|
||
|
encodeResponse,
|
||
|
)
|
||
|
|
||
|
countHandler := httptransport.NewServer(
|
||
|
makeCountEndpoint(svc),
|
||
|
decodeCountRequest,
|
||
|
encodeResponse,
|
||
|
)
|
||
|
|
||
|
http.Handle("/uppercase", uppercaseHandler)
|
||
|
http.Handle("/count", countHandler)
|
||
|
log.Fatal(http.ListenAndServe(":8080", nil))
|
||
|
}
|
||
|
|
||
|
func makeUppercaseEndpoint(svc StringService) endpoint.Endpoint {
|
||
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||
|
req := request.(uppercaseRequest)
|
||
|
v, err := svc.Uppercase(req.S)
|
||
|
if err != nil {
|
||
|
return uppercaseResponse{v, err.Error()}, nil
|
||
|
}
|
||
|
return uppercaseResponse{v, ""}, nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func makeCountEndpoint(svc StringService) endpoint.Endpoint {
|
||
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||
|
req := request.(countRequest)
|
||
|
v := svc.Count(req.S)
|
||
|
return countResponse{v}, nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func decodeUppercaseRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||
|
var request uppercaseRequest
|
||
|
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return request, nil
|
||
|
}
|
||
|
|
||
|
func decodeCountRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||
|
var request countRequest
|
||
|
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return request, nil
|
||
|
}
|
||
|
|
||
|
func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
|
||
|
return json.NewEncoder(w).Encode(response)
|
||
|
}
|
||
|
|
||
|
type uppercaseRequest struct {
|
||
|
S string `json:"s"`
|
||
|
}
|
||
|
|
||
|
type uppercaseResponse struct {
|
||
|
V string `json:"v"`
|
||
|
Err string `json:"err,omitempty"` // errors don't define JSON marshaling
|
||
|
}
|
||
|
|
||
|
type countRequest struct {
|
||
|
S string `json:"s"`
|
||
|
}
|
||
|
|
||
|
type countResponse struct {
|
||
|
V int `json:"v"`
|
||
|
}
|
||
|
|
||
|
// ErrEmpty is returned when an input string is empty.
|
||
|
var ErrEmpty = errors.New("empty string")
|