From 59d2b64312b751a5cd5a69a2adb86976d8ebc343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristoffer=20Sj=C3=B6berg?= Date: Tue, 14 Nov 2023 11:47:18 +0100 Subject: [PATCH 1/2] Create NetStandard 2.0 library Split the library in two parts: One runtime library which targets .NET Standard 2.0 and one test library that targets .NET 6 and consumes the runtime library. This way, Xunit and other test-related libraries are not required to be deployed when referencing Look#. It is recommended to use the lowest/oldest .NET Standard version which under which your library can execute to maximize compatibility. In addition, add support for setting custom headers on a request-by-request basis. This is required because Looker requires the User-Agent header to be present when acquiring an embed session. --- csharp/.gitignore | 1 + .../LookerSdk.Tests.csproj} | 17 ++- .../rtl.Tests/ApiMethodsTests.cs | 2 +- .../rtl.Tests/ApiSettingsTests.cs | 0 .../rtl.Tests/AuthSessionTests.cs | 0 .../rtl.Tests/AuthTokenTests.cs | 0 .../rtl.Tests/SdkMethodsTests.cs | 0 .../rtl.Tests/SdkUtilsTests.cs | 0 .../rtl.Tests/TestUtils.cs | 0 .../rtl.Tests/TransportTests.cs | 5 +- .../rtl.Tests/sdkrtl.Tests.csproj | 0 csharp/LookerSdk/LookerSdk.csproj | 14 ++ csharp/{ => LookerSdk}/rtl/ApiMethods.cs | 0 csharp/{ => LookerSdk}/rtl/ApiSettings.cs | 2 + csharp/{ => LookerSdk}/rtl/AuthSession.cs | 3 - csharp/{ => LookerSdk}/rtl/AuthToken.cs | 0 csharp/{ => LookerSdk}/rtl/Constants.cs | 0 csharp/{ => LookerSdk}/rtl/SdkUtils.cs | 0 csharp/{ => LookerSdk}/rtl/Transport.cs | 101 +++++++------- csharp/{ => LookerSdk}/rtl/sdkrtl.csproj | 0 csharp/{ => LookerSdk}/sdk/4.0/methods.cs | 132 +++++++++--------- csharp/{ => LookerSdk}/sdk/4.0/models.cs | 0 csharp/README.md | 3 +- csharp/csharp.sln | 25 +++- 24 files changed, 172 insertions(+), 133 deletions(-) create mode 100644 csharp/.gitignore rename csharp/{csharp.csproj => LookerSdk.Tests/LookerSdk.Tests.csproj} (53%) rename csharp/{ => LookerSdk.Tests}/rtl.Tests/ApiMethodsTests.cs (99%) rename csharp/{ => LookerSdk.Tests}/rtl.Tests/ApiSettingsTests.cs (100%) rename csharp/{ => LookerSdk.Tests}/rtl.Tests/AuthSessionTests.cs (100%) rename csharp/{ => LookerSdk.Tests}/rtl.Tests/AuthTokenTests.cs (100%) rename csharp/{ => LookerSdk.Tests}/rtl.Tests/SdkMethodsTests.cs (100%) rename csharp/{ => LookerSdk.Tests}/rtl.Tests/SdkUtilsTests.cs (100%) rename csharp/{ => LookerSdk.Tests}/rtl.Tests/TestUtils.cs (100%) rename csharp/{ => LookerSdk.Tests}/rtl.Tests/TransportTests.cs (95%) rename csharp/{ => LookerSdk.Tests}/rtl.Tests/sdkrtl.Tests.csproj (100%) create mode 100644 csharp/LookerSdk/LookerSdk.csproj rename csharp/{ => LookerSdk}/rtl/ApiMethods.cs (100%) rename csharp/{ => LookerSdk}/rtl/ApiSettings.cs (96%) rename csharp/{ => LookerSdk}/rtl/AuthSession.cs (98%) rename csharp/{ => LookerSdk}/rtl/AuthToken.cs (100%) rename csharp/{ => LookerSdk}/rtl/Constants.cs (100%) rename csharp/{ => LookerSdk}/rtl/SdkUtils.cs (100%) rename csharp/{ => LookerSdk}/rtl/Transport.cs (84%) rename csharp/{ => LookerSdk}/rtl/sdkrtl.csproj (100%) rename csharp/{ => LookerSdk}/sdk/4.0/methods.cs (98%) rename csharp/{ => LookerSdk}/sdk/4.0/models.cs (100%) diff --git a/csharp/.gitignore b/csharp/.gitignore new file mode 100644 index 000000000..0a3438179 --- /dev/null +++ b/csharp/.gitignore @@ -0,0 +1 @@ +.vs \ No newline at end of file diff --git a/csharp/csharp.csproj b/csharp/LookerSdk.Tests/LookerSdk.Tests.csproj similarity index 53% rename from csharp/csharp.csproj rename to csharp/LookerSdk.Tests/LookerSdk.Tests.csproj index 01dda240f..a62d8e007 100644 --- a/csharp/csharp.csproj +++ b/csharp/LookerSdk.Tests/LookerSdk.Tests.csproj @@ -2,17 +2,24 @@ net6.0 false - false 10 + Library - bin\Debug/net6.0/ + bin\Debug - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/csharp/rtl.Tests/ApiMethodsTests.cs b/csharp/LookerSdk.Tests/rtl.Tests/ApiMethodsTests.cs similarity index 99% rename from csharp/rtl.Tests/ApiMethodsTests.cs rename to csharp/LookerSdk.Tests/rtl.Tests/ApiMethodsTests.cs index 5e247fa59..916dd317b 100644 --- a/csharp/rtl.Tests/ApiMethodsTests.cs +++ b/csharp/LookerSdk.Tests/rtl.Tests/ApiMethodsTests.cs @@ -44,4 +44,4 @@ public async Task GetHtmlUrlTest() Assert.Contains(_config.HtmlTestContent, actual); } } -} \ No newline at end of file +} diff --git a/csharp/rtl.Tests/ApiSettingsTests.cs b/csharp/LookerSdk.Tests/rtl.Tests/ApiSettingsTests.cs similarity index 100% rename from csharp/rtl.Tests/ApiSettingsTests.cs rename to csharp/LookerSdk.Tests/rtl.Tests/ApiSettingsTests.cs diff --git a/csharp/rtl.Tests/AuthSessionTests.cs b/csharp/LookerSdk.Tests/rtl.Tests/AuthSessionTests.cs similarity index 100% rename from csharp/rtl.Tests/AuthSessionTests.cs rename to csharp/LookerSdk.Tests/rtl.Tests/AuthSessionTests.cs diff --git a/csharp/rtl.Tests/AuthTokenTests.cs b/csharp/LookerSdk.Tests/rtl.Tests/AuthTokenTests.cs similarity index 100% rename from csharp/rtl.Tests/AuthTokenTests.cs rename to csharp/LookerSdk.Tests/rtl.Tests/AuthTokenTests.cs diff --git a/csharp/rtl.Tests/SdkMethodsTests.cs b/csharp/LookerSdk.Tests/rtl.Tests/SdkMethodsTests.cs similarity index 100% rename from csharp/rtl.Tests/SdkMethodsTests.cs rename to csharp/LookerSdk.Tests/rtl.Tests/SdkMethodsTests.cs diff --git a/csharp/rtl.Tests/SdkUtilsTests.cs b/csharp/LookerSdk.Tests/rtl.Tests/SdkUtilsTests.cs similarity index 100% rename from csharp/rtl.Tests/SdkUtilsTests.cs rename to csharp/LookerSdk.Tests/rtl.Tests/SdkUtilsTests.cs diff --git a/csharp/rtl.Tests/TestUtils.cs b/csharp/LookerSdk.Tests/rtl.Tests/TestUtils.cs similarity index 100% rename from csharp/rtl.Tests/TestUtils.cs rename to csharp/LookerSdk.Tests/rtl.Tests/TestUtils.cs diff --git a/csharp/rtl.Tests/TransportTests.cs b/csharp/LookerSdk.Tests/rtl.Tests/TransportTests.cs similarity index 95% rename from csharp/rtl.Tests/TransportTests.cs rename to csharp/LookerSdk.Tests/rtl.Tests/TransportTests.cs index ed1cefeb6..b7a5bff29 100644 --- a/csharp/rtl.Tests/TransportTests.cs +++ b/csharp/LookerSdk.Tests/rtl.Tests/TransportTests.cs @@ -1,10 +1,9 @@ using System; using System.Net; using System.Net.Http; -using System.Text.Json; using System.Threading.Tasks; using Looker.RTL; -using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; +using Newtonsoft.Json; using Xunit; using Xunit.Abstractions; @@ -62,7 +61,7 @@ public async Task GetJsonUrlTest() var content = actual.Body.ToString(); Assert.NotNull(content); Assert.Contains("looker_release_version", content); - var json = JsonSerializer.Deserialize(content); + var json = JsonConvert.DeserializeObject(content); Assert.Equal(json.Keys, _versionKeys); } diff --git a/csharp/rtl.Tests/sdkrtl.Tests.csproj b/csharp/LookerSdk.Tests/rtl.Tests/sdkrtl.Tests.csproj similarity index 100% rename from csharp/rtl.Tests/sdkrtl.Tests.csproj rename to csharp/LookerSdk.Tests/rtl.Tests/sdkrtl.Tests.csproj diff --git a/csharp/LookerSdk/LookerSdk.csproj b/csharp/LookerSdk/LookerSdk.csproj new file mode 100644 index 000000000..8cdfcb23b --- /dev/null +++ b/csharp/LookerSdk/LookerSdk.csproj @@ -0,0 +1,14 @@ + + + netstandard2.0 + true + 10 + + + bin\Debug + + + + + + diff --git a/csharp/rtl/ApiMethods.cs b/csharp/LookerSdk/rtl/ApiMethods.cs similarity index 100% rename from csharp/rtl/ApiMethods.cs rename to csharp/LookerSdk/rtl/ApiMethods.cs diff --git a/csharp/rtl/ApiSettings.cs b/csharp/LookerSdk/rtl/ApiSettings.cs similarity index 96% rename from csharp/rtl/ApiSettings.cs rename to csharp/LookerSdk/rtl/ApiSettings.cs index 300264843..50078011a 100644 --- a/csharp/rtl/ApiSettings.cs +++ b/csharp/LookerSdk/rtl/ApiSettings.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using IniParser; @@ -35,6 +36,7 @@ public class ApiSettings : IApiSettings public string AgentTag { get; set; } private string FileName { get; } private string SectionName { get; } + public IDictionary Headers { get; } = new Dictionary(); public ApiSettings() { diff --git a/csharp/rtl/AuthSession.cs b/csharp/LookerSdk/rtl/AuthSession.cs similarity index 98% rename from csharp/rtl/AuthSession.cs rename to csharp/LookerSdk/rtl/AuthSession.cs index e0df018cb..e515739c4 100644 --- a/csharp/rtl/AuthSession.cs +++ b/csharp/LookerSdk/rtl/AuthSession.cs @@ -1,10 +1,7 @@ using System; using System.Net.Http; using System.Net.Http.Headers; -using System.Runtime.CompilerServices; using System.Threading.Tasks; -using Microsoft.VisualBasic.CompilerServices; -using Xunit.Sdk; namespace Looker.RTL { diff --git a/csharp/rtl/AuthToken.cs b/csharp/LookerSdk/rtl/AuthToken.cs similarity index 100% rename from csharp/rtl/AuthToken.cs rename to csharp/LookerSdk/rtl/AuthToken.cs diff --git a/csharp/rtl/Constants.cs b/csharp/LookerSdk/rtl/Constants.cs similarity index 100% rename from csharp/rtl/Constants.cs rename to csharp/LookerSdk/rtl/Constants.cs diff --git a/csharp/rtl/SdkUtils.cs b/csharp/LookerSdk/rtl/SdkUtils.cs similarity index 100% rename from csharp/rtl/SdkUtils.cs rename to csharp/LookerSdk/rtl/SdkUtils.cs diff --git a/csharp/rtl/Transport.cs b/csharp/LookerSdk/rtl/Transport.cs similarity index 84% rename from csharp/rtl/Transport.cs rename to csharp/LookerSdk/rtl/Transport.cs index 14e71e1df..40e66c49b 100644 --- a/csharp/rtl/Transport.cs +++ b/csharp/LookerSdk/rtl/Transport.cs @@ -1,13 +1,13 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Text; -using System.Text.Json; using System.Threading.Tasks; using Newtonsoft.Json; -using JsonSerializer = System.Text.Json.JsonSerializer; namespace Looker.RTL { @@ -19,16 +19,18 @@ namespace Looker.RTL public interface ITransportSettings { /// base URL of API REST web service - string BaseUrl { get; set; } + string BaseUrl { get; } /// whether to verify ssl certs or not. Defaults to true - bool VerifySsl { get; set; } + bool VerifySsl { get; } /// request timeout in seconds. Default to 30 - int Timeout { get; set; } + int Timeout { get; } /// agent tag to use for the SDK requests string AgentTag { get; set; } + + IDictionary Headers { get; } } /// @@ -154,7 +156,7 @@ Task> Request( /// /// HTPP request processor /// - public class Transport : ITransport, ITransportSettings + public class Transport : ITransport { private readonly HttpClient _client; private readonly ITransportSettings _settings; @@ -188,7 +190,7 @@ public string MakeUrl(string path, Values queryParams = null, Authenticator auth || path.StartsWith("https:", StringComparison.InvariantCultureIgnoreCase)) return SdkUtils.AddQueryParams(path, queryParams); // TODO I don't think authenticator is needed here any more? - return SdkUtils.AddQueryParams($"{BaseUrl}{path}", queryParams); + return SdkUtils.AddQueryParams($"{_settings.BaseUrl}{path}", queryParams); } private static RawResponse InitRawResponse(HttpResponseMessage response) @@ -225,6 +227,26 @@ public async Task RawRequest( var request = new HttpRequestMessage(method, url); request.Headers.Add(Constants.LookerAppiId, _settings.AgentTag); + foreach(var h in _settings.Headers) + { + if (request.Headers.Contains(h.Key)) + { + request.Headers.Remove(h.Key); + } + request.Headers.Add(h.Key, h.Value); + } + if (options != null) + { + foreach (var h in options.Headers) + { + if (request.Headers.Contains(h.Key)) + { + request.Headers.Remove(h.Key); + } + request.Headers.Add(h.Key, h.Value); + } + } + if (body != null) { if (body is string) @@ -238,7 +260,7 @@ public async Task RawRequest( { request.Content = new StringContent( - JsonSerializer.Serialize(body, new JsonSerializerOptions { IgnoreNullValues = true }), + JsonConvert.SerializeObject(body, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), Encoding.UTF8, "application/json"); } @@ -250,27 +272,30 @@ public async Task RawRequest( try { response = await _client.SendAsync(request); + response.EnsureSuccessStatusCode(); result = InitRawResponse(response); // if (response.IsSuccessStatusCode) - await using var stream = await response.Content.ReadAsStreamAsync(); - // Simple content conversion here to make body easily readable in consumers - switch (SdkUtils.ResponseMode(result.ContentType)) + using (var stream = await response.Content.ReadAsStreamAsync()) { - case ResponseMode.Binary: - result.Body = SdkUtils.StreamToByteArray(stream); - break; - case ResponseMode.String: - using (var sr = new StreamReader(stream)) - { - result.Body = await sr.ReadToEndAsync(); - } - - break; - case ResponseMode.Unknown: - result.Body = SdkUtils.StreamToByteArray(stream); - break; - default: - throw new ArgumentOutOfRangeException($"Unrecognized Content Type {result.ContentType}"); + // Simple content conversion here to make body easily readable in consumers + switch (SdkUtils.ResponseMode(result.ContentType)) + { + case ResponseMode.Binary: + result.Body = SdkUtils.StreamToByteArray(stream); + break; + case ResponseMode.String: + using (var sr = new StreamReader(stream)) + { + result.Body = await sr.ReadToEndAsync(); + } + + break; + case ResponseMode.Unknown: + result.Body = SdkUtils.StreamToByteArray(stream); + break; + default: + throw new ArgumentOutOfRangeException($"Unrecognized Content Type {result.ContentType}"); + } } } catch (Exception e) @@ -328,29 +353,5 @@ public async Task> Request( var raw = await RawRequest(method, path, queryParams, body, authenticator, options); return ParseResponse(raw); } - - public string BaseUrl - { - get => _settings.BaseUrl; - set => _settings.BaseUrl = value; - } - - public bool VerifySsl - { - get => _settings.VerifySsl; - set => _settings.VerifySsl = value; - } - - public int Timeout - { - get => _settings.Timeout; - set => _settings.Timeout = value; - } - - public string AgentTag - { - get => _settings.AgentTag; - set => _settings.AgentTag = value; - } } } diff --git a/csharp/rtl/sdkrtl.csproj b/csharp/LookerSdk/rtl/sdkrtl.csproj similarity index 100% rename from csharp/rtl/sdkrtl.csproj rename to csharp/LookerSdk/rtl/sdkrtl.csproj diff --git a/csharp/sdk/4.0/methods.cs b/csharp/LookerSdk/sdk/4.0/methods.cs similarity index 98% rename from csharp/sdk/4.0/methods.cs rename to csharp/LookerSdk/sdk/4.0/methods.cs index 0643b125b..bbf74edbf 100644 --- a/csharp/sdk/4.0/methods.cs +++ b/csharp/LookerSdk/sdk/4.0/methods.cs @@ -161,7 +161,7 @@ public async Task> update_alert_field( ITransportSettings? options = null) { alert_id = SdkUtils.EncodeParam(alert_id); - return await AuthRequest(HttpMethod.Patch, $"/alerts/{alert_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/alerts/{alert_id}", null,body,options); } /// ### Delete an alert by a given alert ID @@ -276,7 +276,7 @@ public async Task> read_alert_notific ITransportSettings? options = null) { alert_notification_id = SdkUtils.EncodeParam(alert_notification_id); - return await AuthRequest(HttpMethod.Patch, $"/alert_notifications/{alert_notification_id}", null,null,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/alert_notifications/{alert_notification_id}", null,null,options); } #endregion Alert: Alert @@ -436,8 +436,8 @@ public async Task> artifact_value( string? key = null, ITransportSettings? options = null) { - namespace = SdkUtils.EncodeParam(namespace); - return await AuthRequest(HttpMethod.Get, $"/artifact/{namespace}/value", new Values { + @namespace = SdkUtils.EncodeParam(@namespace); + return await AuthRequest(HttpMethod.Get, $"/artifact/{@namespace}/value", new Values { { "key", key }},null,options); } @@ -454,8 +454,8 @@ public async Task> purge_artifacts( string @namespace, ITransportSettings? options = null) { - namespace = SdkUtils.EncodeParam(namespace); - return await AuthRequest(HttpMethod.Delete, $"/artifact/{namespace}/purge", null,null,options); + @namespace = SdkUtils.EncodeParam(@namespace); + return await AuthRequest(HttpMethod.Delete, $"/artifact/{@namespace}/purge", null,null,options); } /// ### Search all key/value pairs in a namespace for matching criteria. @@ -499,8 +499,8 @@ public async Task> search_artifacts( long? offset = null, ITransportSettings? options = null) { - namespace = SdkUtils.EncodeParam(namespace); - return await AuthRequest(HttpMethod.Get, $"/artifact/{namespace}/search", new Values { + @namespace = SdkUtils.EncodeParam(@namespace); + return await AuthRequest(HttpMethod.Get, $"/artifact/{@namespace}/search", new Values { { "fields", fields }, { "key", key }, { "user_ids", user_ids }, @@ -533,8 +533,8 @@ public async Task> artifact( long? offset = null, ITransportSettings? options = null) { - namespace = SdkUtils.EncodeParam(namespace); - return await AuthRequest(HttpMethod.Get, $"/artifact/{namespace}", new Values { + @namespace = SdkUtils.EncodeParam(@namespace); + return await AuthRequest(HttpMethod.Get, $"/artifact/{@namespace}", new Values { { "key", key }, { "fields", fields }, { "limit", limit }, @@ -551,15 +551,15 @@ namespace = SdkUtils.EncodeParam(namespace); /// /// void The artifact is deleted. () /// - /// Artifact storage namespace + /// Artifact storage @namespace /// Comma-delimited list of keys. Wildcards not allowed. public async Task> delete_artifact( string @namespace, string key, ITransportSettings? options = null) { - namespace = SdkUtils.EncodeParam(namespace); - return await AuthRequest(HttpMethod.Delete, $"/artifact/{namespace}", new Values { + @namespace = SdkUtils.EncodeParam(@namespace); + return await AuthRequest(HttpMethod.Delete, $"/artifact/{@namespace}", new Values { { "key", key }},null,options); } @@ -590,11 +590,11 @@ namespace = SdkUtils.EncodeParam(namespace); /// /// **Note**: The artifact storage API can only be used by Looker-built extensions. /// - /// PUT /artifacts/{namespace} -> Artifact[] + /// PUT /artifacts/{@namespace} -> Artifact[] /// /// Artifact[] Created or updated artifacts (application/json) /// - /// Artifact storage namespace + /// Artifact storage @namespace /// Comma-delimited names of fields to return in responses. Omit for all fields public async Task> update_artifacts( string @namespace, @@ -602,8 +602,8 @@ public async Task> update_artifacts( string? fields = null, ITransportSettings? options = null) { - namespace = SdkUtils.EncodeParam(namespace); - return await AuthRequest(HttpMethod.Put, $"/artifacts/{namespace}", new Values { + @namespace = SdkUtils.EncodeParam(@namespace); + return await AuthRequest(HttpMethod.Put, $"/artifacts/{@namespace}", new Values { { "fields", fields }},body,options); } @@ -890,7 +890,7 @@ public async Task> update_ldap_config( WriteLDAPConfig body, ITransportSettings? options = null) { - return await AuthRequest(HttpMethod.Patch, "/ldap_config", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), "/ldap_config", null,body,options); } /// ### Test the connection settings for an LDAP configuration. @@ -1031,7 +1031,7 @@ public async Task> update_mobile_device_regi ITransportSettings? options = null) { device_id = SdkUtils.EncodeParam(device_id); - return await AuthRequest(HttpMethod.Patch, $"/mobile/device/{device_id}", null,null,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/mobile/device/{device_id}", null,null,options); } /// ### Deregister a mobile device. @@ -1131,7 +1131,7 @@ public async Task> update_oauth_client_ap ITransportSettings? options = null) { client_guid = SdkUtils.EncodeParam(client_guid); - return await AuthRequest(HttpMethod.Patch, $"/oauth_client_apps/{client_guid}", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/oauth_client_apps/{client_guid}", new Values { { "fields", fields }},body,options); } @@ -1281,7 +1281,7 @@ public async Task> update_oidc_config( WriteOIDCConfig body, ITransportSettings? options = null) { - return await AuthRequest(HttpMethod.Patch, "/oidc_config", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), "/oidc_config", null,body,options); } /// ### Get a OIDC test configuration by test_slug. @@ -1359,7 +1359,7 @@ public async Task> update_password_config WritePasswordConfig body, ITransportSettings? options = null) { - return await AuthRequest(HttpMethod.Patch, "/password_config", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), "/password_config", null,body,options); } /// ### Force all credentials_email users to reset their login passwords upon their next login. @@ -1421,7 +1421,7 @@ public async Task> update_saml_config( WriteSamlConfig body, ITransportSettings? options = null) { - return await AuthRequest(HttpMethod.Patch, "/saml_config", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), "/saml_config", null,body,options); } /// ### Get a SAML test configuration by test_slug. @@ -1527,7 +1527,7 @@ public async Task> update_session_config( WriteSessionConfig body, ITransportSettings? options = null) { - return await AuthRequest(HttpMethod.Patch, "/session_config", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), "/session_config", null,body,options); } /// ### Get Support Access Allowlist Users @@ -1852,7 +1852,7 @@ public async Task> update_board( ITransportSettings? options = null) { board_id = SdkUtils.EncodeParam(board_id); - return await AuthRequest(HttpMethod.Patch, $"/boards/{board_id}", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/boards/{board_id}", new Values { { "fields", fields }},body,options); } @@ -1941,7 +1941,7 @@ public async Task> update_board_item( ITransportSettings? options = null) { board_item_id = SdkUtils.EncodeParam(board_item_id); - return await AuthRequest(HttpMethod.Patch, $"/board_items/{board_item_id}", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/board_items/{board_item_id}", new Values { { "fields", fields }},body,options); } @@ -2027,7 +2027,7 @@ public async Task> update_board_section( ITransportSettings? options = null) { board_section_id = SdkUtils.EncodeParam(board_section_id); - return await AuthRequest(HttpMethod.Patch, $"/board_sections/{board_section_id}", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/board_sections/{board_section_id}", new Values { { "fields", fields }},body,options); } @@ -2208,7 +2208,7 @@ public async Task> update_color_collecti ITransportSettings? options = null) { collection_id = SdkUtils.EncodeParam(collection_id); - return await AuthRequest(HttpMethod.Patch, $"/color_collections/{collection_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/color_collections/{collection_id}", null,body,options); } /// ### Delete a custom color collection by id @@ -2259,7 +2259,7 @@ public async Task> update_cloud_stor WriteBackupConfiguration body, ITransportSettings? options = null) { - return await AuthRequest(HttpMethod.Patch, "/cloud_storage", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), "/cloud_storage", null,body,options); } /// ### Get the current status and content of custom welcome emails @@ -2288,7 +2288,7 @@ public async Task> update_custom_welc bool? send_test_welcome_email = null, ITransportSettings? options = null) { - return await AuthRequest(HttpMethod.Patch, "/custom_welcome_email", new Values { + return await AuthRequest(new HttpMethod("PATCH"), "/custom_welcome_email", new Values { { "send_test_welcome_email", send_test_welcome_email }},body,options); } @@ -2327,7 +2327,7 @@ public async Task> update_digest_emails_ena DigestEmails body, ITransportSettings? options = null) { - return await AuthRequest(HttpMethod.Patch, "/digest_emails_enabled", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), "/digest_emails_enabled", null,body,options); } /// ### Trigger the generation of digest email records and send them to Looker's internal system. This does not send @@ -2382,7 +2382,7 @@ public async Task> update_i WriteInternalHelpResourcesContent body, ITransportSettings? options = null) { - return await AuthRequest(HttpMethod.Patch, "/internal_help_resources_content", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), "/internal_help_resources_content", null,body,options); } /// ### Get and set the options for internal help resources @@ -2407,7 +2407,7 @@ public async Task> update_internal WriteInternalHelpResources body, ITransportSettings? options = null) { - return await AuthRequest(HttpMethod.Patch, "/internal_help_resources", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), "/internal_help_resources", null,body,options); } /// ### Get all legacy features. @@ -2456,7 +2456,7 @@ public async Task> update_legacy_feature( ITransportSettings? options = null) { legacy_feature_id = SdkUtils.EncodeParam(legacy_feature_id); - return await AuthRequest(HttpMethod.Patch, $"/legacy_features/{legacy_feature_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/legacy_features/{legacy_feature_id}", null,body,options); } /// ### Get a list of locales that Looker supports. @@ -2554,7 +2554,7 @@ public async Task> set_setting( string? fields = null, ITransportSettings? options = null) { - return await AuthRequest(HttpMethod.Patch, "/setting", new Values { + return await AuthRequest(new HttpMethod("PATCH"), "/setting", new Values { { "fields", fields }},body,options); } @@ -2734,7 +2734,7 @@ public async Task> update_connection( ITransportSettings? options = null) { connection_name = SdkUtils.EncodeParam(connection_name); - return await AuthRequest(HttpMethod.Patch, $"/connections/{connection_name}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/connections/{connection_name}", null,body,options); } /// ### Delete a connection. @@ -2937,7 +2937,7 @@ public async Task> update_ssh_server( ITransportSettings? options = null) { ssh_server_id = SdkUtils.EncodeParam(ssh_server_id); - return await AuthRequest(HttpMethod.Patch, $"/ssh_server/{ssh_server_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/ssh_server/{ssh_server_id}", null,body,options); } /// ### Delete an SSH Server. @@ -3026,7 +3026,7 @@ public async Task> update_ssh_tunnel( ITransportSettings? options = null) { ssh_tunnel_id = SdkUtils.EncodeParam(ssh_tunnel_id); - return await AuthRequest(HttpMethod.Patch, $"/ssh_tunnel/{ssh_tunnel_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/ssh_tunnel/{ssh_tunnel_id}", null,body,options); } /// ### Delete an SSH Tunnel @@ -3238,7 +3238,7 @@ public async Task> update_content_metadata( ITransportSettings? options = null) { content_metadata_id = SdkUtils.EncodeParam(content_metadata_id); - return await AuthRequest(HttpMethod.Patch, $"/content_metadata/{content_metadata_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/content_metadata/{content_metadata_id}", null,body,options); } /// ### All content metadata access records for a content metadata item. @@ -3713,7 +3713,7 @@ public async Task> sync_lookml_dashboard( ITransportSettings? options = null) { lookml_dashboard_id = SdkUtils.EncodeParam(lookml_dashboard_id); - return await AuthRequest(HttpMethod.Patch, $"/dashboards/{lookml_dashboard_id}/sync", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/dashboards/{lookml_dashboard_id}/sync", new Values { { "raw_locale", raw_locale }},body,options); } @@ -3763,7 +3763,7 @@ public async Task> update_dashboard( ITransportSettings? options = null) { dashboard_id = SdkUtils.EncodeParam(dashboard_id); - return await AuthRequest(HttpMethod.Patch, $"/dashboards/{dashboard_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/dashboards/{dashboard_id}", null,body,options); } /// ### Delete the dashboard with the specified id @@ -3840,7 +3840,7 @@ public async Task> move_dashboard( ITransportSettings? options = null) { dashboard_id = SdkUtils.EncodeParam(dashboard_id); - return await AuthRequest(HttpMethod.Patch, $"/dashboards/{dashboard_id}/move", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/dashboards/{dashboard_id}/move", new Values { { "folder_id", folder_id }},null,options); } @@ -3999,7 +3999,7 @@ public async Task> update_dashboard_ele ITransportSettings? options = null) { dashboard_element_id = SdkUtils.EncodeParam(dashboard_element_id); - return await AuthRequest(HttpMethod.Patch, $"/dashboard_elements/{dashboard_element_id}", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/dashboard_elements/{dashboard_element_id}", new Values { { "fields", fields }},body,options); } @@ -4088,7 +4088,7 @@ public async Task> update_dashboard_filt ITransportSettings? options = null) { dashboard_filter_id = SdkUtils.EncodeParam(dashboard_filter_id); - return await AuthRequest(HttpMethod.Patch, $"/dashboard_filters/{dashboard_filter_id}", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/dashboard_filters/{dashboard_filter_id}", new Values { { "fields", fields }},body,options); } @@ -4174,7 +4174,7 @@ public async Task> update_dashb ITransportSettings? options = null) { dashboard_layout_component_id = SdkUtils.EncodeParam(dashboard_layout_component_id); - return await AuthRequest(HttpMethod.Patch, $"/dashboard_layout_components/{dashboard_layout_component_id}", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/dashboard_layout_components/{dashboard_layout_component_id}", new Values { { "fields", fields }},body,options); } @@ -4229,7 +4229,7 @@ public async Task> update_dashboard_layo ITransportSettings? options = null) { dashboard_layout_id = SdkUtils.EncodeParam(dashboard_layout_id); - return await AuthRequest(HttpMethod.Patch, $"/dashboard_layouts/{dashboard_layout_id}", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/dashboard_layouts/{dashboard_layout_id}", new Values { { "fields", fields }},body,options); } @@ -4356,7 +4356,7 @@ public async Task> update_datagroup( ITransportSettings? options = null) { datagroup_id = SdkUtils.EncodeParam(datagroup_id); - return await AuthRequest(HttpMethod.Patch, $"/datagroups/{datagroup_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/datagroups/{datagroup_id}", null,body,options); } #endregion Datagroup: Manage Datagroups @@ -4554,7 +4554,7 @@ public async Task> update_folder( ITransportSettings? options = null) { folder_id = SdkUtils.EncodeParam(folder_id); - return await AuthRequest(HttpMethod.Patch, $"/folders/{folder_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/folders/{folder_id}", null,body,options); } /// ### Delete the folder with a specific id including any children folders. @@ -5024,7 +5024,7 @@ public async Task> update_group( ITransportSettings? options = null) { group_id = SdkUtils.EncodeParam(group_id); - return await AuthRequest(HttpMethod.Patch, $"/groups/{group_id}", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/groups/{group_id}", new Values { { "fields", fields }},body,options); } @@ -5180,7 +5180,7 @@ public async Task> update_user_a { group_id = SdkUtils.EncodeParam(group_id); user_attribute_id = SdkUtils.EncodeParam(user_attribute_id); - return await AuthRequest(HttpMethod.Patch, $"/groups/{group_id}/attribute_values/{user_attribute_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/groups/{group_id}/attribute_values/{user_attribute_id}", null,body,options); } /// ### Remove a user attribute value from a group. @@ -5292,7 +5292,7 @@ public async Task> update_integration_hub ITransportSettings? options = null) { integration_hub_id = SdkUtils.EncodeParam(integration_hub_id); - return await AuthRequest(HttpMethod.Patch, $"/integration_hubs/{integration_hub_id}", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/integration_hubs/{integration_hub_id}", new Values { { "fields", fields }},body,options); } @@ -5377,7 +5377,7 @@ public async Task> update_integration( ITransportSettings? options = null) { integration_id = SdkUtils.EncodeParam(integration_id); - return await AuthRequest(HttpMethod.Patch, $"/integrations/{integration_id}", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/integrations/{integration_id}", new Values { { "fields", fields }},body,options); } @@ -5605,7 +5605,7 @@ public async Task> update_look( ITransportSettings? options = null) { look_id = SdkUtils.EncodeParam(look_id); - return await AuthRequest(HttpMethod.Patch, $"/looks/{look_id}", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/looks/{look_id}", new Values { { "fields", fields }},body,options); } @@ -5752,7 +5752,7 @@ public async Task> move_look( ITransportSettings? options = null) { look_id = SdkUtils.EncodeParam(look_id); - return await AuthRequest(HttpMethod.Patch, $"/looks/{look_id}/move", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/looks/{look_id}/move", new Values { { "folder_id", folder_id }},null,options); } @@ -5825,7 +5825,7 @@ public async Task> update_lookml_model( ITransportSettings? options = null) { lookml_model_name = SdkUtils.EncodeParam(lookml_model_name); - return await AuthRequest(HttpMethod.Patch, $"/lookml_models/{lookml_model_name}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/lookml_models/{lookml_model_name}", null,body,options); } /// ### Delete a lookml model. @@ -6457,7 +6457,7 @@ public async Task> update_project( ITransportSettings? options = null) { project_id = SdkUtils.EncodeParam(project_id); - return await AuthRequest(HttpMethod.Patch, $"/projects/{project_id}", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/projects/{project_id}", new Values { { "fields", fields }},body,options); } @@ -7783,7 +7783,7 @@ public async Task> update_model_set( ITransportSettings? options = null) { model_set_id = SdkUtils.EncodeParam(model_set_id); - return await AuthRequest(HttpMethod.Patch, $"/model_sets/{model_set_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/model_sets/{model_set_id}", null,body,options); } /// ### Delete the model set with a specific id. @@ -7932,7 +7932,7 @@ public async Task> update_permission_set( ITransportSettings? options = null) { permission_set_id = SdkUtils.EncodeParam(permission_set_id); - return await AuthRequest(HttpMethod.Patch, $"/permission_sets/{permission_set_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/permission_sets/{permission_set_id}", null,body,options); } /// ### Delete the permission set with a specific id. @@ -8156,7 +8156,7 @@ public async Task> update_role( ITransportSettings? options = null) { role_id = SdkUtils.EncodeParam(role_id); - return await AuthRequest(HttpMethod.Patch, $"/roles/{role_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/roles/{role_id}", null,body,options); } /// ### Delete the role with a specific id. @@ -8345,7 +8345,7 @@ public async Task> update_scheduled_plan( ITransportSettings? options = null) { scheduled_plan_id = SdkUtils.EncodeParam(scheduled_plan_id); - return await AuthRequest(HttpMethod.Patch, $"/scheduled_plans/{scheduled_plan_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/scheduled_plans/{scheduled_plan_id}", null,body,options); } /// ### Delete a Scheduled Plan @@ -8728,7 +8728,7 @@ public async Task> update_session( WriteApiSession body, ITransportSettings? options = null) { - return await AuthRequest(HttpMethod.Patch, "/session", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), "/session", null,body,options); } #endregion Session: Session Information @@ -9099,7 +9099,7 @@ public async Task> update_theme( ITransportSettings? options = null) { theme_id = SdkUtils.EncodeParam(theme_id); - return await AuthRequest(HttpMethod.Patch, $"/themes/{theme_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/themes/{theme_id}", null,body,options); } /// ### Delete a specific theme by id @@ -9437,7 +9437,7 @@ public async Task> update_user( ITransportSettings? options = null) { user_id = SdkUtils.EncodeParam(user_id); - return await AuthRequest(HttpMethod.Patch, $"/users/{user_id}", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/users/{user_id}", new Values { { "fields", fields }},body,options); } @@ -9566,7 +9566,7 @@ public async Task> update_user_credenti ITransportSettings? options = null) { user_id = SdkUtils.EncodeParam(user_id); - return await AuthRequest(HttpMethod.Patch, $"/users/{user_id}/credentials_email", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/users/{user_id}/credentials_email", new Values { { "fields", fields }},body,options); } @@ -10170,7 +10170,7 @@ public async Task> set_user_attri { user_id = SdkUtils.EncodeParam(user_id); user_attribute_id = SdkUtils.EncodeParam(user_attribute_id); - return await AuthRequest(HttpMethod.Patch, $"/users/{user_id}/attribute_values/{user_attribute_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/users/{user_id}/attribute_values/{user_attribute_id}", null,body,options); } /// ### Delete a user attribute value from a user's account settings. @@ -10343,7 +10343,7 @@ public async Task> update_user_attribute( ITransportSettings? options = null) { user_attribute_id = SdkUtils.EncodeParam(user_attribute_id); - return await AuthRequest(HttpMethod.Patch, $"/user_attributes/{user_attribute_id}", new Values { + return await AuthRequest(new HttpMethod("PATCH"), $"/user_attributes/{user_attribute_id}", new Values { { "fields", fields }},body,options); } diff --git a/csharp/sdk/4.0/models.cs b/csharp/LookerSdk/sdk/4.0/models.cs similarity index 100% rename from csharp/sdk/4.0/models.cs rename to csharp/LookerSdk/sdk/4.0/models.cs diff --git a/csharp/README.md b/csharp/README.md index 6aa486e00..99923bc97 100644 --- a/csharp/README.md +++ b/csharp/README.md @@ -7,7 +7,8 @@ Look# was developed using the principles in [Build Your Own SDK](/docs/byosdk.md Look# has: - C# Runtime library with strong typing for HTTP responses -- Uses .NET Core 6.x, an Open Source, cross-platform run-time for macOS, Windows, and Linux +- Targets .NET Standard 2.0, which allows usage in .NET Framework and .NET Core/.NET 6 projects alike. +- Requires .NET 6 to build and test. .NET 6 is an Open Source, cross-platform run-time for macOS, Windows, and Linux - SDK Codegen generates the SDK bindings from the Looker API spec - API 4.0 methods (SDK calls) and models (SDK types) - Includes many unit and some functional tests! diff --git a/csharp/csharp.sln b/csharp/csharp.sln index b0c748c03..e16fa9eaa 100644 --- a/csharp/csharp.sln +++ b/csharp/csharp.sln @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26124.0 MinimumVisualStudioVersion = 15.0.26124.0 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csharp", "csharp.csproj", "{62AEDFE2-37D2-4A43-B05F-1853A8344535}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LookerSdk", "LookerSdk\LookerSdk.csproj", "{62AEDFE2-37D2-4A43-B05F-1853A8344535}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LookerSdk.Tests", "LookerSdk.Tests\LookerSdk.Tests.csproj", "{692E3197-1BB6-4922-8CF7-66F22482988B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -14,9 +16,6 @@ Global Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {62AEDFE2-37D2-4A43-B05F-1853A8344535}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {62AEDFE2-37D2-4A43-B05F-1853A8344535}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -30,5 +29,23 @@ Global {62AEDFE2-37D2-4A43-B05F-1853A8344535}.Release|x64.Build.0 = Release|Any CPU {62AEDFE2-37D2-4A43-B05F-1853A8344535}.Release|x86.ActiveCfg = Release|Any CPU {62AEDFE2-37D2-4A43-B05F-1853A8344535}.Release|x86.Build.0 = Release|Any CPU + {692E3197-1BB6-4922-8CF7-66F22482988B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {692E3197-1BB6-4922-8CF7-66F22482988B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {692E3197-1BB6-4922-8CF7-66F22482988B}.Debug|x64.ActiveCfg = Debug|Any CPU + {692E3197-1BB6-4922-8CF7-66F22482988B}.Debug|x64.Build.0 = Debug|Any CPU + {692E3197-1BB6-4922-8CF7-66F22482988B}.Debug|x86.ActiveCfg = Debug|Any CPU + {692E3197-1BB6-4922-8CF7-66F22482988B}.Debug|x86.Build.0 = Debug|Any CPU + {692E3197-1BB6-4922-8CF7-66F22482988B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {692E3197-1BB6-4922-8CF7-66F22482988B}.Release|Any CPU.Build.0 = Release|Any CPU + {692E3197-1BB6-4922-8CF7-66F22482988B}.Release|x64.ActiveCfg = Release|Any CPU + {692E3197-1BB6-4922-8CF7-66F22482988B}.Release|x64.Build.0 = Release|Any CPU + {692E3197-1BB6-4922-8CF7-66F22482988B}.Release|x86.ActiveCfg = Release|Any CPU + {692E3197-1BB6-4922-8CF7-66F22482988B}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {74969703-84D1-45C6-9CCC-BCDC0E554320} EndGlobalSection EndGlobal From 2e0369649fedb15469dd28571955421f8175d26e Mon Sep 17 00:00:00 2001 From: John Kaster Date: Fri, 8 Nov 2024 18:27:36 -0800 Subject: [PATCH 2/2] change the code generator for the bugs in newer .NET versions HttpMethod.Patch is no longer recognized Also improved reserved word support However, Rider and/or .NET Core test runners completely fail to run tests now so I can't verify this version although it builds successfully with only some warnings --- csharp/LookerSdk.Tests/LookerSdk.Tests.csproj | 4 +- csharp/LookerSdk/rtl/Constants.cs | 2 +- csharp/LookerSdk/sdk/4.0/methods.cs | 18 ++++---- csharp/LookerSdk/sdk/4.0/models.cs | 4 +- packages/sdk-codegen/src/codeGen.ts | 5 ++- packages/sdk-codegen/src/csharp.gen.spec.ts | 41 +++++++++++++++++++ packages/sdk-codegen/src/csharp.gen.ts | 38 ++++++++++++----- spec/Looker.4.0.json | 12 ++++-- spec/Looker.4.0.oas.json | 16 ++++++-- 9 files changed, 107 insertions(+), 33 deletions(-) diff --git a/csharp/LookerSdk.Tests/LookerSdk.Tests.csproj b/csharp/LookerSdk.Tests/LookerSdk.Tests.csproj index a62d8e007..cc630dcee 100644 --- a/csharp/LookerSdk.Tests/LookerSdk.Tests.csproj +++ b/csharp/LookerSdk.Tests/LookerSdk.Tests.csproj @@ -9,12 +9,12 @@ bin\Debug - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/csharp/LookerSdk/rtl/Constants.cs b/csharp/LookerSdk/rtl/Constants.cs index 7f52c9ef4..3e3750fca 100644 --- a/csharp/LookerSdk/rtl/Constants.cs +++ b/csharp/LookerSdk/rtl/Constants.cs @@ -61,7 +61,7 @@ public struct Constants public const string DefaultApiVersion = "4.0"; public const string AgentPrefix = "CS-SDK"; - public const string LookerVersion = "24.18"; + public const string LookerVersion = "24.20"; public const string Bearer = "Bearer"; public const string LookerAppiId = "x-looker-appid"; diff --git a/csharp/LookerSdk/sdk/4.0/methods.cs b/csharp/LookerSdk/sdk/4.0/methods.cs index a6ba35b4c..79f3f1f9f 100644 --- a/csharp/LookerSdk/sdk/4.0/methods.cs +++ b/csharp/LookerSdk/sdk/4.0/methods.cs @@ -429,7 +429,7 @@ public async Task> artifact_namespac /// /// string Artifact value (application/json) /// - /// Artifact storage namespace + /// Artifact storage namespace /// Artifact storage key. Namespace + Key must be unique public async Task> artifact_value( string @namespace, @@ -449,7 +449,7 @@ public async Task> artifact_value( /// /// void All artifacts are purged. () /// - /// Artifact storage namespace + /// Artifact storage namespace public async Task> purge_artifacts( string @namespace, ITransportSettings? options = null) @@ -480,7 +480,7 @@ public async Task> purge_artifacts( /// /// Artifact[] Artifacts (application/json) /// - /// Artifact storage namespace + /// Artifact storage namespace /// Comma-delimited names of fields to return in responses. Omit for all fields /// Key pattern to match /// Ids of users who created or updated the artifact (comma-delimited list) @@ -520,7 +520,7 @@ public async Task> search_artifacts( /// /// Artifact[] Created or updated artifacts (application/json) /// - /// Artifact storage namespace + /// Artifact storage namespace /// Comma-delimited list of keys. Wildcards not allowed. /// Comma-delimited names of fields to return in responses. Omit for all fields /// Number of results to return. (used with offset) @@ -551,7 +551,7 @@ public async Task> artifact( /// /// void The artifact is deleted. () /// - /// Artifact storage @namespace + /// Artifact storage namespace /// Comma-delimited list of keys. Wildcards not allowed. public async Task> delete_artifact( string @namespace, @@ -590,11 +590,11 @@ public async Task> delete_artifact( /// /// **Note**: The artifact storage API can only be used by Looker-built extensions. /// - /// PUT /artifacts/{@namespace} -> Artifact[] + /// PUT /artifacts/{namespace} -> Artifact[] /// /// Artifact[] Created or updated artifacts (application/json) /// - /// Artifact storage @namespace + /// Artifact storage namespace /// Comma-delimited names of fields to return in responses. Omit for all fields public async Task> update_artifacts( string @namespace, @@ -2899,7 +2899,7 @@ public async Task> update_exter ITransportSettings? options = null) { client_id = SdkUtils.EncodeParam(client_id); - return await AuthRequest(HttpMethod.Patch, $"/external_oauth_applications/{client_id}", null,body,options); + return await AuthRequest(new HttpMethod("PATCH"), $"/external_oauth_applications/{client_id}", null,body,options); } /// ### Create OAuth User state. @@ -6356,7 +6356,7 @@ public async Task> delete_git_branch( /// /// Id of project /// Branch to deploy to production - /// Ref to deploy to production + /// Ref to deploy to production public async Task> deploy_ref_to_production( string project_id, string? branch = null, diff --git a/csharp/LookerSdk/sdk/4.0/models.cs b/csharp/LookerSdk/sdk/4.0/models.cs index 6c0d3415e..6389ddfe9 100644 --- a/csharp/LookerSdk/sdk/4.0/models.cs +++ b/csharp/LookerSdk/sdk/4.0/models.cs @@ -4309,7 +4309,7 @@ public class Query : SdkModel public string? filter_expression { get; set; } = null; /// Sorting for the query results. Use the format `["view.field", ...]` to sort on fields in ascending order. Use the format `["view.field desc", ...]` to sort on fields in descending order. Use `["__UNSORTED__"]` (2 underscores before and after) to disable sorting entirely. Empty sorts `[]` will trigger a default sort. public string[]? sorts { get; set; } = null; - /// Limit + /// Row limit. To download unlimited results, set the limit to -1 (negative one). public string? limit { get; set; } = null; /// Column Limit public string? column_limit { get; set; } = null; @@ -6800,7 +6800,7 @@ public class WriteQuery : SdkModel public string? filter_expression { get; set; } = null; /// Sorting for the query results. Use the format `["view.field", ...]` to sort on fields in ascending order. Use the format `["view.field desc", ...]` to sort on fields in descending order. Use `["__UNSORTED__"]` (2 underscores before and after) to disable sorting entirely. Empty sorts `[]` will trigger a default sort. public string[]? sorts { get; set; } = null; - /// Limit + /// Row limit. To download unlimited results, set the limit to -1 (negative one). public string? limit { get; set; } = null; /// Column Limit public string? column_limit { get; set; } = null; diff --git a/packages/sdk-codegen/src/codeGen.ts b/packages/sdk-codegen/src/codeGen.ts index 7966e8762..790623b6d 100644 --- a/packages/sdk-codegen/src/codeGen.ts +++ b/packages/sdk-codegen/src/codeGen.ts @@ -1290,8 +1290,9 @@ export abstract class CodeGen implements ICodeGen { argList(indent: string, args: Arg[], prefix?: string) { prefix = prefix || ''; + const names = args.map(a => this.reserve(a)); return args && args.length !== 0 - ? `${indent}${prefix}${args.join(this.argDelimiter + prefix)}` + ? `${indent}${prefix}${names.join(this.argDelimiter + prefix)}` : this.nullStr; } @@ -1301,7 +1302,7 @@ export abstract class CodeGen implements ICodeGen { // Don't append trailing optional arguments if none have been set yet return ''; } - return `${args}${current ? this.argDelimiter : ''}${current}`; + return `${args}${current ? this.argDelimiter : ''}${this.reserve(current)}`; } httpPath(path: string, _prefix?: string) { diff --git a/packages/sdk-codegen/src/csharp.gen.spec.ts b/packages/sdk-codegen/src/csharp.gen.spec.ts index 95bfc357e..f472bb705 100644 --- a/packages/sdk-codegen/src/csharp.gen.spec.ts +++ b/packages/sdk-codegen/src/csharp.gen.spec.ts @@ -242,6 +242,47 @@ public async Task> run_sql_query( result_format = SdkUtils.EncodeParam(result_format); return await AuthRequest(HttpMethod.Post, $"/sql_queries/{slug}/run/{result_format}", new Values { { "download", download }},null,options); +}`; + const actual = gen.declareMethod(indent, method); + expect(actual).toEqual(expected); + }); + it('generates bug work around syntax for HttpMethod.Patch', () => { + const method = apiTestModel.methods.update_ssh_server; + const expected = `public async Task> update_ssh_server( + string ssh_server_id, + WriteSshServer body, + ITransportSettings? options = null) +{ + ssh_server_id = SdkUtils.EncodeParam(ssh_server_id); + return await AuthRequest(new HttpMethod("PATCH"), $"/ssh_server/{ssh_server_id}", null,body,options); +}`; + gen.noComment = true; + const actual = gen.declareMethod(indent, method); + gen.noComment = false; + expect(actual).toEqual(expected); + }); + it('escapes namespace as a reserved word', () => { + const method = apiTestModel.methods.delete_artifact; + const expected = `/// ### Delete one or more artifacts +/// +/// To avoid rate limiting on deletion requests, multiple artifacts can be deleted at the same time by using a comma-delimited list of artifact keys. +/// +/// **Note**: The artifact storage API can only be used by Looker-built extensions. +/// +/// DELETE /artifact/{namespace} -> void +/// +/// void The artifact is deleted. () +/// +/// Artifact storage namespace +/// Comma-delimited list of keys. Wildcards not allowed. +public async Task> delete_artifact( + string @namespace, + string key, + ITransportSettings? options = null) +{ + @namespace = SdkUtils.EncodeParam(@namespace); + return await AuthRequest(HttpMethod.Delete, $"/artifact/{@namespace}", new Values { + { "key", key }},null,options); }`; const actual = gen.declareMethod(indent, method); expect(actual).toEqual(expected); diff --git a/packages/sdk-codegen/src/csharp.gen.ts b/packages/sdk-codegen/src/csharp.gen.ts index 53ea20420..7cf67f277 100644 --- a/packages/sdk-codegen/src/csharp.gen.ts +++ b/packages/sdk-codegen/src/csharp.gen.ts @@ -122,7 +122,7 @@ const reservedWords = new Set([ */ export class CSharpGen extends CodeGen { codePath = './csharp'; - packagePath = ''; + packagePath = '/LookerSdk'; itself = 'this'; fileExtension = '.cs'; commentStr = '// '; @@ -139,6 +139,11 @@ export class CSharpGen extends CodeGen { willItStream = false; codeQuote = '"'; + // sdkFileName(baseFileName: string) { + // // return this.fileName(`sdk/${baseFileName}${this.apiRef}`) + // return this.fileName(`LookerSdk/${baseFileName}`); + // } + commentHeader(indent: string, text: string | undefined) { if (this.noComment) return ''; return text ? `${commentBlock(text, indent, '/// ')}\n` : ''; @@ -310,10 +315,16 @@ namespace Looker.SDK.API${this.apiRef} httpPath(path: string, prefix?: string) { prefix = prefix || ''; + let dollah = ''; if (path.indexOf('{') >= 0) { - return `$"${path.replace(/{/gi, '{' + prefix)}"`; + dollah = '$'; + const rx = /{?(\w+)}/gm; + path = path.replace(rx, a => { + const arg = a.substring(1, a.length - 1); + return `${prefix}{${this.reserve(arg)}}`; + }); } - return `'${path}'`; + return `${dollah}"${path}"`; } declareMethod(indent: string, method: IMethod) { @@ -356,14 +367,16 @@ namespace Looker.SDK.API${this.apiRef} httpCall(indent: string, method: IMethod) { const bump = indent + this.indentStr; const args = this.httpArgs(bump, method); - const dollah = method.pathArgs.length ? '$' : ''; // const errors = `(${this.errorResponses(indent, method)})` const bits = this.genericBits(method); - const fragment = `AuthRequest<${ - bits.success - }, Exception>(HttpMethod.${firstCase(method.httpMethod)}, ${dollah}"${ - method.endpoint - }"${args ? ', ' + args : ''})`; + const http = + method.httpMethod === 'PATCH' + ? 'new HttpMethod("PATCH")' + : `HttpMethod.${firstCase(method.httpMethod)}`; + const path = this.httpPath(method.endpoint); + const fragment = `AuthRequest<${bits.success}, Exception>(${http}, ${path}${ + args ? ', ' + args : '' + })`; return `${indent}return await ${fragment};`; } @@ -373,7 +386,8 @@ namespace Looker.SDK.API${this.apiRef} if (method.pathParams.length > 0) { for (const param of method.pathParams) { if (param.doEncode()) { - encodings += `${bump}${param.name} = SdkUtils.EncodeParam(${param.name});\n`; + const name = this.reserve(param.name); + encodings += `${bump}${name} = SdkUtils.EncodeParam(${name});\n`; } } } @@ -391,7 +405,9 @@ namespace Looker.SDK.API${this.apiRef} paramComment(param: IParameter) { return param.description - ? `\n${describeParam(param)}` + ? `\n${describeParam( + param + )}` : ''; } diff --git a/spec/Looker.4.0.json b/spec/Looker.4.0.json index a8d3ab3a9..afec51b1e 100644 --- a/spec/Looker.4.0.json +++ b/spec/Looker.4.0.json @@ -1,8 +1,8 @@ { "swagger": "2.0", "info": { - "version": "4.0.24.18", - "x-looker-release-version": "24.18.48", + "version": "4.0.24.20", + "x-looker-release-version": "24.20.12", "title": "Looker API 4.0 Reference", "description": "\nAPI 4.0 is the current release of the Looker API. API 3.x has been removed.\n\n### Authorization\n\nThe classic method of API authorization uses Looker **API** credentials for authorization and access control.\nLooker admins can create API credentials on Looker's **Admin/Users** page.\n\nAPI 4.0 adds additional ways to authenticate API requests, including OAuth and CORS requests.\n\nFor details, see [Looker API Authorization](https://cloud.google.com/looker/docs/r/api/authorization).\n\n\n### API Explorer\n\nThe API Explorer is a Looker-provided utility with many new and unique features for learning and using the Looker API and SDKs.\n\nFor details, see the [API Explorer documentation](https://cloud.google.com/looker/docs/r/api/explorer).\n\n\n### Looker Language SDKs\n\nThe Looker API is a RESTful system that should be usable by any programming language capable of making\nHTTPS requests. SDKs for a variety of programming languages are also provided to streamline using the API. Looker\nhas an OpenSource [sdk-codegen project](https://github.com/looker-open-source/sdk-codegen) that provides several\nlanguage SDKs. Language SDKs generated by `sdk-codegen` have an Authentication manager that can automatically\nauthenticate API requests when needed.\n\nFor details on available Looker SDKs, see [Looker API Client SDKs](https://cloud.google.com/looker/docs/r/api/client_sdks).\n\n\n### API Versioning\n\nFuture releases of Looker expand the latest API version release-by-release to securely expose more and more of the core\npower of the Looker platform to API client applications. API endpoints marked as \"beta\" may receive breaking changes without\nwarning (but we will try to avoid doing that). Stable (non-beta) API endpoints should not receive breaking\nchanges in future releases.\n\nFor details, see [Looker API Versioning](https://cloud.google.com/looker/docs/r/api/versioning).\n\n\n### In This Release\n\nAPI 4.0 is the only supported API version for Looker starting with release 23.18. API 3.0 and 3.1 have been removed.\n\nAPI 4.0 has better support for strongly typed languages like TypeScript, Kotlin, Swift, Go, C#, and more.\n\nSee the [API 4.0 GA announcement](https://developers.looker.com/api/advanced-usage/version-4-ga) for more information\nabout API 4.0.\n\nThe API Explorer can be used to [interactively compare](https://cloud.google.com/looker/docs/r/api/explorer#comparing_api_versions) the differences between API 3.1 and 4.0.\n\n\n### API and SDK Support Policies\n\nLooker API versions and language SDKs have varying support levels. Please read the API and SDK\n[support policies](https://cloud.google.com/looker/docs/r/api/support-policy) for more information.\n\n\n", "contact": { @@ -27271,6 +27271,12 @@ "$ref": "#/definitions/Error" } }, + "422": { + "description": "Validation Error", + "schema": { + "$ref": "#/definitions/ValidationError" + } + }, "429": { "description": "Too Many Requests", "schema": { @@ -39386,7 +39392,7 @@ }, "limit": { "type": "string", - "description": "Limit", + "description": "Row limit. To download unlimited results, set the limit to -1 (negative one).", "x-looker-nullable": true }, "column_limit": { diff --git a/spec/Looker.4.0.oas.json b/spec/Looker.4.0.oas.json index d9ec94240..1c5ef9671 100644 --- a/spec/Looker.4.0.oas.json +++ b/spec/Looker.4.0.oas.json @@ -1,8 +1,8 @@ { "openapi": "3.0.0", "info": { - "version": "4.0.24.18", - "x-looker-release-version": "24.18.48", + "version": "4.0.24.20", + "x-looker-release-version": "24.20.12", "title": "Looker API 4.0 Reference", "description": "\nAPI 4.0 is the current release of the Looker API. API 3.x has been removed.\n\n### Authorization\n\nThe classic method of API authorization uses Looker **API** credentials for authorization and access control.\nLooker admins can create API credentials on Looker's **Admin/Users** page.\n\nAPI 4.0 adds additional ways to authenticate API requests, including OAuth and CORS requests.\n\nFor details, see [Looker API Authorization](https://cloud.google.com/looker/docs/r/api/authorization).\n\n\n### API Explorer\n\nThe API Explorer is a Looker-provided utility with many new and unique features for learning and using the Looker API and SDKs.\n\nFor details, see the [API Explorer documentation](https://cloud.google.com/looker/docs/r/api/explorer).\n\n\n### Looker Language SDKs\n\nThe Looker API is a RESTful system that should be usable by any programming language capable of making\nHTTPS requests. SDKs for a variety of programming languages are also provided to streamline using the API. Looker\nhas an OpenSource [sdk-codegen project](https://github.com/looker-open-source/sdk-codegen) that provides several\nlanguage SDKs. Language SDKs generated by `sdk-codegen` have an Authentication manager that can automatically\nauthenticate API requests when needed.\n\nFor details on available Looker SDKs, see [Looker API Client SDKs](https://cloud.google.com/looker/docs/r/api/client_sdks).\n\n\n### API Versioning\n\nFuture releases of Looker expand the latest API version release-by-release to securely expose more and more of the core\npower of the Looker platform to API client applications. API endpoints marked as \"beta\" may receive breaking changes without\nwarning (but we will try to avoid doing that). Stable (non-beta) API endpoints should not receive breaking\nchanges in future releases.\n\nFor details, see [Looker API Versioning](https://cloud.google.com/looker/docs/r/api/versioning).\n\n\n### In This Release\n\nAPI 4.0 is the only supported API version for Looker starting with release 23.18. API 3.0 and 3.1 have been removed.\n\nAPI 4.0 has better support for strongly typed languages like TypeScript, Kotlin, Swift, Go, C#, and more.\n\nSee the [API 4.0 GA announcement](https://developers.looker.com/api/advanced-usage/version-4-ga) for more information\nabout API 4.0.\n\nThe API Explorer can be used to [interactively compare](https://cloud.google.com/looker/docs/r/api/explorer#comparing_api_versions) the differences between API 3.1 and 4.0.\n\n\n### API and SDK Support Policies\n\nLooker API versions and language SDKs have varying support levels. Please read the API and SDK\n[support policies](https://cloud.google.com/looker/docs/r/api/support-policy) for more information.\n\n\n", "contact": { @@ -37683,6 +37683,16 @@ } } }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + }, "429": { "description": "Too Many Requests", "content": { @@ -49973,7 +49983,7 @@ }, "limit": { "type": "string", - "description": "Limit", + "description": "Row limit. To download unlimited results, set the limit to -1 (negative one).", "nullable": true }, "column_limit": {