Skip to content

Commit 0d16cbb

Browse files
committed
Merge pull request #170 from interlock/context
Added net/context support.
2 parents b9ace5b + 1d16d01 commit 0d16cbb

File tree

5 files changed

+331
-50
lines changed

5 files changed

+331
-50
lines changed

api.go

Lines changed: 101 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,18 @@ type resource struct {
191191
marshalers map[string]ContentMarshaler
192192
}
193193

194+
// middlewareChain executes the middleeware chain setup
195+
func (api *API) middlewareChain(c APIContexter, w http.ResponseWriter, r *http.Request) {
196+
for _, middleware := range api.middlewares {
197+
middleware(c, w, r)
198+
}
199+
}
200+
201+
// allocateContext creates a context for the api.contextPool, saving allocations
202+
func (api *API) allocateDefaultContext() APIContexter {
203+
return &APIContext{}
204+
}
205+
194206
func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source CRUD, marshalers map[string]ContentMarshaler) *resource {
195207
resourceType := reflect.TypeOf(prototype)
196208
if resourceType.Kind() != reflect.Struct && resourceType.Kind() != reflect.Ptr {
@@ -224,24 +236,40 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source CRUD, ma
224236
}
225237

226238
api.router.Handle("OPTIONS", api.prefix+name, func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
239+
c := api.contextPool.Get().(APIContexter)
240+
c.Reset()
241+
api.middlewareChain(c, w, r)
227242
w.Header().Set("Allow", "GET,POST,PATCH,OPTIONS")
228243
w.WriteHeader(http.StatusNoContent)
244+
api.contextPool.Put(c)
229245
})
230246

231247
api.router.Handle("OPTIONS", api.prefix+name+"/:id", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
248+
c := api.contextPool.Get().(APIContexter)
249+
c.Reset()
250+
api.middlewareChain(c, w, r)
232251
w.Header().Set("Allow", "GET,PATCH,DELETE,OPTIONS")
233252
w.WriteHeader(http.StatusNoContent)
253+
api.contextPool.Put(c)
234254
})
235255

236256
api.router.GET(api.prefix+name, func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
237-
err := res.handleIndex(w, r, api.info)
257+
c := api.contextPool.Get().(APIContexter)
258+
c.Reset()
259+
api.middlewareChain(c, w, r)
260+
err := res.handleIndex(c, w, r, api.info)
261+
api.contextPool.Put(c)
238262
if err != nil {
239263
handleError(err, w, r, marshalers)
240264
}
241265
})
242266

