private static ExpressApplication RestImpl(this ExpressApplication app, string url, Type type, Func <int> nextIndex, Func <RequestContext, object> getInstance, Func <RequestContext, object> getModel) { app.Get(url, req => req.Json(getInstance(req))); var props = type .GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => FilterProperty(p)) .ToList(); props.ForEach(prop => { var propertyUrl = Combine(url, prop.Name); var getter = DynamicMethods.CompileGetter(type, prop); var setter = DynamicMethods.CompileSetter(type, prop); Func <RequestContext, object> propertyInstance = req => { var instance = getInstance(req); return(getter(instance)); }; app.Get(propertyUrl, req => req.Json(propertyInstance(req))); if (setter != null) { app.Update(propertyUrl, req => { req.SetContext(); var json = req.ParseJson(); var hasChanges = ChangesDetector(req, getModel); var instance = getInstance(req); // TODO get default value from metadata var defval = GetDefaultValue(prop.PropertyType); var value = json.Get("value", defval, prop.PropertyType); setter(instance, value); req.Json(hasChanges() ? ModelPayload(req, getModel) : null); }); } if (IsCollection(prop.PropertyType)) { RestCollection(app, propertyUrl, prop.PropertyType, nextIndex, propertyInstance, getModel); } else if (IsObject(prop.PropertyType)) { RestImpl(app, propertyUrl, prop.PropertyType, nextIndex, propertyInstance, getModel); } }); var methods = type .GetMethods(BindingFlags.Public | BindingFlags.Instance) .Where(m => m.GetAttribute <RestAttribute>(true) != null) .ToList(); methods.ForEach(method => { var call = DynamicMethods.CompileMethod(type, method); app.Post(url, req => { req.SetContext(); var hasChanges = ChangesDetector(req, getModel); var args = req.ParseArgs(method.GetParameters()); var collection = getInstance(req); var result = call(collection, args); req.Json(hasChanges() ? ModelPayload(req, getModel) : result); }); }); return(app); }
private static void RestCollection(this ExpressApplication app, string url, Type type, Func <int> nextIndex, Func <RequestContext, object> getInstance, Func <RequestContext, object> getModel) { var indexer = DynamicMethods.CompileIndexer(type); var indexName = "i" + nextIndex(); var indexUrl = Combine(url, string.Format("{{{0}}}", indexName)); Func <RequestContext, object> getItem = req => { var index = req.Param <int>(indexName); var collection = getInstance(req); return(indexer(collection, index)); }; if (indexer != null) { app.Get(indexUrl, req => req.Json(getItem(req))); } // TODO dispatch multiple Add methods var addMethod = type.GetMethod("Add"); if (addMethod != null) { var add = DynamicMethods.CompileMethod(type, addMethod); app.Put(url, req => { req.SetContext(); var hasChanges = ChangesDetector(req, getModel); var args = req.ParseArgs(addMethod.GetParameters()); var collection = getInstance(req); var result = add(collection, args); req.Json(hasChanges() ? ModelPayload(req, getModel) : result); }); } var remove = DynamicMethods.CompileRemoveAt(type); if (remove != null) { app.Delete(indexUrl, req => { req.SetContext(); var hasChanges = ChangesDetector(req, getModel); var index = req.Param <int>(indexName); var collection = getInstance(req); var result = remove(collection, index); req.Json(hasChanges() ? ModelPayload(req, getModel) : result); }); } var countProperty = type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public); if (countProperty != null && countProperty.GetIndexParameters().Length == 0) { var count = DynamicMethods.CompileGetter(type, countProperty); app.Get(Combine(url, "Count"), req => { var collection = getInstance(req); req.Json(count(collection)); }); } var itemType = GetItemType(type); if (IsObject(itemType)) { RestImpl(app, indexUrl, itemType, nextIndex, getItem, getModel); } }