Skip to content

Commit a43bd0e

Browse files
author
Derek Dowling
committed
Merge pull request #9 from derekdowling/dd-jsc-headers
Adding support for intermediate client requests in jsc, allows custom…
2 parents b4f0fb1 + fde91ab commit a43bd0e

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)