Initial checkin
This commit is contained in:
commit
ef921ff728
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
8
.idea/cure.iml
Normal file
8
.idea/cure.iml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
4
.idea/encodings.xml
Normal file
4
.idea/encodings.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
|
||||
</project>
|
10
.idea/inspectionProfiles/Project_Default.xml
Normal file
10
.idea/inspectionProfiles/Project_Default.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
6
.idea/misc.xml
Normal file
6
.idea/misc.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/cure.iml" filepath="$PROJECT_DIR$/.idea/cure.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
208
cure.go
Normal file
208
cure.go
Normal file
|
@ -0,0 +1,208 @@
|
|||
// Common Uniform Rest Endpoint
|
||||
//
|
||||
// This is a library to access REST endpoints in a simplified way.
|
||||
package cure // import "udico.de/cure"
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"github.com/golang/protobuf/jsonpb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Endpoint struct {
|
||||
// The base url of the REST API
|
||||
Base string
|
||||
|
||||
// use this string as user agent
|
||||
UserAgent string
|
||||
|
||||
// Additional HTTP header attributes to set in every call.
|
||||
// You can (and should) also set per Call attributes within the Call object
|
||||
Head map[string]string
|
||||
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func New(baseurl string) *Endpoint {
|
||||
return &Endpoint{
|
||||
Base: baseurl,
|
||||
UserAgent: "Common Uniform Rest Endpoint, 1.0.0",
|
||||
Head: make(map[string]string),
|
||||
client: &http.Client{},
|
||||
}
|
||||
}
|
||||
|
||||
type call struct {
|
||||
url string
|
||||
method string
|
||||
api *Endpoint
|
||||
|
||||
// HTTP header attributes to set. These will override the ones set within the endpoint.
|
||||
Head map[string]string
|
||||
|
||||
// The parameters of your call. Depending on the method, they'll be appended to the query or posted url-form-encoded
|
||||
Parameters map[string]string
|
||||
|
||||
// If set, this data will be used as POST data (
|
||||
Body *bytes.Reader
|
||||
}
|
||||
|
||||
type callret struct {
|
||||
Code int
|
||||
Message string
|
||||
err error
|
||||
}
|
||||
|
||||
func (r callret) Ok() bool {
|
||||
if r.err != nil {
|
||||
return false
|
||||
}
|
||||
// We don't expect 1xx codes
|
||||
if (r.Code / 100) > 2 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Simplify error handling at client side
|
||||
func (r callret) Error() error {
|
||||
if r.err != nil {
|
||||
return r.err
|
||||
}
|
||||
if (r.Code / 100) > 2 {
|
||||
return errors.New(r.Message)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Endpoint) createCall(method, endpoint string) *call {
|
||||
ret := &call{
|
||||
url: a.Base + endpoint, // todo: ensure we have a valid url
|
||||
method: method,
|
||||
api: a,
|
||||
Head: make(map[string]string),
|
||||
Parameters: make(map[string]string),
|
||||
}
|
||||
ret.Head["user-agent"] = a.UserAgent
|
||||
for k, v := range a.Head {
|
||||
ret.Head[k] = v
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (a *Endpoint) Get(endpoint string) *call {
|
||||
return a.createCall("GET", endpoint)
|
||||
}
|
||||
|
||||
func (a *Endpoint) PostForm(endpoint string) *call {
|
||||
ret := a.createCall("POST", endpoint)
|
||||
ret.Head["content-type"] = "application/x-www-form-urlencoded"
|
||||
return ret
|
||||
}
|
||||
|
||||
func (a *Endpoint) PostBody(endpoint string) *call {
|
||||
ret := a.createCall("POST", endpoint)
|
||||
ret.Head["content-type"] = "application/json"
|
||||
return ret
|
||||
}
|
||||
|
||||
func (c *call) Param(param interface{}) *call {
|
||||
marshaller := new(jsonpb.Marshaler)
|
||||
marshaller.EmitDefaults = false
|
||||
marshaller.EnumsAsInts = false
|
||||
marshaller.OrigName = true
|
||||
buf := &bytes.Buffer{}
|
||||
_ = marshaller.Marshal(buf, param.(proto.Message))
|
||||
logrus.Debug(string(buf.Bytes()[:]))
|
||||
logrus.Debug(string(buf.Bytes()[:]))
|
||||
c.Body = bytes.NewReader(buf.Bytes())
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *call) Fire(ctx context.Context, result interface{}) callret {
|
||||
// disable HTTP2
|
||||
//client := &http.Client{Transport: &http.Transport{TLSNextProto: make(map[string]func(string, *tls.Conn) http.RoundTripper)}}
|
||||
//client := &http.Client{}
|
||||
|
||||
// handle POST parameters
|
||||
var request *http.Request
|
||||
var err error
|
||||
if c.method == "POST" {
|
||||
if c.Body != nil {
|
||||
request, err = http.NewRequest(c.method, c.url, c.Body)
|
||||
//request.Header.Set("content-length", fmt.Sprintf("%v", c.Body.Len()))
|
||||
} else {
|
||||
fdata := url.Values{}
|
||||
for k, v := range c.Parameters {
|
||||
fdata.Add(k, v)
|
||||
}
|
||||
logrus.Debug(fdata.Encode())
|
||||
sRead := strings.NewReader(fdata.Encode())
|
||||
request, err = http.NewRequest(c.method, c.url, sRead)
|
||||
}
|
||||
} else {
|
||||
request, err = http.NewRequest(c.method, c.url, nil)
|
||||
}
|
||||
|
||||
for k, v := range c.Head {
|
||||
request.Header.Set(k, v)
|
||||
}
|
||||
|
||||
request = request.WithContext(ctx)
|
||||
|
||||
// handle GET parameters
|
||||
if c.method == "GET" {
|
||||
gdata := request.URL.Query()
|
||||
for k, v := range c.Parameters {
|
||||
gdata.Add(k, v)
|
||||
}
|
||||
request.URL.RawQuery = gdata.Encode()
|
||||
}
|
||||
|
||||
logrus.Debugf("%v %v", c.method, c.url)
|
||||
for k, v := range c.Head {
|
||||
logrus.Debugf(" [%v: %v]", k, v)
|
||||
}
|
||||
for k, v := range c.Parameters {
|
||||
logrus.Debugf(" + %v = '%v'", k, v)
|
||||
}
|
||||
|
||||
hbuf := &bytes.Buffer{}
|
||||
request.Header.Write(hbuf)
|
||||
|
||||
// go!
|
||||
response, err := c.api.client.Do(request)
|
||||
if err != nil {
|
||||
return callret{0, "", err}
|
||||
}
|
||||
logrus.Debugf("-> %v", response.Status)
|
||||
|
||||
if response == nil {
|
||||
return callret{0, "", errors.New("empty response")}
|
||||
}
|
||||
|
||||
// no result requested
|
||||
if result == nil {
|
||||
return callret{0, "", nil}
|
||||
}
|
||||
|
||||
// TODO: dump the content
|
||||
//buf := &bytes.Buffer{}
|
||||
buf, err := ioutil.ReadAll(response.Body)
|
||||
bbuf := bytes.NewReader(buf)
|
||||
logrus.Debug(string(buf[:]))
|
||||
|
||||
unmarshaller := new(jsonpb.Unmarshaler)
|
||||
unmarshaller.AllowUnknownFields = true
|
||||
return callret{
|
||||
response.StatusCode,
|
||||
response.Status,
|
||||
unmarshaller.Unmarshal(bbuf, result.(proto.Message)),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user