Skip to content

Commit be68f56

Browse files
authored
Merge pull request #299 from manyminds/framework-routing
Installl adapter via conditional build tags
2 parents d8e0ec7 + 48da564 commit be68f56

14 files changed

+482
-27
lines changed

.travis.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,14 @@ install:
1414
- go get -u github.com/golang/lint/golint
1515
- go get -u github.com/modocache/gover
1616
- go get -u github.com/mattn/goveralls
17+
# optional dependencies
18+
- go get -u github.com/gin-gonic/gin
19+
- go get -u github.com/gorilla/mux
1720

1821
script:
1922
- ginkgo -r -cover --randomizeAllSpecs --randomizeSuites --failOnPending --trace --race --progress
23+
- ginkgo -tags=gorillamux -r --randomizeSuites --failOnPending --trace --race
24+
- ginkgo -tags=gingonic -r --randomizeSuites --failOnPending --trace --race
2025
- rm examples/examples.coverprofile
2126
- bash scripts/fmtpolice
2227
- gover

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,14 +333,16 @@ In order to use omitempty with those types, you need to specify them as pointers
333333
If you want to use api2go with [gin](https://github.com/gin-gonic/gin) you need to use a different router than the default one.
334334
Get the according adapter using:
335335

336-
```go get github.com/manyminds/api2go-adapter/gingonic```
336+
```go get -tags=gingonic github.com/manyminds/api2go```
337+
338+
Currently the supported tags are: `gingonic` or `gorillamux`.
337339

338340
After that you can bootstrap api2go the following way:
339341
```go
340342
import (
341343
"github.com/gin-gonic/gin"
342344
"github.com/manyminds/api2go"
343-
"github.com/manyminds/api2go-adapter/gingonic"
345+
"github.com/manyminds/api2go/routing"
344346
"github.com/manyminds/api2go/examples/model"
345347
"github.com/manyminds/api2go/examples/resource"
346348
"github.com/manyminds/api2go/examples/storage"
@@ -351,7 +353,7 @@ After that you can bootstrap api2go the following way:
351353
api := api2go.NewAPIWithRouting(
352354
"api",
353355
api2go.NewStaticResolver("/"),
354-
gingonic.New(r),
356+
routing.Gin(r),
355357
)
356358

357359
userStorage := storage.NewUserStorage()

api.go

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,13 @@ type notAllowedHandler struct {
172172
func (n notAllowedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
173173
err := NewHTTPError(nil, "Method Not Allowed", http.StatusMethodNotAllowed)
174174
w.WriteHeader(http.StatusMethodNotAllowed)
175-
n.API.handleError(err, w, r)
175+
176+
contentType := defaultContentTypHeader
177+
if n.API != nil {
178+
contentType = n.API.ContentType
179+
}
180+
181+
handleError(err, w, r, contentType)
176182
}
177183

178184
type resource struct {
@@ -262,7 +268,7 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source interfac
262268
err := res.handleIndex(c, w, r, *info)
263269
api.contextPool.Put(c)
264270
if err != nil {
265-
api.handleError(err, w, r)
271+
handleError(err, w, r, api.ContentType)
266272
}
267273
})
268274

@@ -284,7 +290,7 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source interfac
284290
err := res.handleRead(c, w, r, params, *info)
285291
api.contextPool.Put(c)
286292
if err != nil {
287-
api.handleError(err, w, r)
293+
handleError(err, w, r, api.ContentType)
288294
}
289295
})
290296
}
@@ -303,7 +309,7 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source interfac
303309
err := res.handleReadRelation(c, w, r, params, *info, relation)
304310
api.contextPool.Put(c)
305311
if err != nil {
306-
api.handleError(err, w, r)
312+
handleError(err, w, r, api.ContentType)
307313
}
308314
}
309315
}(relation))
@@ -317,7 +323,7 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source interfac
317323
err := res.handleLinked(c, api, w, r, params, relation, *info)
318324
api.contextPool.Put(c)
319325
if err != nil {
320-
api.handleError(err, w, r)
326+
handleError(err, w, r, api.ContentType)
321327
}
322328
}
323329
}(relation))
@@ -330,7 +336,7 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source interfac
330336
err := res.handleReplaceRelation(c, w, r, params, relation)
331337
api.contextPool.Put(c)
332338
if err != nil {
333-
api.handleError(err, w, r)
339+
handleError(err, w, r, api.ContentType)
334340
}
335341
}
336342
}(relation))
@@ -345,7 +351,7 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source interfac
345351
err := res.handleAddToManyRelation(c, w, r, params, relation)
346352
api.contextPool.Put(c)
347353
if err != nil {
348-
api.handleError(err, w, r)
354+
handleError(err, w, r, api.ContentType)
349355
}
350356
}
351357
}(relation))
@@ -358,7 +364,7 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source interfac
358364
err := res.handleDeleteToManyRelation(c, w, r, params, relation)
359365
api.contextPool.Put(c)
360366
if err != nil {
361-
api.handleError(err, w, r)
367+
handleError(err, w, r, api.ContentType)
362368
}
363369
}
364370
}(relation))
@@ -375,7 +381,7 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source interfac
375381
err := res.handleCreate(c, w, r, info.prefix, *info)
376382
api.contextPool.Put(c)
377383
if err != nil {
378-
api.handleError(err, w, r)
384+
handleError(err, w, r, api.ContentType)
379385
}
380386
})
381387
}
@@ -388,7 +394,7 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source interfac
388394
err := res.handleDelete(c, w, r, params)
389395
api.contextPool.Put(c)
390396
if err != nil {
391-
api.handleError(err, w, r)
397+
handleError(err, w, r, api.ContentType)
392398
}
393399
})
394400
}
@@ -402,7 +408,7 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source interfac
402408
err := res.handleUpdate(c, w, r, params, *info)
403409
api.contextPool.Put(c)
404410
if err != nil {
405-
api.handleError(err, w, r)
411+
handleError(err, w, r, api.ContentType)
406412
}
407413
})
408414
}
@@ -413,7 +419,6 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source interfac
413419
}
414420

415421
func getAllowedMethods(source interface{}, collection bool) []string {
416-
417422
result := []string{http.MethodOptions}
418423

419424
if _, ok := source.(ResourceGetter); ok {
@@ -597,7 +602,6 @@ func (res *resource) handleLinked(c APIContexter, api *API, w http.ResponseWrite
597602
}
598603

599604
func (res *resource) handleCreate(c APIContexter, w http.ResponseWriter, r *http.Request, prefix string, info information) error {
600-
601605
source, ok := res.source.(ResourceCreator)
602606

603607
if !ok {
@@ -1151,16 +1155,16 @@ func replaceAttributes(query *map[string][]string, entry *jsonapi.Data) map[stri
11511155
return nil
11521156
}
11531157

1154-
func (api *API) handleError(err error, w http.ResponseWriter, r *http.Request) {
1158+
func handleError(err error, w http.ResponseWriter, r *http.Request, contentType string) {
11551159
log.Println(err)
11561160
if e, ok := err.(HTTPError); ok {
1157-
writeResult(w, []byte(marshalHTTPError(e)), e.status, api.ContentType)
1161+
writeResult(w, []byte(marshalHTTPError(e)), e.status, contentType)
11581162
return
11591163

11601164
}
11611165

11621166
e := NewHTTPError(err, err.Error(), http.StatusInternalServerError)
1163-
writeResult(w, []byte(marshalHTTPError(e)), http.StatusInternalServerError, api.ContentType)
1167+
writeResult(w, []byte(marshalHTTPError(e)), http.StatusInternalServerError, contentType)
11641168
}
11651169

11661170
// TODO: this can also be replaced with a struct into that we directly json.Unmarshal

api_entity_name_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ var _ = Describe("Test route renaming with EntityNamer interface", func() {
7676
body *strings.Reader
7777
)
7878
BeforeEach(func() {
79-
api = NewAPI("v1")
79+
api = NewAPIWithRouting(testPrefix, NewStaticResolver(""), newTestRouter())
8080
api.AddResource(BaguetteTaste{}, BaguetteResource{})
8181
rec = httptest.NewRecorder()
8282
body = strings.NewReader(`

api_object_initializer_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ var _ = Describe("Test resource implementing the ObjectInitializer interface", f
4040
body *strings.Reader
4141
)
4242
BeforeEach(func() {
43-
api = NewAPI("v1")
43+
api = NewAPIWithRouting(testPrefix, NewStaticResolver(""), newTestRouter())
4444
api.AddResource(Post{}, ObjectInitializerResource{})
4545
rec = httptest.NewRecorder()
4646
body = strings.NewReader(`

api_test.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717
"gopkg.in/guregu/null.v2"
1818
)
1919

20+
const testPrefix = "v1"
21+
2022
type requestURLResolver struct {
2123
r http.Request
2224
calls int
@@ -1236,7 +1238,7 @@ var _ = Describe("RestHandler", func() {
12361238
"7": {ID: "7", Title: "Hello, World!"},
12371239
}, false}
12381240

1239-
api = NewAPI("v1")
1241+
api = NewAPIWithRouting(testPrefix, NewStaticResolver(""), newTestRouter())
12401242
api.AddResource(Post{}, source)
12411243

12421244
rec = httptest.NewRecorder()
@@ -1413,10 +1415,10 @@ var _ = Describe("RestHandler", func() {
14131415
req, err := http.NewRequest("PATCH", "/v1/posts", reqBody)
14141416
Expect(err).To(BeNil())
14151417
api.Handler().ServeHTTP(rec, req)
1416-
expected := `{"errors":[{"status":"405","title":"Method Not Allowed"}]}`
1417-
Expect(rec.Body.String()).To(MatchJSON(expected))
14181418
Expect(rec.Header().Get("Content-Type")).To(Equal(defaultContentTypHeader))
14191419
Expect(rec.Code).To(Equal(http.StatusMethodNotAllowed))
1420+
expected := `{"errors":[{"status":"405","title":"Method Not Allowed"}]}`
1421+
Expect(rec.Body.String()).To(MatchJSON(expected))
14201422
})
14211423
})
14221424

@@ -1463,7 +1465,7 @@ var _ = Describe("RestHandler", func() {
14631465
"1": {ID: "1", Title: "Hello, World!"},
14641466
}, false}
14651467

1466-
api = NewAPI("v1")
1468+
api = NewAPIWithRouting(testPrefix, NewStaticResolver(""), newTestRouter())
14671469
api.AddResource(Post{}, source)
14681470
MiddleTest := func(c APIContexter, w http.ResponseWriter, r *http.Request) {
14691471
w.Header().Add("x-test", "test123")
@@ -1497,7 +1499,7 @@ var _ = Describe("RestHandler", func() {
14971499
"1": {ID: "1", Title: "Hello, World!"},
14981500
}, false}
14991501

1500-
api = NewAPI("v1")
1502+
api = NewAPIWithRouting(testPrefix, NewStaticResolver(""), newTestRouter())
15011503
api.AddResource(Post{}, source)
15021504
api.SetContextAllocator(func(api *API) APIContexter {
15031505
customContextCalled = true
@@ -1780,7 +1782,7 @@ var _ = Describe("RestHandler", func() {
17801782
source = &fixtureSource{map[string]*Post{
17811783
"1": {ID: "1", Title: "Nice Post", Value: null.FloatFrom(13.37), Author: &author},
17821784
}, false}
1783-
mainAPI = NewAPI("v1")
1785+
mainAPI = NewAPIWithRouting(testPrefix, NewStaticResolver(""), newTestRouter())
17841786
mainAPI.AddResource(Post{}, source)
17851787

17861788
author2 := User{ID: "888", Name: "Version 2 Tester", Info: "Is the next version"}

gingonic_router_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// +build gingonic,!gorillamux
2+
3+
package api2go
4+
5+
import (
6+
"log"
7+
8+
"github.com/gin-gonic/gin"
9+
"github.com/manyminds/api2go/routing"
10+
)
11+
12+
func newTestRouter() routing.Routeable {
13+
gin.SetMode(gin.ReleaseMode)
14+
gg := gin.Default()
15+
notFound := func(c *gin.Context) {
16+
notAllowedHandler{}.ServeHTTP(c.Writer, c.Request)
17+
}
18+
19+
gg.NoRoute(notFound)
20+
21+
return routing.Gin(gg)
22+
}
23+
24+
func init() {
25+
log.Println("Testing with gin router")
26+
}

gorillamux_router_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// +build !gingonic,gorillamux
2+
3+
package api2go
4+
5+
import (
6+
"log"
7+
8+
"github.com/gorilla/mux"
9+
"github.com/manyminds/api2go/routing"
10+
)
11+
12+
func newTestRouter() routing.Routeable {
13+
router := mux.NewRouter()
14+
router.MethodNotAllowedHandler = notAllowedHandler{}
15+
return routing.Gorilla(router)
16+
}
17+
18+
func init() {
19+
log.Println("Testing with gorilla router")
20+
}

httprouter_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// +build !gingonic,!gorillamux
2+
3+
package api2go
4+
5+
import (
6+
"log"
7+
8+
"github.com/manyminds/api2go/routing"
9+
)
10+
11+
func newTestRouter() routing.Routeable {
12+
return routing.NewHTTPRouter(testPrefix, &notAllowedHandler{})
13+
}
14+
15+
func init() {
16+
log.Println("Testing with default router")
17+
}

routing/gingonic.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// +build gingonic,!gorillamux
2+
3+
package routing
4+
5+
import (
6+
"net/http"
7+
8+
"github.com/gin-gonic/gin"
9+
)
10+
11+
type ginRouter struct {
12+
router *gin.Engine
13+
}
14+
15+
func (g ginRouter) Handler() http.Handler {
16+
return g.router
17+
}
18+
19+
func (g ginRouter) Handle(protocol, route string, handler HandlerFunc) {
20+
wrappedCallback := func(c *gin.Context) {
21+
params := map[string]string{}
22+
for _, p := range c.Params {
23+
params[p.Key] = p.Value
24+
}
25+
26+
handler(c.Writer, c.Request, params)
27+
}
28+
29+
g.router.Handle(protocol, route, wrappedCallback)
30+
}
31+
32+
//Gin creates a new api2go router to use with the gin framework
33+
func Gin(g *gin.Engine) Routeable {
34+
return &ginRouter{router: g}
35+
}

0 commit comments

Comments
 (0)