func (res *resource) handleCreate(c APIContexter, w http.ResponseWriter, r *http.Request, prefix string, info information) error { ctx, err := unmarshalRequest(r, res.marshalers) if err != nil { return err } newObjs := reflect.MakeSlice(reflect.SliceOf(res.resourceType), 0, 0) structType := res.resourceType if structType.Kind() == reflect.Ptr { structType = structType.Elem() } err = jsonapi.UnmarshalInto(ctx, structType, &newObjs) if err != nil { return err } if newObjs.Len() != 1 { return errors.New("expected one object in POST") } //TODO create multiple objects not only one. newObj := newObjs.Index(0).Interface() response, err := res.source.Create(newObj, buildRequest(c, r)) if err != nil { return err } result, ok := response.Result().(jsonapi.MarshalIdentifier) if !ok { return fmt.Errorf("Expected one newly created object by resource %s", res.name) } w.Header().Set("Location", "/"+prefix+"/"+res.name+"/"+result.GetID()) // handle 200 status codes switch response.StatusCode() { case http.StatusCreated: return respondWith(response, info, http.StatusCreated, w, r, res.marshalers) case http.StatusNoContent: w.WriteHeader(response.StatusCode()) return nil case http.StatusAccepted: w.WriteHeader(response.StatusCode()) return nil default: return fmt.Errorf("invalid status code %d from resource %s for method Create", response.StatusCode(), res.name) } }
func (res *resource) handleCreate(w http.ResponseWriter, r *http.Request, prefix string, info information) error { ctx, err := unmarshalRequest(r, res.marshalers) if err != nil { return err } newObjs := reflect.MakeSlice(reflect.SliceOf(res.resourceType), 0, 0) structType := res.resourceType if structType.Kind() == reflect.Ptr { structType = structType.Elem() } err = jsonapi.UnmarshalInto(ctx, structType, &newObjs) if err != nil { return err } if newObjs.Len() != 1 { return errors.New("expected one object in POST") } //TODO create multiple objects not only one. newObj := newObjs.Index(0).Interface() checkID, ok := newObj.(jsonapi.MarshalIdentifier) if ok { if checkID.GetID() != "" { err := Error{ Status: string(http.StatusForbidden), Title: "Forbidden", Detail: "Client generated IDs are not supported.", } return respondWith(err, info, http.StatusForbidden, w, r, res.marshalers) } } id, err := res.source.Create(newObj, buildRequest(r)) if err != nil { return err } w.Header().Set("Location", prefix+res.name+"/"+id) obj, err := res.source.FindOne(id, buildRequest(r)) if err != nil { return err } return respondWith(obj, info, http.StatusCreated, w, r, res.marshalers) }
func (res *resource) handleCreate(w http.ResponseWriter, r *http.Request, prefix string, info information) error { ctx, err := unmarshalRequest(r, res.marshalers) if err != nil { return err } newObjs := reflect.MakeSlice(reflect.SliceOf(res.resourceType), 0, 0) structType := res.resourceType if structType.Kind() == reflect.Ptr { structType = structType.Elem() } err = jsonapi.UnmarshalInto(ctx, structType, &newObjs) if err != nil { return err } if newObjs.Len() != 1 { return errors.New("expected one object in POST") } //TODO create multiple objects not only one. newObj := newObjs.Index(0).Interface() id, err := res.source.Create(newObj, buildRequest(r)) if err != nil { return err } w.Header().Set("Location", prefix+res.name+"/"+id) obj, err := res.source.FindOne(id, buildRequest(r)) if err != nil { return err } return respondWith(obj, info, http.StatusCreated, w, r, res.marshalers) }
func (res *resource) handleUpdate(c APIContexter, w http.ResponseWriter, r *http.Request, params map[string]string) error { id := params["id"] obj, err := res.source.FindOne(id, buildRequest(c, r)) if err != nil { return err } ctx, err := unmarshalRequest(r, res.marshalers) if err != nil { return err } data, ok := ctx["data"] if !ok { return NewHTTPError( errors.New("Forbidden"), "missing mandatory data key.", http.StatusForbidden, ) } check, ok := data.(map[string]interface{}) if !ok { return NewHTTPError( errors.New("Forbidden"), "data must contain an object.", http.StatusForbidden, ) } if _, ok := check["id"]; !ok { return NewHTTPError( errors.New("Forbidden"), "missing mandatory id key.", http.StatusForbidden, ) } if _, ok := check["type"]; !ok { return NewHTTPError( errors.New("Forbidden"), "missing mandatory type key.", http.StatusForbidden, ) } updatingObjs := reflect.MakeSlice(reflect.SliceOf(res.resourceType), 1, 1) updatingObjs.Index(0).Set(reflect.ValueOf(obj.Result())) structType := res.resourceType if structType.Kind() == reflect.Ptr { structType = structType.Elem() } err = jsonapi.UnmarshalInto(ctx, structType, &updatingObjs) if err != nil { return err } if updatingObjs.Len() != 1 { return errors.New("expected one object") } updatingObj := updatingObjs.Index(0).Interface() response, err := res.source.Update(updatingObj, buildRequest(c, r)) if err != nil { return err } switch response.StatusCode() { case http.StatusOK: updated := response.Result() if updated == nil { internalResponse, err := res.source.FindOne(id, buildRequest(c, r)) if err != nil { return err } updated = internalResponse.Result() if updated == nil { return fmt.Errorf("Expected FindOne to return one object of resource %s", res.name) } response = internalResponse } return respondWith(response, information{}, http.StatusOK, w, r, res.marshalers) case http.StatusAccepted: w.WriteHeader(http.StatusAccepted) return nil case http.StatusNoContent: w.WriteHeader(http.StatusNoContent) return nil default: return fmt.Errorf("invalid status code %d from resource %s for method Update", response.StatusCode(), res.name) } }
func (res *resource) handleUpdate(w http.ResponseWriter, r *http.Request, ps httprouter.Params) error { obj, err := res.source.FindOne(ps.ByName("id"), buildRequest(r)) if err != nil { return err } ctx, err := unmarshalRequest(r, res.marshalers) if err != nil { return err } data, ok := ctx["data"] if !ok { return NewHTTPError( errors.New("Forbidden"), "missing mandatory data key.", http.StatusForbidden, ) } check, ok := data.(map[string]interface{}) if !ok { return NewHTTPError( errors.New("Forbidden"), "data must contain an object.", http.StatusForbidden, ) } if _, ok := check["id"]; !ok { return NewHTTPError( errors.New("Forbidden"), "missing mandatory id key.", http.StatusForbidden, ) } if _, ok := check["type"]; !ok { return NewHTTPError( errors.New("Forbidden"), "missing mandatory type key.", http.StatusForbidden, ) } updatingObjs := reflect.MakeSlice(reflect.SliceOf(res.resourceType), 1, 1) updatingObjs.Index(0).Set(reflect.ValueOf(obj)) structType := res.resourceType if structType.Kind() == reflect.Ptr { structType = structType.Elem() } err = jsonapi.UnmarshalInto(ctx, structType, &updatingObjs) if err != nil { return err } if updatingObjs.Len() != 1 { return errors.New("expected one object") } updatingObj := updatingObjs.Index(0).Interface() if err := res.source.Update(updatingObj, buildRequest(r)); err != nil { return err } w.WriteHeader(http.StatusNoContent) return nil }
func (res *resource) handleUpdate(r Request) response { obj, err := res.source.FindOne(r.Params.ByName("id"), r) if err != nil { log.Printf("ERROR!: %v\n", err) return response{Error: err} } ctx := r.Data data, ok := ctx["data"] if !ok { return response{ Error: NewHTTPError(errors.New("missing_data_key"), "missing mandatory data key.", http.StatusForbidden), } } check, ok := data.(map[string]interface{}) if !ok { return response{ Error: NewHTTPError(errors.New("invalid_data"), "data must contain an object.", http.StatusForbidden), } } if _, ok := check["id"]; !ok { return response{ Error: NewHTTPError(errors.New("missing_id_key"), "missing mandatory id key.", http.StatusForbidden), } } if _, ok := check["type"]; !ok { return response{ Error: NewHTTPError(errors.New("missing_type_key"), "missing mandatory type key.", http.StatusForbidden), } } updatingObjs := reflect.MakeSlice(reflect.SliceOf(res.resourceType), 1, 1) updatingObjs.Index(0).Set(reflect.ValueOf(obj.Result())) structType := res.resourceType if structType.Kind() == reflect.Ptr { structType = structType.Elem() } err = jsonapi.UnmarshalInto(ctx, structType, &updatingObjs) if err != nil { log.Printf("unmarshal failed: %v\n", err) return response{Error: err} } if updatingObjs.Len() != 1 { return response{Error: errors.New("expected one object")} } updatingObj := updatingObjs.Index(0).Interface() resp, err := res.source.Update(updatingObj, r) if err != nil { return response{Error: err} } switch resp.StatusCode() { case http.StatusOK: updated := resp.Result() if updated == nil { internalResponse, err := res.source.FindOne(r.Params.ByName("id"), r) if err != nil { return response{Error: err} } updated = internalResponse.Result() if updated == nil { return response{ Error: fmt.Errorf("Expected FindOne to return one object of resource %s", res.name), } } resp = internalResponse } return res.buildResponse(response{Data: updated}, nil, http.StatusOK) case http.StatusAccepted: return response{ Status: http.StatusAccepted, } case http.StatusNoContent: return response{ Status: http.StatusNoContent, } default: err := NewHTTPError(errors.New("invalid_status_code"), fmt.Sprintf("invalid status code %d from resource %s for method Update", resp.StatusCode(), res.name), http.StatusInternalServerError) return response{ Error: err, } } }
func (res *resource) handleCreate(r Request) response { ctx := r.Data newObjs := reflect.MakeSlice(reflect.SliceOf(res.resourceType), 0, 0) structType := res.resourceType if structType.Kind() == reflect.Ptr { structType = structType.Elem() } err := jsonapi.UnmarshalInto(ctx, structType, &newObjs) if err != nil { return response{Error: err} } if newObjs.Len() != 1 { return response{Error: errors.New("expected one object in POST")} } //TODO create multiple objects not only one. newObj := newObjs.Index(0).Interface() resp, err := res.source.Create(newObj, r) if err != nil { return response{Error: err} } result, ok := resp.Result().(jsonapi.MarshalIdentifier) if !ok { return response{ Error: fmt.Errorf("Expected one newly created object by resource %s", res.name), } } // TODO: ADD HEADER! //w.Header().Set("Location", prefix+res.name+"/"+result.GetID()) header := http.Header{ "Location": []string{res.api.prefix + res.name + "/" + result.GetID()}, } // handle 200 status codes switch resp.StatusCode() { case http.StatusCreated: r := res.buildResponse(response{ Data: result, }, nil, http.StatusCreated) r.Header = header return r case http.StatusNoContent: return response{ Status: resp.StatusCode(), Header: header, } case http.StatusAccepted: return response{ Status: resp.StatusCode(), Header: header, } default: err := NewHTTPError(errors.New("invalid_status_code"), fmt.Sprintf("invalid status code %d from resource %s for method Create", resp.StatusCode(), res.name), 500) return response{ Error: err, } } }