{"id":63,"date":"2024-05-23T23:41:41","date_gmt":"2024-05-23T23:41:41","guid":{"rendered":"https:\/\/mystifying-liskov.77-68-127-141.plesk.page\/?p=63"},"modified":"2024-05-23T23:41:41","modified_gmt":"2024-05-23T23:41:41","slug":"restapi-cs","status":"publish","type":"post","link":"https:\/\/mystifying-liskov.77-68-127-141.plesk.page\/?p=63","title":{"rendered":"RestAPI.cs"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code>using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Reflection;\nusing System.Runtime.Serialization;\nusing System.Runtime.Serialization.Json;\nusing System.Text;\nusing System.Threading.Tasks;\nusing WooCommerceNET.Base;<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>namespace WooCommerceNET\n{\n    public class RestAPI\n    {\n        protected string wc_url = string.Empty;\n        protected string wc_key = \"ck_fef6065e15729d76e176fe75fdada8a448f70aa5\";\n        protected string wc_secret = \"cs_d9fe6eb1d265a018ae69a22c71a362ac8c3b8045\";\n        \/\/private bool wc_Proxy = false;<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>protected bool AuthorizedHeader { get; set; }\n\nprotected Func&lt;string, string&gt; jsonSeFilter;\nprotected Func&lt;string, string&gt; jsonDeseFilter;\nprotected Action&lt;HttpWebRequest&gt; webRequestFilter;\nprotected Action&lt;HttpWebResponse&gt; webResponseFilter;\n\n\/\/\/ &lt;summary&gt;\n\/\/\/ For WordPress REST API with OAuth 1.0 ONLY\n\/\/\/ &lt;\/summary&gt;\npublic string oauth_token { get; set; }\n\n\/\/\/ &lt;summary&gt;\n\/\/\/ For WordPress REST API with OAuth 1.0 ONLY\n\/\/\/ &lt;\/summary&gt;\npublic string oauth_token_secret { get; set; }\n\npublic WP_JWT_Object JWT_Object { get; set; }\n\n\/\/\/ &lt;summary&gt;\n\/\/\/ Authenticate Woocommerce API with JWT when set to True\n\/\/\/ &lt;\/summary&gt;\npublic bool WCAuthWithJWT { get; set; }\n\n\/\/\/ &lt;summary&gt;\n\/\/\/ Provide a function to modify the json string before deserilizing, this is for JWT Token ONLY!\n\/\/\/ &lt;\/summary&gt;\npublic Func&lt;string, string&gt; JWTDeserializeFilter { get; set; }\n\n\/\/\/ &lt;summary&gt;\n\/\/\/ Provide a function to modify the HttpWebRequest object, this is for JWT Token ONLY!\n\/\/\/ &lt;\/summary&gt;\npublic Action&lt;HttpWebRequest&gt; JWTRequestFilter { get; set; }\n\n\/\/\/ &lt;summary&gt;\n\/\/\/ If running in Debug mode, default is False.\n\/\/\/ NOTE: Beware when setting Debug to True, as exceptions might contain sensetive information.\n\/\/\/ &lt;\/summary&gt;\npublic bool Debug { get; set; }\n\n\/\/\/ &lt;summary&gt;\n\/\/\/ Initialize the RestAPI object\n\/\/\/ &lt;\/summary&gt;\n\/\/\/ &lt;param name=\"url\"&gt;\n\/\/\/ WooCommerce REST API URL, e.g.: http:\/\/yourstore\/wp-json\/wc\/v1\/ \n\/\/\/ WordPress REST API URL, e.g.: http:\/\/yourstore\/wp-json\/\n\/\/\/ &lt;\/param&gt;\n\/\/\/ &lt;param name=\"key\"&gt;WooCommerce REST API Key Or WordPress consumerKey&lt;\/param&gt;\n\/\/\/ &lt;param name=\"secret\"&gt;WooCommerce REST API Secret Or WordPress consumerSecret&lt;\/param&gt;\n\/\/\/ &lt;param name=\"authorizedHeader\"&gt;WHEN using HTTPS, do you prefer to send the Credentials in HTTP HEADER?&lt;\/param&gt;\n\/\/\/ &lt;param name=\"jsonSerializeFilter\"&gt;Provide a function to modify the json string after serilizing.&lt;\/param&gt;\n\/\/\/ &lt;param name=\"jsonDeserializeFilter\"&gt;Provide a function to modify the json string before deserilizing.&lt;\/param&gt;\n\/\/\/ &lt;param name=\"requestFilter\"&gt;Provide a function to modify the HttpWebRequest object.&lt;\/param&gt;\n\/\/\/ &lt;param name=\"responseFilter\"&gt;Provide a function to grab information from the HttpWebResponse object.&lt;\/param&gt;\npublic RestAPI(string url, string key, string secret, bool authorizedHeader = true,\n                    Func&lt;string, string&gt; jsonSerializeFilter = null,\n                    Func&lt;string, string&gt; jsonDeserializeFilter = null,\n                    Action&lt;HttpWebRequest&gt; requestFilter = null,\n                    Action&lt;HttpWebResponse&gt; responseFilter = null)\/\/, bool useProxy = false)\n{\n    if (string.IsNullOrEmpty(url))\n        throw new Exception(\"Please use a valid WooCommerce Restful API url.\");\n\n    string urlLower = url.Trim().ToLower().TrimEnd('\/');\n    if (urlLower.EndsWith(\"wc-api\/v1\") || urlLower.EndsWith(\"wc-api\/v2\") || urlLower.EndsWith(\"wc-api\/v3\"))\n        Version = APIVersion.Legacy;\n    else if (urlLower.EndsWith(\"wp-json\/wc\/v1\"))\n        Version = APIVersion.Version1;\n    else if (urlLower.EndsWith(\"wp-json\/wc\/v2\"))\n        Version = APIVersion.Version2;\n    else if (urlLower.EndsWith(\"wp-json\/wc\/v3\"))\n        Version = APIVersion.Version3;\n    else if (urlLower.Contains(\"wp-json\/wc-\"))\n        Version = APIVersion.ThirdPartyPlugins;\n    else if (urlLower.EndsWith(\"wp-json\/wp\/v2\") || urlLower.EndsWith(\"wp-json\"))\n        Version = APIVersion.WordPressAPI;\n    else if (urlLower.EndsWith(\"jwt-auth\/v1\/token\"))\n    {\n        Version = APIVersion.WordPressAPIJWT;\n        url = urlLower.Replace(\"jwt-auth\/v1\/token\", \"wp\/v2\");\n    }\n    else\n    {\n        Version = APIVersion.Unknown;\n        throw new Exception(\"Unknown WooCommerce Restful API version.\");\n    }\n\n    wc_url = url + (url.EndsWith(\"\/\") ? \"\" : \"\/\");\n    wc_key = key;\n    AuthorizedHeader = authorizedHeader;\n\n    \/\/Why extra '&amp;'? look here: https:\/\/wordpress.org\/support\/topic\/woocommerce-rest-api-v3-problem-woocommerce_api_authentication_error\/\n    if ((url.ToLower().Contains(\"wc-api\/v3\") || !IsLegacy) &amp;&amp; !wc_url.StartsWith(\"https\", StringComparison.OrdinalIgnoreCase) &amp;&amp; !(Version == APIVersion.WordPressAPI || Version == APIVersion.WordPressAPIJWT))\n        wc_secret = secret + \"&amp;\";\n    else\n        wc_secret = secret;\n\n    jsonSeFilter = jsonSerializeFilter;\n    jsonDeseFilter = jsonDeserializeFilter;\n    webRequestFilter = requestFilter;\n    webResponseFilter = responseFilter;\n\n    \/\/wc_Proxy = useProxy;\n}\n\n\npublic bool IsLegacy\n{\n    get\n    {\n        return Version == APIVersion.Legacy;\n    }\n}\n\npublic APIVersion Version { get; private set; }\n\npublic string Url { get { return wc_url; } }\n\n\/\/\/ &lt;summary&gt;\n\/\/\/ Make Restful calls\n\/\/\/ &lt;\/summary&gt;\n\/\/\/ &lt;typeparam name=\"T\"&gt;&lt;\/typeparam&gt;\n\/\/\/ &lt;param name=\"endpoint\"&gt;&lt;\/param&gt;\n\/\/\/ &lt;param name=\"method\"&gt;HEAD, GET, POST, PUT, PATCH, DELETE&lt;\/param&gt;\n\/\/\/ &lt;param name=\"requestBody\"&gt;If your call doesn't have a body, please pass string.Empty, not null.&lt;\/param&gt;\n\/\/\/ &lt;param name=\"parms\"&gt;&lt;\/param&gt;\n\/\/\/ &lt;returns&gt;json string&lt;\/returns&gt;\npublic virtual async Task&lt;string&gt; SendHttpClientRequest&lt;T&gt;(string endpoint, RequestMethod method, T requestBody, Dictionary&lt;string, string&gt; parms = null)\n{\n    HttpWebRequest httpWebRequest = null;\n    try\n    {\n        if (Version == APIVersion.WordPressAPI)\n        {\n            if (string.IsNullOrEmpty(oauth_token) || string.IsNullOrEmpty(oauth_token_secret))\n                throw new Exception($\"oauth_token and oauth_token_secret parameters are required when using WordPress REST API.\");\n        }\n\n        if ((Version == APIVersion.WordPressAPIJWT || WCAuthWithJWT) &amp;&amp; JWT_Object == null)\n        {\n            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(wc_url.Replace(\"wp\/v2\", \"jwt-auth\/v1\/token\")\n                                                                                .Replace(\"wc\/v1\", \"jwt-auth\/v1\/token\")\n                                                                                .Replace(\"wc\/v2\", \"jwt-auth\/v1\/token\")\n                                                                                .Replace(\"wc\/v3\", \"jwt-auth\/v1\/token\"));\n            request.Method = \"POST\";\n            request.ContentType = \"application\/x-www-form-urlencoded\";\n\n            if (JWTRequestFilter != null)\n                JWTRequestFilter.Invoke(request);\n\n            var buffer = Encoding.UTF8.GetBytes($\"username={wc_key}&amp;password={WebUtility.UrlEncode(wc_secret)}\");\n            using (Stream dataStream = await request.GetRequestStreamAsync().ConfigureAwait(false))\n            {\n                dataStream.Write(buffer, 0, buffer.Length);\n            }\n            WebResponse response = await request.GetResponseAsync().ConfigureAwait(false);\n            Stream resStream = response.GetResponseStream();\n            string result = await GetStreamContent(resStream, \"UTF-8\").ConfigureAwait(false);\n\n            if (JWTDeserializeFilter != null)\n                result = JWTDeserializeFilter.Invoke(result);\n\n            JWT_Object = DeserializeJSon&lt;WP_JWT_Object&gt;(result);\n        }\n\n        if (wc_url.StartsWith(\"https\", StringComparison.OrdinalIgnoreCase) &amp;&amp; Version != APIVersion.WordPressAPI &amp;&amp; Version != APIVersion.WordPressAPIJWT)\n        {\n            if (AuthorizedHeader == false)\n            {\n                if (parms == null)\n                    parms = new Dictionary&lt;string, string&gt;();\n\n                if (!parms.ContainsKey(\"consumer_key\"))\n                    parms.Add(\"consumer_key\", wc_key);\n                if (!parms.ContainsKey(\"consumer_secret\"))\n                    parms.Add(\"consumer_secret\", wc_secret);\n            }<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>            \/\/Allow accessing WordPress plugin REST API with WooCommerce secret and key.\n            \/\/Url should be passed to RestAPI as WooCommerce Rest API url, e.g.: https:\/\/mystore.com\/wp-json\/wc\/v3\n            \/\/Endpoint should be starting with wp-json\n            if (endpoint.StartsWith(\"wp-json\"))\n                httpWebRequest = (HttpWebRequest)WebRequest.Create(new Uri(new Uri($\"https:\/\/{new Uri(wc_url).Host}\"), GetOAuthEndPoint(method.ToString(), endpoint, parms)));\n            else\n                httpWebRequest = (HttpWebRequest)WebRequest.Create(wc_url + GetOAuthEndPoint(method.ToString(), endpoint, parms));\n\n            if (AuthorizedHeader == true)\n            {\n                if (WCAuthWithJWT &amp;&amp; JWT_Object != null)\n                    httpWebRequest.Headers&#91;\"Authorization\"] = \"Bearer \" + JWT_Object.token;\n                else\n                    httpWebRequest.Headers&#91;\"Authorization\"] = \"Basic \" + Convert.ToBase64String(Encoding.GetEncoding(\"ISO-8859-1\").GetBytes(wc_key + \":\" + wc_secret));\n            }\n        }\n        else\n        {\n            httpWebRequest = (HttpWebRequest)WebRequest.Create(wc_url + GetOAuthEndPoint(method.ToString(), endpoint, parms));\n            if (Version == APIVersion.WordPressAPIJWT)\n                httpWebRequest.Headers&#91;\"Authorization\"] = \"Bearer \" + JWT_Object.token;\n        }\n\n        \/\/ start the stream immediately\n        httpWebRequest.Method = method.ToString();\n        httpWebRequest.AllowReadStreamBuffering = false;\n        \n        if (webRequestFilter != null)\n            webRequestFilter.Invoke(httpWebRequest);\n\n        \/\/if (wc_Proxy)\n        \/\/    httpWebRequest.Proxy.Credentials = CredentialCache.DefaultCredentials;\n        \/\/else\n        \/\/    httpWebRequest.Proxy = null;\n\n        if (requestBody != null &amp;&amp; requestBody.GetType() != typeof(string))\n        {\n            httpWebRequest.ContentType = \"application\/json\";\n            var buffer = Encoding.UTF8.GetBytes(SerializeJSon(parms));\n            using (Stream dataStream = await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false))\n            {\n                dataStream.Write(buffer, 0, buffer.Length);\n            }\n        }\n        else\n        {\n            if (requestBody != null &amp;&amp; requestBody.ToString() != string.Empty)\n            {\n                if (requestBody.ToString() == \"fileupload\")\n                {\n                    httpWebRequest.Headers&#91;\"Content-Disposition\"] = $\"form-data; filename=\\\"{parms&#91;\"name\"]}\\\"\";\n                    httpWebRequest.ContentType = \"application\/x-www-form-urlencoded\";\n\n                    using (Stream dataStream = await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false))\n                    {\n                        FileStream fileStream = new FileStream(parms&#91;\"path\"], FileMode.Open, FileAccess.Read);\n                        byte&#91;] buffer = new byte&#91;4096];\n                        int bytesRead = 0;\n\n                        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)\n                        {\n                            dataStream.Write(buffer, 0, bytesRead);\n                        }\n                        fileStream.Close();\n                    }\n                }\n                else\n                {\n                    httpWebRequest.ContentType = \"application\/json\";\n                    var buffer = Encoding.UTF8.GetBytes(requestBody.ToString());\n                    using (Stream dataStream = await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false))\n                    {\n                        dataStream.Write(buffer, 0, buffer.Length);\n                    }\n                }\n            }\n        }\n\n        \/\/ asynchronously get a response\n        WebResponse wr = await httpWebRequest.GetResponseAsync().ConfigureAwait(false);\n\n        if (webResponseFilter != null)\n            webResponseFilter.Invoke((HttpWebResponse)wr);\n\n        return await GetStreamContent(wr.GetResponseStream(), wr.ContentType.Contains(\"=\") ? wr.ContentType.Split('=')&#91;1] : \"UTF-8\").ConfigureAwait(false);\n    }\n    catch (WebException we)\n    {\n        if (httpWebRequest != null &amp;&amp; httpWebRequest.HaveResponse)\n            if (we.Response != null)\n                throw new WebException(await GetStreamContent(we.Response.GetResponseStream(), we.Response.ContentType.Contains(\"=\") ? we.Response.ContentType.Split('=')&#91;1] : \"UTF-8\").ConfigureAwait(false), we.InnerException, we.Status, we.Response);\n            else\n                throw we;\n        else\n            throw we;\n    }\n    catch (Exception e)\n    {\n        return e.Message;\n    }\n}\n\npublic async Task&lt;string> GetRestful(string endpoint, Dictionary&lt;string, string> parms = null)\n{\n    return await SendHttpClientRequest(endpoint.ToLower(), RequestMethod.GET, string.Empty, parms).ConfigureAwait(false);\n}\n\npublic async Task&lt;string> PostRestful(string endpoint, object jsonObject, Dictionary&lt;string, string> parms = null)\n{\n    return await SendHttpClientRequest(endpoint.ToLower(), RequestMethod.POST, jsonObject, parms).ConfigureAwait(false);\n}\n\npublic async Task&lt;string> PutRestful(string endpoint, object jsonObject, Dictionary&lt;string, string> parms = null)\n{\n    return await SendHttpClientRequest(endpoint.ToLower(), RequestMethod.PUT, jsonObject, parms).ConfigureAwait(false);\n}\n\npublic async Task&lt;string> DeleteRestful(string endpoint, Dictionary&lt;string, string> parms = null)\n{\n    return await SendHttpClientRequest(endpoint.ToLower(), RequestMethod.DELETE, string.Empty, parms).ConfigureAwait(false);\n}\n\npublic async Task&lt;string> DeleteRestful(string endpoint, object jsonObject, Dictionary&lt;string, string> parms = null)\n{\n    return await SendHttpClientRequest(endpoint.ToLower(), RequestMethod.DELETE, jsonObject, parms).ConfigureAwait(false);\n}\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>        protected string GetOAuthEndPoint(string method, string endpoint, Dictionary&lt;string, string> parms = null)\n        {\n            if (Version == APIVersion.WordPressAPIJWT || (wc_url.StartsWith(\"https\", StringComparison.OrdinalIgnoreCase) &amp;&amp; Version != APIVersion.WordPressAPI))\n            {\n                if (parms == null)\n                    return endpoint;\n                else\n                {\n                    string requestParms = string.Empty;\n                    foreach (var parm in parms)\n                        requestParms += parm.Key + \"=\" + parm.Value + \"&amp;\";\n\n                    return endpoint + \"?\" + requestParms.TrimEnd('&amp;');\n                }\n            }\n            \n            Dictionary&lt;string, string> dic = new Dictionary&lt;string, string>();\n            dic.Add(\"oauth_consumer_key\", wc_key);\n\n            if (Version == APIVersion.WordPressAPI)\n                dic.Add(\"oauth_token\", oauth_token);\n\n            dic.Add(\"oauth_nonce\", Guid.NewGuid().ToString(\"N\"));\n            dic.Add(\"oauth_signature_method\", \"HMAC-SHA256\");\n            dic.Add(\"oauth_timestamp\", Common.GetUnixTime(false));\n            dic.Add(\"oauth_version\", \"1.0\");\n\n            if (parms != null)\n                foreach (var p in parms)\n                    dic.Add(p.Key, p.Value);\n\n            string base_request_uri = method.ToUpper() + \"&amp;\" + Uri.EscapeDataString(wc_url + endpoint) + \"&amp;\";\n            string stringToSign = string.Empty;\n\n            foreach (var parm in dic.OrderBy(x => x.Key))\n                stringToSign += Uri.EscapeDataString(parm.Key) + \"=\" + Uri.EscapeDataString(parm.Value) + \"&amp;\";\n\n            base_request_uri = base_request_uri + Uri.EscapeDataString(stringToSign.TrimEnd('&amp;'));\n\n            if (Version == APIVersion.WordPressAPI)\n                dic.Add(\"oauth_signature\", Common.GetSHA256(wc_secret + \"&amp;\" + oauth_token_secret, base_request_uri));\n            else\n                dic.Add(\"oauth_signature\", Common.GetSHA256(wc_secret, base_request_uri));\n            \n            string parmstr = string.Empty;\n            foreach (var parm in dic)\n                parmstr += parm.Key + \"=\" + Uri.EscapeDataString(parm.Value) + \"&amp;\";\n\n            return endpoint + \"?\" + parmstr.TrimEnd('&amp;');\n        }\n\n        protected async Task&lt;string> GetStreamContent(Stream s, string charset)\n        {\n            StringBuilder sb = new StringBuilder();\n            byte&#91;] Buffer = new byte&#91;512];\n            int count = 0;\n            count = await s.ReadAsync(Buffer, 0, Buffer.Length).ConfigureAwait(false);\n            while (count > 0)\n            {\n                sb.Append(Encoding.GetEncoding(charset).GetString(Buffer, 0, count));\n                count = await s.ReadAsync(Buffer, 0, Buffer.Length).ConfigureAwait(false);\n            }\n\n            return sb.ToString();\n        }\n\n        public virtual string SerializeJSon&lt;T>(T t)\n        {\n            DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings()\n            {\n                DateTimeFormat = new DateTimeFormat(DateTimeFormat),\n                UseSimpleDictionaryFormat = true\n            };\n\n            MemoryStream stream = new MemoryStream();\n            DataContractJsonSerializer ds = new DataContractJsonSerializer(t.GetType(), settings);\n            ds.WriteObject(stream, t);\n            byte&#91;] data = stream.ToArray();\n            string jsonString = Encoding.UTF8.GetString(data, 0, data.Length);\n\n            if (t.GetType().GetMethod(\"FormatJsonS\") != null)\n            {\n                jsonString = t.GetType().GetMethod(\"FormatJsonS\").Invoke(null, new object&#91;] { jsonString }).ToString();\n            }\n\n            if (IsLegacy)\n                if (typeof(T).IsArray)\n                    jsonString = \"{\\\"\" + typeof(T).Name.ToLower().Replace(\"&#91;]\", \"s\") + \"\\\":\" + jsonString + \"}\";\n                else\n                    jsonString = \"{\\\"\" + typeof(T).Name.ToLower() + \"\\\":\" + jsonString + \"}\";\n\n            stream.Dispose();\n\n            if (jsonSeFilter != null)\n                jsonString = jsonSeFilter.Invoke(jsonString);\n\n            return jsonString;\n        }\n\n        public virtual T DeserializeJSon&lt;T>(string jsonString)\n        {\n            if (jsonDeseFilter != null)\n                jsonString = jsonDeseFilter.Invoke(jsonString);\n\n            Type dT = typeof(T);\n\n            try\n            {\n                if (dT.Name.EndsWith(\"List\"))\n                    dT = dT.GetTypeInfo().DeclaredProperties.First().PropertyType.GenericTypeArguments&#91;0];\n\n                if (dT.FullName.StartsWith(\"System.Collections.Generic.List\"))\n                {\n                    dT = dT.GetProperty(\"Item\").PropertyType;\n                }\n\n                if (dT.GetMethod(\"FormatJsonD\") != null)\n                {\n                    jsonString = dT.GetMethod(\"FormatJsonD\").Invoke(null, new object&#91;] { jsonString }).ToString();\n                }\n\n                DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings()\n                {\n                    DateTimeFormat = new DateTimeFormat(DateTimeFormat),\n                    UseSimpleDictionaryFormat = true\n                };\n\n                DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T), settings);\n                MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));\n                T obj = (T)ser.ReadObject(stream);\n                stream.Dispose();\n                return obj;\n            }\n            catch (Exception ex)\n            {\n                if (Debug)\n                    throw new Exception(ex.Message + Environment.NewLine + Environment.NewLine + jsonString);\n                else\n                    throw ex;\n            }\n        }\n\n        public string DateTimeFormat\n        {\n            get\n            {\n                return IsLegacy ? \"yyyy-MM-ddTHH:mm:ssZ\" : \"yyyy-MM-ddTHH:mm:ssK\";\n            }\n        }\n    }\n\n    public class WP_JWT_Object\n    {\n        public string token { get; set; }\n\n        public string user_email { get; set; }\n\n        public string user_nicename { get; set; }\n\n        public string user_display_name { get; set; }\n    }\n\n    public enum RequestMethod\n    {\n        HEAD = 1,\n        GET = 2,\n        POST = 3,\n        PUT = 4,\n        PATCH = 5,\n        DELETE = 6\n    }\n\n    public enum APIVersion\n    {\n        Unknown = 0,\n        Legacy = 1,\n        Version1 = 2,\n        Version2 = 3,\n        Version3 = 4,\n        WordPressAPI = 90,\n        WordPressAPIJWT = 91,\n        ThirdPartyPlugins = 99\n    }\n}\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-63","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/mystifying-liskov.77-68-127-141.plesk.page\/index.php?rest_route=\/wp\/v2\/posts\/63","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mystifying-liskov.77-68-127-141.plesk.page\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mystifying-liskov.77-68-127-141.plesk.page\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mystifying-liskov.77-68-127-141.plesk.page\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mystifying-liskov.77-68-127-141.plesk.page\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=63"}],"version-history":[{"count":4,"href":"https:\/\/mystifying-liskov.77-68-127-141.plesk.page\/index.php?rest_route=\/wp\/v2\/posts\/63\/revisions"}],"predecessor-version":[{"id":67,"href":"https:\/\/mystifying-liskov.77-68-127-141.plesk.page\/index.php?rest_route=\/wp\/v2\/posts\/63\/revisions\/67"}],"wp:attachment":[{"href":"https:\/\/mystifying-liskov.77-68-127-141.plesk.page\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=63"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mystifying-liskov.77-68-127-141.plesk.page\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=63"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mystifying-liskov.77-68-127-141.plesk.page\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=63"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}