Skip to content

Commit fde91ab

Browse files
author
Derek Dowling
committed
Adding support for intermediate client requests in jsc, allows custom headers to be set before sending
Adding missing stdlogger Adding missing stdlogger
1 parent b4f0fb1 commit fde91ab

File tree

11 files changed

+198
-43
lines changed

11 files changed

+198
-43
lines changed

Godeps/Godeps.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Godeps/_workspace/src/github.com/derekdowling/go-stdlogger/.gitignore

+24
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Godeps/_workspace/src/github.com/derekdowling/go-stdlogger/LICENSE

+22
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Godeps/_workspace/src/github.com/derekdowling/go-stdlogger/README.md

+24
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Godeps/_workspace/src/github.com/derekdowling/go-stdlogger/logger.go

+24
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/client.go

+24-24
Original file line numberDiff line numberDiff line change
@@ -72,49 +72,49 @@ func setIDPath(url *url.URL, resource string, id string) {
7272
}
7373
}
7474

75-
// objectToPayload first prepares/validates the object to ensure it is JSON
76-
// spec compatible, and then marshals it to JSON
77-
func objectToPayload(request *http.Request, object *jsh.Object) ([]byte, *jsh.Error) {
75+
// prepareBody first prepares/validates the object to ensure it is JSON
76+
// spec compatible, and then marshals it to JSON, sets the request body and
77+
// corresponding attributes
78+
func prepareBody(request *http.Request, object *jsh.Object) error {
7879

7980
err := object.Validate(request, false)
8081
if err != nil {
81-
return nil, jsh.ISE(fmt.Sprintf("Error preparing object: %s", err.Error()))
82+
return fmt.Errorf("Error preparing object: %s", err.Error())
8283
}
8384

8485
doc := jsh.Build(object)
8586

86-
jsonContent, jsonErr := json.MarshalIndent(doc, "", " ")
87+
jsonContent, jsonErr := json.MarshalIndent(doc, "", " ")
8788
if jsonErr != nil {
88-
return nil, jsh.ISE(fmt.Sprintf("Unable to prepare JSON content: %s", jsonErr))
89+
return fmt.Errorf("Unable to prepare JSON content: %s", jsonErr.Error())
8990
}
9091

91-
return jsonContent, nil
92-
}
93-
94-
// sendPayloadRequest is required for sending JSON payload related requests
95-
// because by default the http package does not set Content-Length headers
96-
func doObjectRequest(request *http.Request, object *jsh.Object) (*jsh.Document, *http.Response, *jsh.Error) {
92+
request.Body = jsh.CreateReadCloser(jsonContent)
93+
request.ContentLength = int64(len(jsonContent))
9794

98-
payload, err := objectToPayload(request, object)
99-
if err != nil {
100-
return nil, nil, jsh.ISE(fmt.Sprintf("Error converting object to JSON: %s", err.Error()))
101-
}
95+
return nil
96+
}
10297

103-
// prepare payload and corresponding headers
104-
request.Body = jsh.CreateReadCloser(payload)
105-
request.Header.Add("Content-Type", jsh.ContentType)
98+
// Do sends a the specified request to a JSON API compatible endpoint and
99+
// returns the resulting JSON Document if possible along with the response,
100+
// and any errors that were encountered while sending, or parsing the
101+
// JSON Document.
102+
func Do(request *http.Request) (*jsh.Document, *http.Response, error) {
106103

107-
contentLength := strconv.Itoa(len(payload))
108-
request.ContentLength = int64(len(payload))
109-
request.Header.Set("Content-Length", contentLength)
104+
request.Header.Set("Content-Type", jsh.ContentType)
105+
request.Header.Set("Content-Length", strconv.Itoa(int(request.ContentLength)))
110106

111107
client := &http.Client{}
112108
httpResponse, clientErr := client.Do(request)
113109

114110
if clientErr != nil {
115-
return nil, nil, jsh.ISE(fmt.Sprintf(
111+
return nil, nil, fmt.Errorf(
116112
"Error sending %s request: %s", request.Method, clientErr.Error(),
117-
))
113+
)
114+
}
115+
116+
if request.Method == "DELETE" {
117+
return nil, httpResponse, nil
118118
}
119119

120120
document, err := Document(httpResponse)

client/delete.go

+19-9
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,28 @@ import (
88
"github.com/derekdowling/go-json-spec-handler"
99
)
1010

11-
// Delete allows a user to make an outbound DELETE /resources/:id request:
11+
// Delete allows a user to make an outbound "DELETE /resource/:id" request.
1212
//
1313
// resp, err := jsh.Delete("http://apiserver", "user", "2")
1414
//
15-
func Delete(urlStr string, resourceType string, id string) (*http.Response, *jsh.Error) {
15+
func Delete(urlStr string, resourceType string, id string) (*http.Response, error) {
16+
request, err := DeleteRequest(urlStr, resourceType, id)
17+
if err != nil {
18+
return nil, err
19+
}
20+
21+
_, response, err := Do(request)
22+
if err != nil {
23+
return nil, err
24+
}
25+
26+
return response, nil
27+
}
1628

29+
// DeleteRequest returns a fully formatted request for performing a JSON API DELETE.
30+
// This is useful for if you need to set custom headers on the request. Otherwise
31+
// just use "jsc.Delete".
32+
func DeleteRequest(urlStr string, resourceType string, id string) (*http.Request, error) {
1733
u, err := url.Parse(urlStr)
1834
if err != nil {
1935
return nil, jsh.ISE(fmt.Sprintf("Error parsing URL: %s", err.Error()))
@@ -27,11 +43,5 @@ func Delete(urlStr string, resourceType string, id string) (*http.Response, *jsh
2743
return nil, jsh.ISE(fmt.Sprintf("Error creating DELETE request: %s", err.Error()))
2844
}
2945

30-
client := &http.Client{}
31-
response, err := client.Do(request)
32-
if err != nil {
33-
return nil, jsh.ISE(fmt.Sprintf("Error sending DELETE request: %s", err.Error()))
34-
}
35-
36-
return response, nil
46+
return request, nil
3747
}

client/delete_test.go

+18-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,31 @@
11
package jsc
22

33
import (
4+
"log"
5+
"net/http"
6+
"net/http/httptest"
47
"testing"
58

69
. "github.com/smartystreets/goconvey/convey"
710
)
811

912
func TestDelete(t *testing.T) {
1013

11-
Convey("Delete Tests", t, func() {
14+
Convey("DELETE Tests", t, func() {
1215

13-
})
16+
api := testAPI()
17+
server := httptest.NewServer(api)
18+
defer server.Close()
19+
20+
baseURL := server.URL
1421

22+
Convey("->Delete()", func() {
23+
resp, err := Delete(baseURL, "test", "1")
24+
25+
So(err, ShouldBeNil)
26+
log.Printf("patchErr = %+v\n", err)
27+
log.Printf("resp = %+v\n", resp)
28+
So(resp.StatusCode, ShouldEqual, http.StatusOK)
29+
})
30+
})
1531
}

client/patch.go

+20-3
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,34 @@ import (
1717
// updatedObj := json.First()
1818
//
1919
func Patch(baseURL string, object *jsh.Object) (*jsh.Document, *http.Response, error) {
20+
request, err := PatchRequest(baseURL, object)
21+
if err != nil {
22+
return nil, nil, err
23+
}
24+
25+
return Do(request)
26+
}
27+
28+
// PatchRequest returns a fully formatted request with JSON body for performing
29+
// a JSONAPI PATCH. This is useful for if you need to set custom headers on the
30+
// request. Otherwise just use "jsc.Patch".
31+
func PatchRequest(baseURL string, object *jsh.Object) (*http.Request, error) {
2032
u, err := url.Parse(baseURL)
2133
if err != nil {
22-
return nil, nil, fmt.Errorf("Error parsing URL: %s", err.Error())
34+
return nil, fmt.Errorf("Error parsing URL: %s", err.Error())
2335
}
2436

2537
setIDPath(u, object.Type, object.ID)
2638

2739
request, err := http.NewRequest("PATCH", u.String(), nil)
2840
if err != nil {
29-
return nil, nil, fmt.Errorf("Error creating PATCH request: %s", err.Error())
41+
return nil, fmt.Errorf("Error creating PATCH request: %s", err.Error())
42+
}
43+
44+
err = prepareBody(request, object)
45+
if err != nil {
46+
return nil, err
3047
}
3148

32-
return doObjectRequest(request, object)
49+
return request, nil
3350
}

client/patch_test.go

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package jsc
22

33
import (
4-
"log"
54
"net/http"
65
"net/http/httptest"
76
"testing"
@@ -25,7 +24,6 @@ func TestPatch(t *testing.T) {
2524
So(err, ShouldBeNil)
2625

2726
json, resp, patchErr := Patch(baseURL, object)
28-
log.Printf("resp.Request = %+v\n", resp.Request)
2927

3028
So(resp.StatusCode, ShouldEqual, http.StatusOK)
3129
So(patchErr, ShouldBeNil)

client/post.go

+19-3
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,35 @@ import (
1414
// // does POST http://apiserver/user/123
1515
// json, resp, err := jsh.Post("http://apiserver", obj)
1616
func Post(baseURL string, object *jsh.Object) (*jsh.Document, *http.Response, error) {
17+
request, err := PostRequest(baseURL, object)
18+
if err != nil {
19+
return nil, nil, err
20+
}
21+
22+
return Do(request)
23+
}
1724

25+
// PostRequest returns a fully formatted request with JSON body for performing
26+
// a JSONAPI POST. This is useful for if you need to set custom headers on the
27+
// request. Otherwise just use "jsc.Post".
28+
func PostRequest(baseURL string, object *jsh.Object) (*http.Request, error) {
1829
u, err := url.Parse(baseURL)
1930
if err != nil {
20-
return nil, nil, fmt.Errorf("Error parsing URL: %s", err.Error())
31+
return nil, fmt.Errorf("Error parsing URL: %s", err.Error())
2132
}
2233

2334
// ghetto pluralization, fix when it becomes an issue
2435
setPath(u, object.Type)
2536

2637
request, err := http.NewRequest("POST", u.String(), nil)
2738
if err != nil {
28-
return nil, nil, fmt.Errorf("Error building POST request: %s", err.Error())
39+
return nil, fmt.Errorf("Error building POST request: %s", err.Error())
40+
}
41+
42+
err = prepareBody(request, object)
43+
if err != nil {
44+
return nil, err
2945
}
3046

31-
return doObjectRequest(request, object)
47+
return request, nil
3248
}

0 commit comments

Comments
 (0)