/// <summary> /// Initiates the RESTar interface /// </summary> /// <param name="port">The port that RESTar should listen on</param> /// <param name="uri">The URI that RESTar should listen on. E.g. '/rest'</param> /// <param name="configFilePath">The path to the config file containing API keys and /// allowed origins</param> /// <param name="prettyPrint">Should JSON output be pretty print formatted as default? /// (can be changed in settings during runtime)</param> /// <param name="daysToSaveErrors">The number of days to save errors in the Error resource</param> /// <param name="requireApiKey">Should the REST API require an API key?</param> /// <param name="allowAllOrigins">Should any origin be allowed to make CORS requests?</param> /// <param name="lineEndings">The line endings to use when writing JSON</param> /// <param name="entityResourceProviders">External entity resource providers for the RESTar instance</param> /// <param name="protocolProviders">External protocol providers for the RESTar instance</param> /// <param name="contentTypeProviders">External content type providers for the RESTar instance</param> public static void Init ( ushort port = 8282, string uri = "/rest", bool requireApiKey = false, bool allowAllOrigins = true, string configFilePath = null, bool prettyPrint = true, ushort daysToSaveErrors = 30, LineEndings lineEndings = LineEndings.Windows, IEnumerable <IEntityResourceProvider> entityResourceProviders = null, IEnumerable <IProtocolProvider> protocolProviders = null, IEnumerable <IContentTypeProvider> contentTypeProviders = null ) { try { ProcessUri(ref uri); Settings.Init(port, uri, false, prettyPrint, daysToSaveErrors, lineEndings); Log.Init(); DynamitConfig.Init(true, true); ResourceFactory.MakeResources(entityResourceProviders?.ToArray()); ContentTypeController.SetupContentTypeProviders(contentTypeProviders?.ToList()); ProtocolController.SetupProtocolProviders(protocolProviders?.ToList()); RequireApiKey = requireApiKey; AllowAllOrigins = allowAllOrigins; ConfigFilePath = configFilePath; NetworkController.AddNetworkBindings(new ScNetworkProvider()); Initialized = true; UpdateConfiguration(); DatabaseIndex.Init(); DbOutputFormat.Init(); ResourceFactory.BindControllers(); ResourceFactory.FinalCheck(); ProtocolController.OnInit(); Webhook.Check(); WebhookLogSettings.Init(); RegisterStaticIndexes(); RunCustomMigrationLogic(); } catch { Initialized = false; RequireApiKey = default; AllowAllOrigins = default; ConfigFilePath = default; NetworkController.RemoveNetworkBindings(); Settings.Clear(); NewState(); throw; } }
internal static MetaConditions Parse(IReadOnlyCollection <IUriCondition> uriMetaConditions, IEntityResource resource) { if (!uriMetaConditions.Any()) { return(null); } var renames = uriMetaConditions.Where(c => c.Key.EqualsNoCase("rename")); var regular = uriMetaConditions.Where(c => !c.Key.EqualsNoCase("rename")); var mc = new MetaConditions { Empty = false }; ICollection <string> dynamicDomain = default; void make(IEnumerable <IUriCondition> conds) => conds.ForEach(cond => { var(key, op, valueLiteral) = (cond.Key, cond.Operator, cond.ValueLiteral); if (op != EQUALS) { throw new InvalidSyntax(InvalidMetaConditionOperator, "Invalid operator for meta-condition. One and only one '=' is allowed"); } if (!Enum.TryParse(key, true, out RESTarMetaCondition metaCondition)) { throw new InvalidSyntax(InvalidMetaConditionKey, $"Invalid meta-condition '{key}'. Available meta-conditions: {AllMetaConditions}"); } var expectedType = metaCondition.GetExpectedType(); switch (valueLiteral) { case null: case "null": case "": return; case "∞": valueLiteral = int.MaxValue.ToString(); break; case "-∞": valueLiteral = int.MinValue.ToString(); break; } var(first, length) = (valueLiteral.FirstOrDefault(), valueLiteral.Length); switch (first) { case '\'': case '\"': if (length > 1 && valueLiteral[length - 1] == first) { valueLiteral = valueLiteral.Substring(1, length - 2); } break; } dynamic value; try { value = Convert.ChangeType(valueLiteral, expectedType) ?? throw new Exception(); } catch { throw new InvalidSyntax(InvalidMetaConditionValueType, $"Invalid data type assigned to meta-condition '{key}'. Expected {GetTypeString(expectedType)}."); } switch (metaCondition) { case RESTarMetaCondition.Unsafe: mc.Unsafe = value; break; case RESTarMetaCondition.Limit: mc.Limit = (Limit)(int)value; break; case RESTarMetaCondition.Offset: mc.Offset = (Offset)(int)value; break; case RESTarMetaCondition.Order_asc: mc.OrderBy = new OrderByAscending(resource, (string)value, dynamicDomain); break; case RESTarMetaCondition.Order_desc: mc.OrderBy = new OrderByDescending(resource, (string)value, dynamicDomain); break; case RESTarMetaCondition.Select: mc.Select = new Select(resource, (string)value, dynamicDomain); break; case RESTarMetaCondition.Add: mc.Add = new Add(resource, (string)value, dynamicDomain); break; case RESTarMetaCondition.Rename: mc.Rename = new Rename(resource, (string)value, out dynamicDomain); break; case RESTarMetaCondition.Distinct: if ((bool)value) { mc.Distinct = new Distinct(); } break; case RESTarMetaCondition.Search: mc.Search = new Search((string)value); break; case RESTarMetaCondition.Search_regex: mc.Search = new RegexSearch((string)value); break; case RESTarMetaCondition.Safepost: mc.SafePost = value; break; case RESTarMetaCondition.Format: var formatName = (string)value; var format = DbOutputFormat.GetByName(formatName) ?? throw new InvalidSyntax(UnknownFormatter, $"Could not find any output format by '{formatName}'. See RESTar.Admin.OutputFormat " + "for available output formats"); mc.Formatter = format.Format; break; default: throw new ArgumentOutOfRangeException(); } }); make(renames); make(regular); mc.Processors = new IProcessor[] { mc.Add, mc.Rename, mc.Select }.Where(p => p != null).ToArray(); mc.HasProcessors = mc.Processors.Any(); mc.CanUseExternalCounter = mc.Search == null && mc.Distinct == null && mc.Limit.Number == -1 && mc.Offset.Number == 0; if (mc.OrderBy != null) { if (mc.Rename?.Any(p => p.Key.Key.EqualsNoCase(mc.OrderBy.Key)) == true && !mc.Rename.Any(p => p.Value.EqualsNoCase(mc.OrderBy.Key))) { throw new InvalidSyntax(InvalidMetaConditionSyntax, $"The {(mc.OrderBy is OrderByAscending ? RESTarMetaCondition.Order_asc : RESTarMetaCondition.Order_desc)} " + "meta-condition cannot refer to a property x that is to be renamed " + "unless some other property is renamed to x"); } } if (mc.Select != null && mc.Rename != null) { if (mc.Select.Any(pc => mc.Rename.Any(p => p.Key.Key.EqualsNoCase(pc.Key)) && !mc.Rename.Any(p => p.Value.EqualsNoCase(pc.Key)))) { throw new InvalidSyntax(InvalidMetaConditionSyntax, "A 'Select' meta-condition cannot refer to a property x that is " + "to be renamed unless some other property is renamed to x. Use the " + "new property name instead."); } } return(mc); }