243267
api.router.GET(api.prefix+name+"/:id", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
244-
err := res.handleRead(w, r, ps, api.info)
268+
c := api.contextPool.Get().(APIContexter)
269+
c.Reset()
270+
api.middlewareChain(c, w, r)
271+
err := res.handleRead(c, w, r, ps, api.info)
272+
api.contextPool.Put(c)
245273
if err != nil {
246274
handleError(err, w, r, marshalers)
247275
}
@@ -254,7 +282,11 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source CRUD, ma
254282
for _, relation := range relations {
255283
api.router.GET(api.prefix+name+"/:id/relationships/"+relation.Name, func(relation jsonapi.Reference) httprouter.Handle {
256284
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
257-
err := res.handleReadRelation(w, r, ps, api.info, relation)
285+
c := api.contextPool.Get().(APIContexter)
286+
c.Reset()
287+
api.middlewareChain(c, w, r)
288+
err := res.handleReadRelation(c, w, r, ps, api.info, relation)
289+
api.contextPool.Put(c)
258290
if err != nil {
259291
handleError(err, w, r, marshalers)
260292
}
@@ -263,7 +295,11 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source CRUD, ma
263295

264296
api.router.GET(api.prefix+name+"/:id/"+relation.Name, func(relation jsonapi.Reference) httprouter.Handle {
265297
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
266-
err := res.handleLinked(api, w, r, ps, relation, api.info)
298+
c := api.contextPool.Get().(APIContexter)
299+
c.Reset()
300+
api.middlewareChain(c, w, r)
301+
err := res.handleLinked(c, api, w, r, ps, relation, api.info)
302+
api.contextPool.Put(c)
267303
if err != nil {
268304
handleError(err, w, r, marshalers)
269305
}
@@ -272,7 +308,11 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source CRUD, ma
272308

273309
api.router.PATCH(api.prefix+name+"/:id/relationships/"+relation.Name, func(relation jsonapi.Reference) httprouter.Handle {
274310
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
275-
err := res.handleReplaceRelation(w, r, ps, relation)
311+
c := api.contextPool.Get().(APIContexter)
312+
c.Reset()
313+
api.middlewareChain(c, w, r)
314+
err := res.handleReplaceRelation(c, w, r, ps, relation)
315+
api.contextPool.Put(c)
276316
if err != nil {
277317
handleError(err, w, r, marshalers)
278318
}
@@ -283,7 +323,11 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source CRUD, ma
283323
// generate additional routes to manipulate to-many relationships
284324
api.router.POST(api.prefix+name+"/:id/relationships/"+relation.Name, func(relation jsonapi.Reference) httprouter.Handle {
285325
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
286-
err := res.handleAddToManyRelation(w, r, ps, relation)
326+
c := api.contextPool.Get().(APIContexter)
327+
c.Reset()
328+
api.middlewareChain(c, w, r)
329+
err := res.handleAddToManyRelation(c, w, r, ps, relation)
330+
api.contextPool.Put(c)
287331
if err != nil {
288332
handleError(err, w, r, marshalers)
289333
}
@@ -292,7 +336,11 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source CRUD, ma
292336

293337
api.router.DELETE(api.prefix+name+"/:id/relationships/"+relation.Name, func(relation jsonapi.Reference) httprouter.Handle {
294338
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
295-
err := res.handleDeleteToManyRelation(w, r, ps, relation)
339+
c := api.contextPool.Get().(APIContexter)
340+
c.Reset()
341+
api.middlewareChain(c, w, r)
342+
err := res.handleDeleteToManyRelation(c, w, r, ps, relation)
343+
api.contextPool.Put(c)
296344
if err != nil {
297345
handleError(err, w, r, marshalers)
298346
}
@@ -303,21 +351,33 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source CRUD, ma
303351
}
304352

305353
api.router.POST(api.prefix+name, func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
306-
err := res.handleCreate(w, r, api.prefix, api.info)
354+
c := api.contextPool.Get().(APIContexter)
355+
c.Reset()
356+
api.middlewareChain(c, w, r)
357+
err := res.handleCreate(c, w, r, api.prefix, api.info)
358+
api.contextPool.Put(c)
307359
if err != nil {
308360
handleError(err, w, r, marshalers)
309361
}
310362
})
311363

312364
api.router.DELETE(api.prefix+name+"/:id", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
313-
err := res.handleDelete(w, r, ps)
365+
c := api.contextPool.Get().(APIContexter)
366+
c.Reset()
367+
api.middlewareChain(c, w, r)
368+
err := res.handleDelete(c, w, r, ps)
369+
api.contextPool.Put(c)
314370
if err != nil {
315371
handleError(err, w, r, marshalers)
316372
}
317373
})
318374

319375
api.router.PATCH(api.prefix+name+"/:id", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
320-
err := res.handleUpdate(w, r, ps)
376+
c := api.contextPool.Get().(APIContexter)
377+
c.Reset()
378+
api.middlewareChain(c, w, r)
379+
err := res.handleUpdate(c, w, r, ps)
380+
api.contextPool.Put(c)
321381
if err != nil {
322382
handleError(err, w, r, marshalers)
323383
}
@@ -328,26 +388,27 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source CRUD, ma
328388
return &res
329389
}
330390

331-
func buildRequest(r *http.Request) Request {
391+
func buildRequest(c APIContexter, r *http.Request) Request {
332392
req := Request{PlainRequest: r}
333393
params := make(map[string][]string)
334394
for key, values := range r.URL.Query() {
335395
params[key] = strings.Split(values[0], ",")
336396
}
337397
req.QueryParams = params
338398
req.Header = r.Header
399+
req.Context = c
339400
return req
340401
}
341402

342-
func (res *resource) handleIndex(w http.ResponseWriter, r *http.Request, info information) error {
403+
func (res *resource) handleIndex(c APIContexter, w http.ResponseWriter, r *http.Request, info information) error {
343404
pagination := newPaginationQueryParams(r)
344405
if pagination.isValid() {
345406
source, ok := res.source.(PaginatedFindAll)
346407
if !ok {
347408
return NewHTTPError(nil, "Resource does not implement the PaginatedFindAll interface", http.StatusNotFound)
348409
}
349410

350-
count, response, err := source.PaginatedFindAll(buildRequest(r))
411+
count, response, err := source.PaginatedFindAll(buildRequest(c, r))
351412
if err != nil {
352413
return err
353414
}
@@ -364,18 +425,18 @@ func (res *resource) handleIndex(w http.ResponseWriter, r *http.Request, info in
364425
return NewHTTPError(nil, "Resource does not implement the FindAll interface", http.StatusNotFound)
365426
}
366427

367-
response, err := source.FindAll(buildRequest(r))
428+
response, err := source.FindAll(buildRequest(c, r))
368429
if err != nil {
369430
return err
370431
}
371432

372433
return respondWith(response, info, http.StatusOK, w, r, res.marshalers)
373434
}
374435

375-
func (res *resource) handleRead(w http.ResponseWriter, r *http.Request, ps httprouter.Params, info information) error {
436+
func (res *resource) handleRead(c APIContexter, w http.ResponseWriter, r *http.Request, ps httprouter.Params, info information) error {
376437
id := ps.ByName("id")
377438

378-
response, err := res.source.FindOne(id, buildRequest(r))
439+
response, err := res.source.FindOne(id, buildRequest(c, r))
379440

380441
if err != nil {
381442
return err
@@ -384,10 +445,10 @@ func (res *resource) handleRead(w http.ResponseWriter, r *http.Request, ps httpr
384445
return respondWith(response, info, http.StatusOK, w, r, res.marshalers)
385446
}
386447

387-
func (res *resource) handleReadRelation(w http.ResponseWriter, r *http.Request, ps httprouter.Params, info information, relation jsonapi.Reference) error {
448+
func (res *resource) handleReadRelation(c APIContexter, w http.ResponseWriter, r *http.Request, ps httprouter.Params, info information, relation jsonapi.Reference) error {
388449
id := ps.ByName("id")
389450

390-
obj, err := res.source.FindOne(id, buildRequest(r))
451+
obj, err := res.source.FindOne(id, buildRequest(c, r))
391452
if err != nil {
392453
return err
393454
}
@@ -440,11 +501,11 @@ func (res *resource) handleReadRelation(w http.ResponseWriter, r *http.Request,
440501
}
441502

442503
// try to find the referenced resource and call the findAll Method with referencing resource id as param
443-
func (res *resource) handleLinked(api *API, w http.ResponseWriter, r *http.Request, ps httprouter.Params, linked jsonapi.Reference, info information) error {
504+
func (res *resource) handleLinked(c APIContexter, api *API, w http.ResponseWriter, r *http.Request, ps httprouter.Params, linked jsonapi.Reference, info information) error {
444505
id := ps.ByName("id")
445506
for _, resource := range api.resources {
446507
if resource.name == linked.Type {
447-
request := buildRequest(r)
508+
request := buildRequest(c, r)
448509
request.QueryParams[res.name+"ID"] = []string{id}
449510
request.QueryParams[res.name+"Name"] = []string{linked.Name}
450511

@@ -495,7 +556,7 @@ func (res *resource) handleLinked(api *API, w http.ResponseWriter, r *http.Reque
495556

496557
}
497558

498-
func (res *resource) handleCreate(w http.ResponseWriter, r *http.Request, prefix string, info information) error {
559+
func (res *resource) handleCreate(c APIContexter, w http.ResponseWriter, r *http.Request, prefix string, info information) error {
499560
ctx, err := unmarshalRequest(r, res.marshalers)
500561
if err != nil {
501562
return err
@@ -518,7 +579,7 @@ func (res *resource) handleCreate(w http.ResponseWriter, r *http.Request, prefix
518579
//TODO create multiple objects not only one.
519580
newObj := newObjs.Index(0).Interface()
520581

521-
response, err := res.source.Create(newObj, buildRequest(r))
582+
response, err := res.source.Create(newObj, buildRequest(c, r))
522583
if err != nil {
523584
return err
524585
}
@@ -545,8 +606,8 @@ func (res *resource) handleCreate(w http.ResponseWriter, r *http.Request, prefix
545606
}
546607
}
547608

548-
func (res *resource) handleUpdate(w http.ResponseWriter, r *http.Request, ps httprouter.Params) error {
549-
obj, err := res.source.FindOne(ps.ByName("id"), buildRequest(r))
609+
func (res *resource) handleUpdate(c APIContexter, w http.ResponseWriter, r *http.Request, ps httprouter.Params) error {
610+
obj, err := res.source.FindOne(ps.ByName("id"), buildRequest(c, r))
550611
if err != nil {
551612
return err
552613
}
@@ -609,7 +670,7 @@ func (res *resource) handleUpdate(w http.ResponseWriter, r *http.Request, ps htt
609670

610671
updatingObj := updatingObjs.Index(0).Interface()
611672

612-
response, err := res.source.Update(updatingObj, buildRequest(r))
673+
response, err := res.source.Update(updatingObj, buildRequest(c, r))
613674

614675
if err != nil {
615676
return err
@@ -619,7 +680,7 @@ func (res *resource) handleUpdate(w http.ResponseWriter, r *http.Request, ps htt
619680
case http.StatusOK:
620681
updated := response.Result()
621682
if updated == nil {
622-
internalResponse, err := res.source.FindOne(ps.ByName("id"), buildRequest(r))
683+
internalResponse, err := res.source.FindOne(ps.ByName("id"), buildRequest(c, r))
623684
if err != nil {
624685
return err
625686
}
@@ -643,13 +704,13 @@ func (res *resource) handleUpdate(w http.ResponseWriter, r *http.Request, ps htt
643704
}
644705
}
645706

646-
func (res *resource) handleReplaceRelation(w http.ResponseWriter, r *http.Request, ps httprouter.Params, relation jsonapi.Reference) error {
707+
func (res *resource) handleReplaceRelation(c APIContexter, w http.ResponseWriter, r *http.Request, ps httprouter.Params, relation jsonapi.Reference) error {
647708
var (
648709
err error
649710
editObj interface{}
650711
)
651712

652-
response, err := res.source.FindOne(ps.ByName("id"), buildRequest(r))
713+
response, err := res.source.FindOne(ps.ByName("id"), buildRequest(c, r))
653714
if err != nil {
654715
return err
655716
}
@@ -677,22 +738,22 @@ func (res *resource) handleReplaceRelation(w http.ResponseWriter, r *http.Reques
677738
}
678739

679740
if resType == reflect.Struct {
680-
_, err = res.source.Update(reflect.ValueOf(editObj).Elem().Interface(), buildRequest(r))
741+
_, err = res.source.Update(reflect.ValueOf(editObj).Elem().Interface(), buildRequest(c, r))
681742
} else {
682-
_, err = res.source.Update(editObj, buildRequest(r))
743+
_, err = res.source.Update(editObj, buildRequest(c, r))
683744
}
684745

685746
w.WriteHeader(http.StatusNoContent)
686747
return err
687748
}
688749

689-
func (res *resource) handleAddToManyRelation(w http.ResponseWriter, r *http.Request, ps httprouter.Params, relation jsonapi.Reference) error {
750+
func (res *resource) handleAddToManyRelation(c APIContexter, w http.ResponseWriter, r *http.Request, ps httprouter.Params, relation jsonapi.Reference) error {
690751
var (
691752
err error
692753
editObj interface{}
693754
)
694755

695-
response, err := res.source.FindOne(ps.ByName("id"), buildRequest(r))
756+
response, err := res.source.FindOne(ps.ByName("id"), buildRequest(c, r))
696757
if err != nil {
697758
return err
698759
}
@@ -741,22 +802,22 @@ func (res *resource) handleAddToManyRelation(w http.ResponseWriter, r *http.Requ
741802
targetObj.AddToManyIDs(relation.Name, newIDs)
742803

743804
if resType == reflect.Struct {
744-
_, err = res.source.Update(reflect.ValueOf(targetObj).Elem().Interface(), buildRequest(r))
805+
_, err = res.source.Update(reflect.ValueOf(targetObj).Elem().Interface(), buildRequest(c, r))
745806
} else {
746-
_, err = res.source.Update(targetObj, buildRequest(r))
807+
_, err = res.source.Update(targetObj, buildRequest(c, r))
747808
}
748809

749810
w.WriteHeader(http.StatusNoContent)
750811

751812
return err
752813
}
753814

754-
func (res *resource) handleDeleteToManyRelation(w http.ResponseWriter, r *http.Request, ps httprouter.Params, relation jsonapi.Reference) error {
815+
func (res *resource) handleDeleteToManyRelation(c APIContexter, w http.ResponseWriter, r *http.Request, ps httprouter.Params, relation jsonapi.Reference) error {
755816
var (
756817
err error
757818
editObj interface{}
758819
)
759-
response, err := res.source.FindOne(ps.ByName("id"), buildRequest(r))
820+
response, err := res.source.FindOne(ps.ByName("id"), buildRequest(c, r))
760821
if err != nil {
761822
return err
762823
}
@@ -805,9 +866,9 @@ func (res *resource) handleDeleteToManyRelation(w http.ResponseWriter, r *http.R
805866
targetObj.DeleteToManyIDs(relation.Name, obsoleteIDs)
806867

807868
if resType == reflect.Struct {
808-
_, err = res.source.Update(reflect.ValueOf(targetObj).Elem().Interface(), buildRequest(r))
869+
_, err = res.source.Update(reflect.ValueOf(targetObj).Elem().Interface(), buildRequest(c, r))
809870
} else {
810-
_, err = res.source.Update(targetObj, buildRequest(r))
871+
_, err = res.source.Update(targetObj, buildRequest(c, r))
811872
}
812873

813874
w.WriteHeader(http.StatusNoContent)
@@ -823,8 +884,8 @@ func getPointerToStruct(oldObj interface{}) interface{} {
823884
return ptr.Interface()
824885
}
825886

826-
func (res *resource) handleDelete(w http.ResponseWriter, r *http.Request, ps httprouter.Params) error {
827-
response, err := res.source.Delete(ps.ByName("id"), buildRequest(r))
887+
func (res *resource) handleDelete(c APIContexter, w http.ResponseWriter, r *http.Request, ps httprouter.Params) error {
888+
response, err := res.source.Delete(ps.ByName("id"), buildRequest(c, r))
828889
if err != nil {
829890
return err
830891
}

0 commit comments

Comments
 (0)