// creates dummy client and user directly from the stores func createStoreDummies(ctx context.Context, password, redirect string) (*oauth2.Client, *oauth2.User) { // generate dummy user us, err := store.Get(ctx, oauth2.KeyUser) if err != nil { panic(err) } u := dummyNewUser(password) err = us.Create(store.NewConds(), u) if err != nil { panic(err) } // get related dummy client cs, err := store.Get(ctx, oauth2.KeyClient) if err != nil { panic(err) } c := dummyNewClient(redirect) c.UserID = u.ID err = cs.Create(store.NewConds(), c) if err != nil { panic(err) } return c, u }
// LoadAuthorize looks up AuthorizeData by a code. // Client information MUST be loaded together. // Optionally can return error if expired. func (storage *Storage) LoadAuthorize(code string) (d *osin.AuthorizeData, err error) { // TODO: use logger := log.NewContext(,sg) logger, errLogger := msg, errMsg logger.Log( "method", "LoadAuthorize", "code", code) // loading osin using osin storage srv, err := store.Get(storage.ctx, KeyAuth) if err != nil { return } defer srv.Close() e := &AuthorizeData{} conds := store.NewConds() conds.Add("code", code) err = srv.One(conds, e) if err != nil { return } else if e == nil { err = store.Error(http.StatusNotFound, "AuthorizeData not found for the code") return } // load client here var ok bool cli, err := storage.GetClient(e.ClientID) if err != nil { return } else if e.Client, ok = cli.(*Client); !ok { err = store.Error(http.StatusInternalServerError, "Internal Server Error") errLogger.Log( "method", "GetClient", "code", code, "cond", conds, "raw client", fmt.Sprintf("%#v", cli), "message", "Unable to cast raw client into Client") return } // load user data here if e.UserID != "" { userStore, err := store.Get(storage.ctx, KeyUser) if err != nil { return d, err } user := &User{} userStore.One(store.NewConds().Add("id", e.UserID), user) e.UserData = user } d = e.ToOsin() return }
// SaveAuthorize saves authorize data. func (storage *Storage) SaveAuthorize(d *osin.AuthorizeData) (err error) { // TODO: use logger := log.NewContext(,sg) logger := msg logger.Log( "method", "SaveAuthorize", "*osin.AuthorizeData", d) srv, err := store.Get(storage.ctx, KeyAuth) if err != nil { return } defer srv.Close() e := &AuthorizeData{} err = e.ReadOsin(d) if err != nil { return } // store client id with auth in database e.ClientID = e.Client.GetId() // create the auth data now err = srv.Create(store.NewConds(), e) return }
// LoadRefresh retrieves refresh AccessData. Client information MUST be loaded together. // AuthorizeData and AccessData DON'T NEED to be loaded if not easily available. // Optionally can return error if expired. func (storage *Storage) LoadRefresh(token string) (d *osin.AccessData, err error) { // TODO: use logger := log.NewContext(,sg) logger := msg logger.Log( "method", "LoadRefresh", "token", token) srv, err := store.Get(storage.ctx, KeyAccess) if err != nil { return } defer srv.Close() e := &AccessData{} conds := store.NewConds() conds.Add("refresh_token", token) err = srv.One(conds, e) if err != nil { return } else if e == nil { err = store.Error(http.StatusNotFound, "AccessData not found for the refresh token") return } // load supplementary data if err = storage.loadAccessSupp(e); err != nil { return } d = e.ToOsin() return }
func TestSetGet(t *testing.T) { type tempKey int const ( srcKey tempKey = iota key ) randString := func(n int) string { var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") b := make([]rune, n) for i := range b { b[i] = letterRunes[rand.Intn(len(letterRunes))] } return string(b) } msg := randString(20) ch := make(chan int) // prepare the context ctx := func(msg interface{}, ch chan<- int) context.Context { dummySrc := func() (conn store.Conn, err error) { conn = tConn{msg, ch} return } factory := store.NewFactory() factory.SetSource(srcKey, store.SourceFunc(dummySrc)) factory.Set(key, srcKey, func(sess interface{}) (s store.Store, err error) { err = fmt.Errorf("%s", sess) return }) return store.WithFactory(context.Background(), factory) }(msg, ch) // get a store if _, err := store.Get(ctx, key); err == nil { t.Error("unexpected nil error") } else if want, have := msg, err.Error(); want != have { t.Errorf("expected %#v, got %#v", want, have) } // test if store would close before timeout d, _ := time.ParseDuration("1s") timeout := time.After(d) store.CloseAllIn(ctx) select { case <-timeout: t.Error("tConn not closed before timeout") case <-ch: t.Log("tConn closed") } }
// GetClient implements osin.Storage.GetClient func (storage *Storage) GetClient(id string) (c osin.Client, err error) { // TODO: use logger := log.NewContext(,sg) logger, errLogger := msg, errMsg logger.Log( "method", "GetClient", "id", id) srv, err := store.Get(storage.ctx, KeyClient) if err != nil { serr := store.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) serr.TellServer("unable to get client store: %s", err) err = serr return } defer srv.Close() e := &Client{} conds := store.NewConds() conds.Add("id", id) err = srv.One(conds, e) if err != nil { serr := store.ExpandError(err) errLogger.Log( "method", "GetClient", "id", id, "cond", conds, "message", "Failed running One()", "error", serr.ServerMsg) return } else if e == nil { errLogger.Log( "method", "GetClient", "id", id, "cond", fmt.Sprintf("%#v", conds), "message", "Client not found") err = store.Error(http.StatusNotFound, "Client not found for the given id") return } c = e return }
// loadAccessSupp loads supplementary data onto an *AccessData func (storage *Storage) loadAccessSupp(e *AccessData) (err error) { // load client here var ok bool cli, err := storage.GetClient(e.ClientID) if err != nil { return } else if e.Client, ok = cli.(*Client); !ok { serr := store.Error(http.StatusInternalServerError, "Internal Server Error") serr.TellServer("Unable to cast client into Client type: %#v", cli) err = serr return } e.ClientID = e.Client.GetId() // unserialize previous AuthorizeData here if e.AuthorizeDataJSON != "" { ad := &AuthorizeData{} json.Unmarshal([]byte(e.AuthorizeDataJSON), ad) e.AuthorizeData = ad } // unserialize previous AccessData here if e.AccessDataJSON != "" { ad := &AccessData{} json.Unmarshal([]byte(e.AccessDataJSON), ad) e.AccessData = ad } // load user data here if e.UserID != "" { userStore, err := store.Get(storage.ctx, KeyUser) if err != nil { return err } user := &User{} userStore.One(store.NewConds().Add("id", e.UserID), user) e.UserData = user } return }
// RemoveRefresh revokes or deletes refresh AccessData. func (storage *Storage) RemoveRefresh(token string) (err error) { // TODO: use logger := log.NewContext(,sg) logger := msg logger.Log( "method", "RemoveRefresh", "token", token) srv, err := store.Get(storage.ctx, KeyAccess) if err != nil { return } defer srv.Close() conds := store.NewConds() conds.Add("refresh_token", token) err = srv.Delete(conds) return }
// RemoveAuthorize revokes or deletes the authorization code. func (storage *Storage) RemoveAuthorize(code string) (err error) { // TODO: use logger := log.NewContext(,sg) logger := msg logger.Log( "method", "RemoveAuthorize", "code", code) srv, err := store.Get(storage.ctx, KeyAuth) if err != nil { return } defer srv.Close() conds := store.NewConds() conds.Add("code", code) err = srv.Delete(conds) return }
// GetEndpoints generate endpoints http handers and return func (m *Manager) GetEndpoints(factory store.Factory) *Endpoints { // try to login with given request login tryLogin := func(ctx context.Context, r *http.Request) (user OAuth2User, err error) { logger := msg logger.Log( "func", "tryLogin (Manager.GetEndpoints)") // parse POST input r.ParseForm() if r.Method == "POST" { var u OAuth2User var us store.Store // get and check password non-empty password := r.Form.Get("password") if password == "" { err = errors.New("empty password") return } // obtain user store us, err = store.Get(ctx, KeyUser) if err != nil { err = store.Error( http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)). TellServer("error obtaining user store: %s", err.Error()) return } // get user by userFunc u, err = m.userFunc(r, us) if err != nil { serr := store.ExpandError(err) if serr.Status == http.StatusNotFound { err = store.Error(http.StatusBadRequest, "user id or password incorrect"). TellServer("user not found") } else { err = store.Error( http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)). TellServer("error obtaining user: %s", serr.ServerMsg) } return } // if user is nil, user not found if u == nil { err = store.Error(http.StatusBadRequest, "user not found") return } // if password does not match if !u.PasswordIs(password) { err = store.Error(http.StatusBadRequest, "user id or password incorrect"). TellServer("incorrect password") return } // return pointer of user object, allow it to be re-cast logger.Log( "func", "tryLogin (Manager.GetEndpoints)", "message", "login success") user = u return } // no POST input or incorrect login, show form // end login handling sequence and wait for // user input from login form err = store.Error(http.StatusUnauthorized, "Require login"). TellServer("no POST input") return } type ContextHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request) *osin.Response // sessionContext takes a ContextHandlerFunc and returns // a http.HandlerFunc sessionContext := func(inner ContextHandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // per connection based context.Context, with factory ctx := store.WithFactory(context.Background(), factory) defer store.CloseAllIn(ctx) if resp := inner(ctx, w, r); resp != nil { if resp.InternalError != nil { errLogger := errMsg errLogger.Log( "func", "sessionContext (Manager.GetEndpoints)", "error", resp.InternalError.Error()) } osin.OutputJSON(resp, w, r) } } } ep := Endpoints{} // authorize endpoint ep.Auth = sessionContext(func(ctx context.Context, w http.ResponseWriter, r *http.Request) *osin.Response { logger := msg logger.Log( "endpoint", "auth") srvr := m.osinServer resp := srvr.NewResponse() resp.Storage.(*Storage).SetContext(ctx) // handle authorize request with osin if ar := srvr.HandleAuthorizeRequest(resp, r); ar != nil { logger.Log( "endpoint", "auth", "message", "handle authorize request") // TODO: maybe redirect to another URL for // dedicated login form flow? var err error if ar.UserData, err = tryLogin(ctx, r); err != nil { serr := store.ExpandError(err) logger.Log( "endpoint", "auth", "message", "handle authorize request", "error", serr.ServerMsg) lctx := &LoginFormContext{ Context: withOsinAuthRequest(ctx, ar), LoginErr: err, ResponseWriter: w, Request: r, Logger: logger, } m.showLoginForm(lctx, w, r) return nil } logger.Log( "endpoint", "auth", "message", "User obtained", "osin.AuthorizeData.UserData", fmt.Sprintf("%#v", ar.UserData)) ar.Authorized = true srvr.FinishAuthorizeRequest(resp, r, ar) } logger.Log( "endpoint", "auth", "message", "User obtained", "response", fmt.Sprintf("%#v", resp)) return resp }) // token endpoint ep.Token = sessionContext(func(ctx context.Context, w http.ResponseWriter, r *http.Request) *osin.Response { logger := msg logger.Log( "endpoint", "token") srvr := m.osinServer resp := srvr.NewResponse() resp.Storage.(*Storage).SetContext(ctx) if ar := srvr.HandleAccessRequest(resp, r); ar != nil { // TODO: handle authorization // check if the user has the permission to grant the scope logger.Log( "endpoint", "token", "message", "access successful") ar.Authorized = true srvr.FinishAccessRequest(resp, r, ar) } logger.Log( "endpoint", "token", "response", fmt.Sprintf("%#v", resp)) return resp }) // information endpoint ep.Info = sessionContext(func(ctx context.Context, w http.ResponseWriter, r *http.Request) *osin.Response { logger := msg logger.Log( "endpoint", "information") srvr := m.osinServer resp := srvr.NewResponse() resp.Storage.(*Storage).SetContext(ctx) defer resp.Close() if ir := srvr.HandleInfoRequest(resp, r); ir != nil { srvr.FinishInfoRequest(resp, r, ir) } logger.Log( "endpoint", "information", "response", fmt.Sprintf("%#v", resp)) return resp }) return &ep }
// SaveAccess writes AccessData. // If RefreshToken is not blank, it must save in a way that can be loaded using LoadRefresh. func (storage *Storage) SaveAccess(ad *osin.AccessData) (err error) { // TODO: use logger := log.NewContext(,sg) logger, errLogger := msg, errMsg logger.Log( "method", "SaveAccess", "*osin.AccessData", ad) srv, err := store.Get(storage.ctx, KeyAccess) if err != nil { return } defer srv.Close() // generate database access type e := &AccessData{} err = e.ReadOsin(ad) if err != nil { return } // store client id with access in database e.ClientID = e.Client.GetId() // if AuthorizeData is set, store as JSON if ad.AuthorizeData != nil { var b []byte authData := &AuthorizeData{} if err = authData.ReadOsin(ad.AuthorizeData); err != nil { return } if b, err = json.Marshal(authData); err != nil { return } e.AuthorizeDataJSON = string(b) } // if AccessData is set, store as JSON if ad.AccessData != nil { var b []byte accessData := &AccessData{} if err = accessData.ReadOsin(ad.AccessData); err != nil { return } if accessData.AccessData != nil { // forget data of too long ago accessData.AccessData = nil } if b, err = json.Marshal(accessData); err != nil { return } e.AccessDataJSON = string(b) } // create in database if err = srv.Create(store.NewConds(), e); err != nil { serr := store.ExpandError(err) errLogger.Log( "method", "SaveAccess", "*osin.AccessData", ad, "err", serr.ServerMsg) } return }
// UserStoreEndpoints return CURD endpoints for UserStore func UserStoreEndpoints(noun, nounp string) (endpoints map[string]endpoint.Endpoint) { // variables to use later allocEntityList := func() *[]User { return &[]User{} } storeKey := KeyUser getStore := func(ctx context.Context) (s *UserStore, err error) { raw, err := store.Get(ctx, storeKey) if err != nil { return } s, ok := raw.(*UserStore) if !ok { err = fmt.Errorf("store.Get(\"UserStore\") does not return *UserStore") return } return } // store endpoints here // TODO: may have new struct to store endpoints = make(map[string]endpoint.Endpoint) endpoints["create"] = func(ctx context.Context, e interface{}) (res interface{}, err error) { // get context information r := gourdctx.HTTPRequest(ctx) if r == nil { serr := store.ErrorInternal serr.ServerMsg = "missing request in context" err = serr return } // get store s, err := getStore(ctx) if err != nil { serr := store.ErrorInternal serr.ServerMsg = fmt.Sprintf("error obtaining %s store (%s)", storeKey, err) err = serr return } defer s.Close() // create entity err = s.Create(nil, e) if err != nil { serr := store.ErrorInternal serr.ServerMsg = fmt.Sprintf( "error creating %s: %#v, entity: %#v", noun, err.Error(), e) err = serr return } // encode response res = map[string]interface{}{ nounp: &[]User{*e.(*User)}, } return } endpoints["retrieve"] = func(ctx context.Context, request interface{}) (res interface{}, err error) { sReq := request.(*httpservice.Request) q := sReq.Query // get context information r := gourdctx.HTTPRequest(ctx) if r == nil { serr := store.ErrorInternal serr.ServerMsg = "missing request in context" err = serr return } // get store s, err := getStore(ctx) if err != nil { serr := store.ErrorInternal serr.ServerMsg = fmt.Sprintf("error obtaining %s store (%s)", storeKey, err) err = serr return } defer s.Close() // allocate memory for variables el := allocEntityList() // retrieve err = s.Search(q).All(el) if err != nil { serr := store.ErrorInternal serr.ServerMsg = fmt.Sprintf("error searching %s: %s", noun, err) err = serr return } // encode response if s.Len(el) == 0 { err = store.ErrorNotFound return } res = map[string]interface{}{ nounp: el, } return } endpoints["list"] = func(ctx context.Context, request interface{}) (res interface{}, err error) { sReq := request.(*httpservice.Request) q := sReq.Query // get context information r := gourdctx.HTTPRequest(ctx) if r == nil { serr := store.ErrorInternal serr.ServerMsg = "missing request in context" err = serr return } // get store s, err := getStore(ctx) if err != nil { serr := store.ErrorInternal serr.ServerMsg = fmt.Sprintf("error obtaining %s store (%s)", storeKey, err) err = serr return } defer s.Close() // allocate memory for variables el := allocEntityList() results := s.Search(q) count, err := results.Count() if err != nil { serr := store.ErrorInternal serr.ServerMsg = fmt.Sprintf("error counting %s: %s", noun, err) err = serr return } err = results.All(el) if err != nil { serr := store.ErrorInternal serr.ServerMsg = fmt.Sprintf("error searching %s: %s", noun, err) err = serr return } // TODO: need to fix overflow error of pager variables res = map[string]interface{}{ nounp: el, "paging": store.NewPager(). SetTotal(int(count)). SetLimit(int(q.GetLimit()), int(q.GetOffset())), } return } endpoints["update"] = func(ctx context.Context, request interface{}) (res interface{}, err error) { sReq := request.(*httpservice.Request) q := sReq.Query e := sReq.Payload cond := q.GetConds() // get context information r := gourdctx.HTTPRequest(ctx) if r == nil { serr := store.ErrorInternal serr.ServerMsg = "missing request in context" err = serr return } // get store s, err := getStore(ctx) if err != nil { serr := store.ErrorInternal serr.ServerMsg = fmt.Sprintf("error obtaining %s store (%s)", storeKey, err) err = serr return } defer s.Close() // update entity if err = s.Update(cond, e); err != nil { serr := store.ErrorInternal serr.ServerMsg = fmt.Sprintf( "error encoding %s list: %s", noun, err) err = serr return } res = map[string]interface{}{ nounp: &[]User{*e.(*User)}, } return } endpoints["delete"] = func(ctx context.Context, request interface{}) (res interface{}, err error) { // allocate memory for variables el := allocEntityList() // store query of id sReq := request.(*httpservice.Request) q := sReq.Query cond := q.GetConds() // get context information r := gourdctx.HTTPRequest(ctx) if r == nil { serr := store.ErrorInternal serr.ServerMsg = "missing request in context" err = serr return } // get store s, err := getStore(ctx) if err != nil { serr := store.ErrorInternal serr.ServerMsg = fmt.Sprintf("error obtaining %s store (%s)", storeKey, err) err = serr return } defer s.Close() // find the content of the id err = s.Search(q).All(el) if err != nil { serr := store.ErrorInternal serr.ServerMsg = fmt.Sprintf("error searching %s: %s", noun, err) err = serr return } // delete entity if err = s.Delete(cond); err != nil { serr := store.ErrorInternal serr.ServerMsg = fmt.Sprintf( "error encoding %s list: %s", noun, err) err = serr return } res = map[string]interface{}{ nounp: el, } return } return }
func UserStoreServices(paths httpservice.Paths, endpoints map[string]endpoint.Endpoint) (handlers httpservice.Services) { // variables to use later noun := paths.Noun() storeKey := KeyUser getStore := func(ctx context.Context) (s *UserStore, err error) { raw, err := store.Get(ctx, storeKey) if err != nil { return } s, ok := raw.(*UserStore) if !ok { err = fmt.Errorf(`store.Get(KeyUser) does not return *KeyUser`) return } return } // define default middlewares var prepareCreate endpoint.Middleware = func(inner endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (respond interface{}, err error) { // placeholder: anything you want to do with the entity // before append to database httpservice.EnforceCreate(request) return inner(ctx, request) } } var prepareUpdate endpoint.Middleware = func(inner endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { sReq := request.(*httpservice.Request) // get context information r := gourdctx.HTTPRequest(ctx) if r == nil { serr := store.ErrorInternal serr.ServerMsg = "missing request in context" err = serr return } el := &[]User{} q := sReq.Query // get store s, err := getStore(ctx) if err != nil { serr := store.ErrorInternal serr.ServerMsg = fmt.Sprintf("error obtaining %s store (%s)", storeKey, err) err = serr return } defer s.Close() // find the previous content of the id err = s.Search(q).All(el) if err != nil { serr := store.ErrorInternal serr.ServerMsg = fmt.Sprintf("error searching %s: %s", noun.Singular(), err) err = serr return } // tell the inner if len(*el) > 0 { sReq.Previous = &(*el)[0] } // enforce agreement on sReq.Payload with previous sReq.Entity httpservice.EnforceUpdate(sReq.Previous, sReq.Payload) // placeholder: anything you want to do with the entity // before update to database return inner(ctx, sReq) } } var prepareList endpoint.Middleware = func(inner endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { response, err = inner(ctx, request) if err != nil { return } vmap := response.(map[string]interface{}) list := vmap[noun.Plural()].(*[]User) if list == nil || *list == nil { *list = make([]User, 0) } vmap[noun.Plural()] = list // placeholder: anything you want to do with the entity // list response return vmap, nil } } // wrap inner response with default protocol var prepareProtocol endpoint.Middleware = func(inner endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { v, err := inner(ctx, request) if err != nil { return } switch v.(type) { case map[string]interface{}: response = store.ExpandResponse(v.(map[string]interface{})) default: response = store.NewResponse(noun.Plural(), v) } return } } // generates response permission checker middleware checkPermBefore := func(permission string) endpoint.Middleware { return func(inner endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { m := perm.GetMux(ctx) err = m.Allow(ctx, permission, request) if err != nil { return } return inner(ctx, request) } } } // generates request permission checker middleware checkPermAfter := func(permission string) endpoint.Middleware { return func(inner endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { v, err := inner(ctx, request) if err != nil { return } m := perm.GetMux(ctx) err = m.Allow(ctx, permission, request, v) if err != nil { return } response = v return } } } // // ==== raw decode functions // decodeServiceIDReq := func(ctx context.Context, r *http.Request) (request *httpservice.Request, err error) { id := r.URL.Query().Get(":id") // will change cond := store.NewConds().Add("id", id) request = &httpservice.Request{ Request: r, Query: store.NewQuery().SetConds(cond), } return } decodeJSONEntity := func(ctx context.Context, r *http.Request) (entity *User, err error) { // allocate entity entity = &User{} // decode request dec := json.NewDecoder(r.Body) err = dec.Decode(entity) return } // // ==== httptransport.DecodeRequestFunc implementations // // decodeIDReq generically decoded :id field // (works with pat based URL routing, router specific) var decodeIDReq httptransport.DecodeRequestFunc = func(ctx context.Context, r *http.Request) (request interface{}, err error) { return decodeServiceIDReq(ctx, r) } // decodeListReq decode query for list endpoint var decodeListReq httptransport.DecodeRequestFunc = func(ctx context.Context, r *http.Request) (request interface{}, err error) { sReq := &httpservice.Request{ Request: r, Query: store.NewQuery(), } // parse sort parameter sortStr := r.FormValue("sorts") if sortStr != "" { sorts := strings.Split(sortStr, ",") for _, sort := range sorts { sReq.Query.Sort(sort) } } // parse paging request parameter offset, limit := func(r *http.Request) (o, l uint64) { ostr := r.FormValue("offset") lstr := r.FormValue("limit") if ostr != "" { if ot, err := strconv.ParseUint(ostr, 10, 64); err == nil { o = ot } } if lstr != "" { if lt, err := strconv.ParseUint(lstr, 10, 64); err == nil { l = lt } } return }(r) // retrieve sReq.Query.SetOffset(offset) sReq.Query.SetLimit(limit) request = sReq return } // decodeJSONReq returns a DecodeRequestFunc that decode request // into allocated memory structure var decodeJSONReq httptransport.DecodeRequestFunc = func(ctx context.Context, r *http.Request) (request interface{}, err error) { return decodeJSONEntity(ctx, r) } // decodeUpdate returns a DecodeRequestFunc that decode request var decodeUpdate httptransport.DecodeRequestFunc = func(ctx context.Context, r *http.Request) (request interface{}, err error) { sReq, err := decodeServiceIDReq(ctx, r) if err != nil { return } sReq.Payload, err = decodeJSONEntity(ctx, r) if err != nil { return } request = sReq return } // // ==== httpservce.Services // // define middleware chains of all RESTful endpoints handlers = make(map[string]*httpservice.Service) handlers["create"] = httpservice.NewJSONService( paths.Plural(), endpoints["create"]) handlers["create"].Weight = 1 handlers["create"].Methods = []string{"POST"} handlers["create"].DecodeFunc = decodeJSONReq handlers["create"].Middlewares.Add(httpservice.MWProtocol, prepareProtocol) handlers["create"].Middlewares.Add(httpservice.MWPrepare, prepareCreate) handlers["create"].Middlewares.Add(httpservice.MWInner, checkPermBefore("create "+noun.Singular())) handlers["retrieve"] = httpservice.NewJSONService( paths.Singular(), endpoints["retrieve"]) handlers["retrieve"].Methods = []string{"GET"} handlers["retrieve"].DecodeFunc = decodeIDReq handlers["retrieve"].Middlewares.Add(httpservice.MWProtocol, prepareProtocol) handlers["retrieve"].Middlewares.Add(httpservice.MWPrepare, prepareList) handlers["retrieve"].Middlewares.Add(httpservice.MWInner, checkPermAfter("retrieve "+noun.Singular())) handlers["update"] = httpservice.NewJSONService( paths.Singular(), endpoints["update"]) handlers["update"].Methods = []string{"PUT"} handlers["update"].DecodeFunc = decodeUpdate handlers["update"].Middlewares.Add(httpservice.MWProtocol, prepareProtocol) handlers["update"].Middlewares.Add(httpservice.MWPrepare, prepareUpdate) handlers["update"].Middlewares.Add(httpservice.MWInner, checkPermBefore("update "+noun.Singular())) handlers["list"] = httpservice.NewJSONService( paths.Plural(), endpoints["list"]) handlers["list"].Weight = 1 handlers["list"].Methods = []string{"GET"} handlers["list"].DecodeFunc = decodeListReq handlers["list"].Middlewares.Add(httpservice.MWProtocol, prepareProtocol) handlers["list"].Middlewares.Add(httpservice.MWPrepare, prepareList) handlers["list"].Middlewares.Add(httpservice.MWInner, checkPermAfter("list "+noun.Singular())) handlers["delete"] = httpservice.NewJSONService( paths.Singular(), endpoints["delete"]) handlers["delete"].Methods = []string{"DELETE"} handlers["delete"].DecodeFunc = decodeIDReq handlers["delete"].Middlewares.Add(httpservice.MWProtocol, prepareProtocol) handlers["delete"].Middlewares.Add(httpservice.MWInner, checkPermBefore("delete "+noun.Singular())) return }