diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fc7470505..611128b4a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'csharp', 'go', 'java', 'node', 'php', 'python', 'ruby' ] + language: ['java' ] runs-on: ubuntu-latest timeout-minutes: 20 env: diff --git a/examples/csharp/src/Twilio/Rest/Api/V2010/Account/Call/FeedbackCallSummaryResource.cs b/examples/csharp/src/Twilio/Rest/Api/V2010/Account/Call/FeedbackCallSummaryResource.cs index d211831c7..fda3d2947 100644 --- a/examples/csharp/src/Twilio/Rest/Api/V2010/Account/Call/FeedbackCallSummaryResource.cs +++ b/examples/csharp/src/Twilio/Rest/Api/V2010/Account/Call/FeedbackCallSummaryResource.cs @@ -56,10 +56,10 @@ private static Request BuildUpdateRequest(UpdateFeedbackCallSummaryOptions optio string path = "/2010-04-01/Accounts/{AccountSid}/Calls/Feedback/Summary/{Sid}.json"; - string PathAccountSid = options.PathAccountSid ?? client.AccountSid; - path = path.Replace("{"+"AccountSid"+"}", PathAccountSid); string PathSid = options.PathSid; path = path.Replace("{"+"Sid"+"}", PathSid); + string PathAccountSid = options.PathAccountSid ?? client.AccountSid; + path = path.Replace("{"+"AccountSid"+"}", PathAccountSid); return new Request( HttpMethod.Post, @@ -137,6 +137,7 @@ public static async System.Threading.Tasks.Task Upd return await UpdateAsync(options, client); } #endif + /// /// Converts a JSON string into a FeedbackCallSummaryResource object diff --git a/examples/csharp/src/Twilio/Rest/Api/V2010/Account/CallOptions.cs b/examples/csharp/src/Twilio/Rest/Api/V2010/Account/CallOptions.cs index 473d9ab82..2c2630983 100644 --- a/examples/csharp/src/Twilio/Rest/Api/V2010/Account/CallOptions.cs +++ b/examples/csharp/src/Twilio/Rest/Api/V2010/Account/CallOptions.cs @@ -83,6 +83,7 @@ public List> GetParams() } + /// delete public class DeleteCallOptions : IOptions { diff --git a/examples/csharp/src/Twilio/Rest/Api/V2010/Account/CallResource.cs b/examples/csharp/src/Twilio/Rest/Api/V2010/Account/CallResource.cs index ad0d34fd9..f7a3f1e8d 100644 --- a/examples/csharp/src/Twilio/Rest/Api/V2010/Account/CallResource.cs +++ b/examples/csharp/src/Twilio/Rest/Api/V2010/Account/CallResource.cs @@ -134,6 +134,7 @@ public static async System.Threading.Tasks.Task CreateAsync( return await CreateAsync(options, client); } #endif + /// delete /// Delete Call parameters @@ -144,10 +145,10 @@ private static Request BuildDeleteRequest(DeleteCallOptions options, ITwilioRest string path = "/2010-04-01/Accounts/{AccountSid}/Calls/{TestInteger}.json"; - string PathAccountSid = options.PathAccountSid ?? client.AccountSid; - path = path.Replace("{"+"AccountSid"+"}", PathAccountSid); string PathTestInteger = options.PathTestInteger.ToString(); path = path.Replace("{"+"TestInteger"+"}", PathTestInteger); + string PathAccountSid = options.PathAccountSid ?? client.AccountSid; + path = path.Replace("{"+"AccountSid"+"}", PathAccountSid); return new Request( HttpMethod.Delete, @@ -212,10 +213,10 @@ private static Request BuildFetchRequest(FetchCallOptions options, ITwilioRestCl string path = "/2010-04-01/Accounts/{AccountSid}/Calls/{TestInteger}.json"; - string PathAccountSid = options.PathAccountSid ?? client.AccountSid; - path = path.Replace("{"+"AccountSid"+"}", PathAccountSid); string PathTestInteger = options.PathTestInteger.ToString(); path = path.Replace("{"+"TestInteger"+"}", PathTestInteger); + string PathAccountSid = options.PathAccountSid ?? client.AccountSid; + path = path.Replace("{"+"AccountSid"+"}", PathAccountSid); return new Request( HttpMethod.Get, diff --git a/examples/csharp/src/Twilio/Rest/Api/V2010/AccountOptions.cs b/examples/csharp/src/Twilio/Rest/Api/V2010/AccountOptions.cs index 5c85f5db3..cf70d8ec8 100644 --- a/examples/csharp/src/Twilio/Rest/Api/V2010/AccountOptions.cs +++ b/examples/csharp/src/Twilio/Rest/Api/V2010/AccountOptions.cs @@ -76,6 +76,7 @@ public List> GetHeaderParams() } } + /// delete public class DeleteAccountOptions : IOptions { diff --git a/examples/csharp/src/Twilio/Rest/Api/V2010/AccountResource.cs b/examples/csharp/src/Twilio/Rest/Api/V2010/AccountResource.cs index 2aeda8a82..0274555bc 100644 --- a/examples/csharp/src/Twilio/Rest/Api/V2010/AccountResource.cs +++ b/examples/csharp/src/Twilio/Rest/Api/V2010/AccountResource.cs @@ -140,6 +140,7 @@ public static async System.Threading.Tasks.Task CreateAsync( return await CreateAsync(options, client); } #endif + /// delete /// Delete Account parameters @@ -484,6 +485,7 @@ public static async System.Threading.Tasks.Task UpdateAsync( return await UpdateAsync(options, client); } #endif + /// /// Converts a JSON string into a AccountResource object diff --git a/examples/csharp/src/Twilio/Rest/FlexApi/V1/CallResource.cs b/examples/csharp/src/Twilio/Rest/FlexApi/V1/CallResource.cs index bbe77b31f..93dfac837 100644 --- a/examples/csharp/src/Twilio/Rest/FlexApi/V1/CallResource.cs +++ b/examples/csharp/src/Twilio/Rest/FlexApi/V1/CallResource.cs @@ -102,6 +102,7 @@ public static async System.Threading.Tasks.Task UpdateAsync( return await UpdateAsync(options, client); } #endif + /// /// Converts a JSON string into a CallResource object diff --git a/examples/csharp/src/Twilio/Rest/FlexApi/V1/Credential/AwsResource.cs b/examples/csharp/src/Twilio/Rest/FlexApi/V1/Credential/AwsResource.cs index fbbdf9632..b383fd4c6 100644 --- a/examples/csharp/src/Twilio/Rest/FlexApi/V1/Credential/AwsResource.cs +++ b/examples/csharp/src/Twilio/Rest/FlexApi/V1/Credential/AwsResource.cs @@ -361,6 +361,7 @@ public static async System.Threading.Tasks.Task UpdateAsync( return await UpdateAsync(options, client); } #endif + /// /// Converts a JSON string into a AwsResource object diff --git a/examples/csharp/src/Twilio/Rest/FlexApi/V1/Credential/NewCredentialsOptions.cs b/examples/csharp/src/Twilio/Rest/FlexApi/V1/Credential/NewCredentialsOptions.cs index 413652c42..90a3b3835 100644 --- a/examples/csharp/src/Twilio/Rest/FlexApi/V1/Credential/NewCredentialsOptions.cs +++ b/examples/csharp/src/Twilio/Rest/FlexApi/V1/Credential/NewCredentialsOptions.cs @@ -41,10 +41,10 @@ public class CreateNewCredentialsOptions : IOptions public decimal? TestNumber { get; set; } - public float? TestNumberFloat { get; set; } + public float TestNumberFloat { get; set; } - public double? TestNumberDouble { get; set; } + public double TestNumberDouble { get; set; } public decimal? TestNumberInt32 { get; set; } @@ -170,5 +170,6 @@ public List> GetParams() } + } diff --git a/examples/csharp/src/Twilio/Rest/FlexApi/V1/Credential/NewCredentialsResource.cs b/examples/csharp/src/Twilio/Rest/FlexApi/V1/Credential/NewCredentialsResource.cs index 515501877..70bd7182f 100644 --- a/examples/csharp/src/Twilio/Rest/FlexApi/V1/Credential/NewCredentialsResource.cs +++ b/examples/csharp/src/Twilio/Rest/FlexApi/V1/Credential/NewCredentialsResource.cs @@ -126,11 +126,11 @@ public static NewCredentialsResource Create( string testString, int? testInteger = null, DateTime? testDate = null, - float? testNumberFloat = null, + float testNumberFloat = null, object testObject = null, bool? testBoolean = null, decimal? testNumber = null, - double? testNumberDouble = null, + double testNumberDouble = null, decimal? testNumberInt32 = null, long? testNumberInt64 = null, DateTime? testDateTime = null, @@ -171,11 +171,11 @@ public static async System.Threading.Tasks.Task CreateAs string testString, int? testInteger = null, DateTime? testDate = null, - float? testNumberFloat = null, + float testNumberFloat = null, object testObject = null, bool? testBoolean = null, decimal? testNumber = null, - double? testNumberDouble = null, + double testNumberDouble = null, decimal? testNumberInt32 = null, long? testNumberInt64 = null, DateTime? testDateTime = null, @@ -191,6 +191,7 @@ public static async System.Threading.Tasks.Task CreateAs return await CreateAsync(options, client); } #endif + /// /// Converts a JSON string into a NewCredentialsResource object diff --git a/examples/csharp/src/Twilio/Rest/PreviewIam/Organizations/UserOptions.cs b/examples/csharp/src/Twilio/Rest/PreviewIam/Organizations/UserOptions.cs deleted file mode 100644 index 745105eac..000000000 --- a/examples/csharp/src/Twilio/Rest/PreviewIam/Organizations/UserOptions.cs +++ /dev/null @@ -1,225 +0,0 @@ -/* - * This code was generated by - * ___ _ _ _ _ _ _ ____ ____ ____ _ ____ ____ _ _ ____ ____ ____ ___ __ __ - * | | | | | | | | | __ | | |__| | __ | __ |___ |\ | |___ |__/ |__| | | | |__/ - * | |_|_| | |___ | |__| |__| | | | |__] |___ | \| |___ | \ | | | |__| | \ - * - * Organization Public API - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * NOTE: This class is auto generated by OpenAPI Generator. - * https://openapi-generator.tech - * Do not edit the class manually. - */ - - -using System; -using System.Collections.Generic; -using Twilio.Base; -using Twilio.Converters; - - - - -namespace Twilio.Rest.PreviewIam.Organizations -{ - - /// create - public class CreateUserOptions : IOptions - { - - - public string PathOrganizationSid { get; } - - - public UserResource.ScimUser ScimUser { get; } - - - /// Construct a new CreateOrganizationUserOptions - /// - /// - public CreateUserOptions(string pathOrganizationSid, UserResource.ScimUser scimUser) - { - PathOrganizationSid = pathOrganizationSid; - ScimUser = scimUser; - } - - - /// Generate the request body - public string GetBody() - { - string body = ""; - - if (ScimUser != null) - { - body = UserResource.ToJson(ScimUser); - } - return body; - } - - - } - /// delete - public class DeleteUserOptions : IOptions - { - - - public string PathOrganizationSid { get; } - - - public string PathUserSid { get; } - - - - /// Construct a new DeleteOrganizationUserOptions - /// - /// - public DeleteUserOptions(string pathOrganizationSid, string pathUserSid) - { - PathOrganizationSid = pathOrganizationSid; - PathUserSid = pathUserSid; - } - - - /// Generate the necessary parameters - public List> GetParams() - { - var p = new List>(); - - return p; - } - - - - } - - - /// fetch - public class FetchUserOptions : IOptions - { - - - public string PathOrganizationSid { get; } - - - public string PathUserSid { get; } - - - - /// Construct a new FetchOrganizationUserOptions - /// - /// - public FetchUserOptions(string pathOrganizationSid, string pathUserSid) - { - PathOrganizationSid = pathOrganizationSid; - PathUserSid = pathUserSid; - } - - - /// Generate the necessary parameters - public List> GetParams() - { - var p = new List>(); - - return p; - } - - - - } - - - /// read - public class ReadUserOptions : ReadOptions - { - - - public string PathOrganizationSid { get; } - - - public string Filter { get; set; } - - - - /// Construct a new ListOrganizationUsersOptions - /// - public ReadUserOptions(string pathOrganizationSid) - { - PathOrganizationSid = pathOrganizationSid; - } - - - /// Generate the necessary parameters - public List> GetParams() - { - var p = new List>(); - - if (Filter != null) - { - p.Add(new KeyValuePair("filter", Filter)); - } - return p; - } - - - - } - - /// update - public class UpdateUserOptions : IOptions - { - - - public string PathOrganizationSid { get; } - - - public string PathUserSid { get; } - - - public UserResource.ScimUser ScimUser { get; } - - - public string IfMatch { get; set; } - - - - /// Construct a new UpdateOrganizationUserOptions - /// - /// - /// - public UpdateUserOptions(string pathOrganizationSid, string pathUserSid, UserResource.ScimUser scimUser) - { - PathOrganizationSid = pathOrganizationSid; - PathUserSid = pathUserSid; - ScimUser = scimUser; - } - - - /// Generate the request body - public string GetBody() - { - string body = ""; - - if (ScimUser != null) - { - body = UserResource.ToJson(ScimUser); - } - return body; - } - - /// Generate the necessary header parameters - public List> GetHeaderParams() - { - var p = new List>(); - if (IfMatch != null) - { - p.Add(new KeyValuePair("If-Match", IfMatch)); - } - return p; - } - - } - - -} - diff --git a/examples/csharp/src/Twilio/Rest/PreviewIam/Organizations/UserResource.cs b/examples/csharp/src/Twilio/Rest/PreviewIam/Organizations/UserResource.cs deleted file mode 100644 index dfc6671c5..000000000 --- a/examples/csharp/src/Twilio/Rest/PreviewIam/Organizations/UserResource.cs +++ /dev/null @@ -1,752 +0,0 @@ -/* - * This code was generated by - * ___ _ _ _ _ _ _ ____ ____ ____ _ ____ ____ _ _ ____ ____ ____ ___ __ __ - * | | | | | | | | | __ | | |__| | __ | __ |___ |\ | |___ |__/ |__| | | | |__/ - * | |_|_| | |___ | |__| |__| | | | |__] |___ | \| |___ | \ | | | |__| | \ - * - * Organization Public API - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * NOTE: This class is auto generated by OpenAPI Generator. - * https://openapi-generator.tech - * Do not edit the class manually. - */ - - -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using Twilio.Base; -using Twilio.Clients; -using Twilio.Constant; -using Twilio.Converters; -using Twilio.Exceptions; -using Twilio.Http; - - - -namespace Twilio.Rest.PreviewIam.Organizations -{ - public class UserResource : Resource - { - - public class ScimName - { - [JsonProperty("givenName")] - private string GivenName {get; set;} - [JsonProperty("familyName")] - private string FamilyName {get; set;} - [JsonProperty("TestAnyType")] - private object TestAnyType {get; set;} - public ScimName() { } - public class Builder - { - private ScimName _scimName = new ScimName(); - public Builder() - { - } - public Builder WithGivenName(string givenName) - { - _scimName.GivenName= givenName; - return this; - } - public Builder WithFamilyName(string familyName) - { - _scimName.FamilyName= familyName; - return this; - } - public Builder WithTestAnyType(object testAnyType) - { - _scimName.TestAnyType= testAnyType; - return this; - } - public ScimName Build() - { - return _scimName; - } - } - } - public class ScimEmailAddress - { - [JsonProperty("primary")] - private bool? Primary {get; set;} - [JsonProperty("value")] - private string Value {get; set;} - [JsonProperty("type")] - private string Type {get; set;} - public ScimEmailAddress() { } - public class Builder - { - private ScimEmailAddress _scimEmailAddress = new ScimEmailAddress(); - public Builder() - { - } - public Builder WithPrimary(bool? primary) - { - _scimEmailAddress.Primary= primary; - return this; - } - public Builder WithValue(string value) - { - _scimEmailAddress.Value= value; - return this; - } - public Builder WithType(string type) - { - _scimEmailAddress.Type= type; - return this; - } - public ScimEmailAddress Build() - { - return _scimEmailAddress; - } - } - } - public class ScimMeta - { - [JsonProperty("resourceType")] - private string ResourceType {get; set;} - [JsonProperty("created")] - private DateTime? Created {get; set;} - [JsonProperty("lastModified")] - private DateTime? LastModified {get; set;} - [JsonProperty("version")] - private string Version {get; set;} - public ScimMeta() { } - public class Builder - { - private ScimMeta _scimMeta = new ScimMeta(); - public Builder() - { - } - public Builder WithResourceType(string resourceType) - { - _scimMeta.ResourceType= resourceType; - return this; - } - public Builder WithCreated(DateTime? created) - { - _scimMeta.Created= created; - return this; - } - public Builder WithLastModified(DateTime? lastModified) - { - _scimMeta.LastModified= lastModified; - return this; - } - public Builder WithVersion(string version) - { - _scimMeta.Version= version; - return this; - } - public ScimMeta Build() - { - return _scimMeta; - } - } - } - public class ScimUser - { - [JsonProperty("id")] - private string Id {get; set;} - [JsonProperty("externalId")] - private string ExternalId {get; set;} - [JsonProperty("userName")] - private string UserName {get; set;} - [JsonProperty("displayName")] - private string DisplayName {get; set;} - [JsonProperty("name")] - private ScimName Name {get; set;} - [JsonProperty("emails")] - private List Emails {get; set;} - [JsonProperty("active")] - private bool? Active {get; set;} - [JsonProperty("locale")] - private string Locale {get; set;} - [JsonProperty("timezone")] - private string Timezone {get; set;} - [JsonProperty("schemas")] - private List Schemas {get; set;} - [JsonProperty("meta")] - private ScimMeta Meta {get; set;} - public ScimUser() { } - public class Builder - { - private ScimUser _scimUser = new ScimUser(); - public Builder() - { - } - public Builder WithId(string id) - { - _scimUser.Id= id; - return this; - } - public Builder WithExternalId(string externalId) - { - _scimUser.ExternalId= externalId; - return this; - } - public Builder WithUserName(string userName) - { - _scimUser.UserName= userName; - return this; - } - public Builder WithDisplayName(string displayName) - { - _scimUser.DisplayName= displayName; - return this; - } - public Builder WithName(ScimName name) - { - _scimUser.Name= name; - return this; - } - public Builder WithEmails(List emails) - { - _scimUser.Emails= emails; - return this; - } - public Builder WithActive(bool? active) - { - _scimUser.Active= active; - return this; - } - public Builder WithLocale(string locale) - { - _scimUser.Locale= locale; - return this; - } - public Builder WithTimezone(string timezone) - { - _scimUser.Timezone= timezone; - return this; - } - public Builder WithSchemas(List schemas) - { - _scimUser.Schemas= schemas; - return this; - } - public Builder WithMeta(ScimMeta meta) - { - _scimUser.Meta= meta; - return this; - } - public ScimUser Build() - { - return _scimUser; - } - } - } - - - - - private static Request BuildCreateRequest(CreateUserOptions options, ITwilioRestClient client) - { - - string path = "/Organizations/{organizationSid}/scim/Users"; - - string PathOrganizationSid = options.PathOrganizationSid.ToString(); - path = path.Replace("{"+"organizationSid"+"}", PathOrganizationSid); - - return new Request( - HttpMethod.Post, - Rest.Domain.PreviewIam, - path, - - contentType: EnumConstants.ContentTypeEnum.JSON, - body: options.GetBody(), - headerParams: null - ); - } - - /// create - /// Create User parameters - /// Client to make requests to Twilio - /// A single instance of User - public static UserResource Create(CreateUserOptions options, ITwilioRestClient client = null) - { - client = client ?? TwilioClient.GetRestClient(); - var response = client.Request(BuildCreateRequest(options, client)); - return FromJson(response.Content); - } - - #if !NET35 - /// create - /// Create User parameters - /// Client to make requests to Twilio - /// Task that resolves to A single instance of User - public static async System.Threading.Tasks.Task CreateAsync(CreateUserOptions options, ITwilioRestClient client = null) - { - client = client ?? TwilioClient.GetRestClient(); - var response = await client.RequestAsync(BuildCreateRequest(options, client)); - return FromJson(response.Content); - } - #endif - - /// create - /// - /// - /// Client to make requests to Twilio - /// A single instance of User - public static UserResource Create( - string pathOrganizationSid, - UserResource.ScimUser scimUser, - ITwilioRestClient client = null) - { - var options = new CreateUserOptions(pathOrganizationSid, scimUser){ }; - return Create(options, client); - } - - #if !NET35 - /// create - /// - /// - /// Client to make requests to Twilio - /// Task that resolves to A single instance of User - public static async System.Threading.Tasks.Task CreateAsync( - string pathOrganizationSid, - UserResource.ScimUser scimUser, - ITwilioRestClient client = null) - { - var options = new CreateUserOptions(pathOrganizationSid, scimUser){ }; - return await CreateAsync(options, client); - } - #endif - - /// delete - /// Delete User parameters - /// Client to make requests to Twilio - /// A single instance of User - private static Request BuildDeleteRequest(DeleteUserOptions options, ITwilioRestClient client) - { - - string path = "/Organizations/{organizationSid}/scim/Users/{userSid}"; - - string PathOrganizationSid = options.PathOrganizationSid.ToString(); - path = path.Replace("{"+"organizationSid"+"}", PathOrganizationSid); - string PathUserSid = options.PathUserSid.ToString(); - path = path.Replace("{"+"userSid"+"}", PathUserSid); - - return new Request( - HttpMethod.Delete, - Rest.Domain.PreviewIam, - path, - queryParams: options.GetParams(), - headerParams: null - ); - } - - /// delete - /// Delete User parameters - /// Client to make requests to Twilio - /// A single instance of User - public static bool Delete(DeleteUserOptions options, ITwilioRestClient client = null) - { - client = client ?? TwilioClient.GetRestClient(); - var response = client.Request(BuildDeleteRequest(options, client)); - return response.StatusCode == System.Net.HttpStatusCode.NoContent; - } - - #if !NET35 - /// delete - /// Delete User parameters - /// Client to make requests to Twilio - /// Task that resolves to A single instance of User - public static async System.Threading.Tasks.Task DeleteAsync(DeleteUserOptions options, - ITwilioRestClient client = null) - { - client = client ?? TwilioClient.GetRestClient(); - var response = await client.RequestAsync(BuildDeleteRequest(options, client)); - return response.StatusCode == System.Net.HttpStatusCode.NoContent; - } - #endif - - /// delete - /// - /// - /// Client to make requests to Twilio - /// A single instance of User - public static bool Delete(string pathOrganizationSid, string pathUserSid, ITwilioRestClient client = null) - { - var options = new DeleteUserOptions(pathOrganizationSid, pathUserSid) ; - return Delete(options, client); - } - - #if !NET35 - /// delete - /// - /// - /// Client to make requests to Twilio - /// Task that resolves to A single instance of User - public static async System.Threading.Tasks.Task DeleteAsync(string pathOrganizationSid, string pathUserSid, ITwilioRestClient client = null) - { - var options = new DeleteUserOptions(pathOrganizationSid, pathUserSid) ; - return await DeleteAsync(options, client); - } - #endif - - private static Request BuildFetchRequest(FetchUserOptions options, ITwilioRestClient client) - { - - string path = "/Organizations/{organizationSid}/scim/Users/{userSid}"; - - string PathOrganizationSid = options.PathOrganizationSid.ToString(); - path = path.Replace("{"+"organizationSid"+"}", PathOrganizationSid); - string PathUserSid = options.PathUserSid.ToString(); - path = path.Replace("{"+"userSid"+"}", PathUserSid); - - return new Request( - HttpMethod.Get, - Rest.Domain.PreviewIam, - path, - queryParams: options.GetParams(), - headerParams: null - ); - } - - /// fetch - /// Fetch User parameters - /// Client to make requests to Twilio - /// A single instance of User - public static UserResource Fetch(FetchUserOptions options, ITwilioRestClient client = null) - { - client = client ?? TwilioClient.GetRestClient(); - var response = client.Request(BuildFetchRequest(options, client)); - return FromJson(response.Content); - } - - #if !NET35 - /// fetch - /// Fetch User parameters - /// Client to make requests to Twilio - /// Task that resolves to A single instance of User - public static async System.Threading.Tasks.Task FetchAsync(FetchUserOptions options, ITwilioRestClient client = null) - { - client = client ?? TwilioClient.GetRestClient(); - var response = await client.RequestAsync(BuildFetchRequest(options, client)); - return FromJson(response.Content); - } - #endif - /// fetch - /// - /// - /// Client to make requests to Twilio - /// A single instance of User - public static UserResource Fetch( - string pathOrganizationSid, - string pathUserSid, - ITwilioRestClient client = null) - { - var options = new FetchUserOptions(pathOrganizationSid, pathUserSid){ }; - return Fetch(options, client); - } - - #if !NET35 - /// fetch - /// - /// - /// Client to make requests to Twilio - /// Task that resolves to A single instance of User - public static async System.Threading.Tasks.Task FetchAsync(string pathOrganizationSid, string pathUserSid, ITwilioRestClient client = null) - { - var options = new FetchUserOptions(pathOrganizationSid, pathUserSid){ }; - return await FetchAsync(options, client); - } - #endif - - private static Request BuildReadRequest(ReadUserOptions options, ITwilioRestClient client) - { - - string path = "/Organizations/{organizationSid}/scim/Users"; - - string PathOrganizationSid = options.PathOrganizationSid.ToString(); - path = path.Replace("{"+"organizationSid"+"}", PathOrganizationSid); - - return new Request( - HttpMethod.Get, - Rest.Domain.PreviewIam, - path, - queryParams: options.GetParams(), - headerParams: null - ); - } - /// read - /// Read User parameters - /// Client to make requests to Twilio - /// A single instance of User - public static ResourceSet Read(ReadUserOptions options, ITwilioRestClient client = null) - { - client = client ?? TwilioClient.GetRestClient(); - var response = client.Request(BuildReadRequest(options, client)); - var page = Page.FromJson("Resources", response.Content); - return new ResourceSet(page, options, client); - } - - #if !NET35 - /// read - /// Read User parameters - /// Client to make requests to Twilio - /// Task that resolves to A single instance of User - public static async System.Threading.Tasks.Task> ReadAsync(ReadUserOptions options, ITwilioRestClient client = null) - { - client = client ?? TwilioClient.GetRestClient(); - var response = await client.RequestAsync(BuildReadRequest(options, client)); - - var page = Page.FromJson("Resources", response.Content); - return new ResourceSet(page, options, client); - } - #endif - /// read - /// - /// - /// Record limit - /// Client to make requests to Twilio - /// A single instance of User - public static ResourceSet Read( - string pathOrganizationSid, - string filter = null, - long? limit = null, - ITwilioRestClient client = null) - { - var options = new ReadUserOptions(pathOrganizationSid){ Filter = filter, Limit = limit}; - return Read(options, client); - } - - #if !NET35 - /// read - /// - /// - /// Record limit - /// Client to make requests to Twilio - /// Task that resolves to A single instance of User - public static async System.Threading.Tasks.Task> ReadAsync( - string pathOrganizationSid, - string filter = null, - long? limit = null, - ITwilioRestClient client = null) - { - var options = new ReadUserOptions(pathOrganizationSid){ Filter = filter, Limit = limit}; - return await ReadAsync(options, client); - } - #endif - - - /// Fetch the target page of records - /// API-generated URL for the requested results page - /// Client to make requests to Twilio - /// The target page of records - public static Page GetPage(string targetUrl, ITwilioRestClient client) - { - client = client ?? TwilioClient.GetRestClient(); - - var request = new Request( - HttpMethod.Get, - targetUrl - ); - - var response = client.Request(request); - return Page.FromJson("Resources", response.Content); - } - - /// Fetch the next page of records - /// current page of records - /// Client to make requests to Twilio - /// The next page of records - public static Page NextPage(Page page, ITwilioRestClient client) - { - var request = new Request( - HttpMethod.Get, - page.GetNextPageUrl(Rest.Domain.Api) - ); - - var response = client.Request(request); - return Page.FromJson("Resources", response.Content); - } - - /// Fetch the previous page of records - /// current page of records - /// Client to make requests to Twilio - /// The previous page of records - public static Page PreviousPage(Page page, ITwilioRestClient client) - { - var request = new Request( - HttpMethod.Get, - page.GetPreviousPageUrl(Rest.Domain.Api) - ); - - var response = client.Request(request); - return Page.FromJson("Resources", response.Content); - } - - - private static Request BuildUpdateRequest(UpdateUserOptions options, ITwilioRestClient client) - { - - string path = "/Organizations/{organizationSid}/scim/Users/{userSid}"; - - string PathOrganizationSid = options.PathOrganizationSid.ToString(); - path = path.Replace("{"+"organizationSid"+"}", PathOrganizationSid); - string PathUserSid = options.PathUserSid.ToString(); - path = path.Replace("{"+"userSid"+"}", PathUserSid); - - return new Request( - HttpMethod.Put, - Rest.Domain.PreviewIam, - path, - - contentType: EnumConstants.ContentTypeEnum.JSON, - body: options.GetBody(), - headerParams: options.GetHeaderParams() - ); - } - - /// update - /// Update User parameters - /// Client to make requests to Twilio - /// A single instance of User - public static UserResource Update(UpdateUserOptions options, ITwilioRestClient client = null) - { - client = client ?? TwilioClient.GetRestClient(); - var response = client.Request(BuildUpdateRequest(options, client)); - return FromJson(response.Content); - } - - /// update - /// Update User parameters - /// Client to make requests to Twilio - /// Task that resolves to A single instance of User - #if !NET35 - public static async System.Threading.Tasks.Task UpdateAsync(UpdateUserOptions options, - ITwilioRestClient client = null) - { - client = client ?? TwilioClient.GetRestClient(); - var response = await client.RequestAsync(BuildUpdateRequest(options, client)); - return FromJson(response.Content); - } - #endif - - /// update - /// - /// - /// - /// - /// Client to make requests to Twilio - /// A single instance of User - public static UserResource Update( - string pathOrganizationSid, - string pathUserSid, - UserResource.ScimUser scimUser, - string ifMatch = null, - ITwilioRestClient client = null) - { - var options = new UpdateUserOptions(pathOrganizationSid, pathUserSid, scimUser){ IfMatch = ifMatch }; - return Update(options, client); - } - - #if !NET35 - /// update - /// - /// - /// - /// - /// Client to make requests to Twilio - /// Task that resolves to A single instance of User - public static async System.Threading.Tasks.Task UpdateAsync( - string pathOrganizationSid, - string pathUserSid, - UserResource.ScimUser scimUser, - string ifMatch = null, - ITwilioRestClient client = null) - { - var options = new UpdateUserOptions(pathOrganizationSid, pathUserSid, scimUser){ IfMatch = ifMatch }; - return await UpdateAsync(options, client); - } - #endif - - /// - /// Converts a JSON string into a UserResource object - /// - /// Raw JSON string - /// UserResource object represented by the provided JSON - public static UserResource FromJson(string json) - { - try - { - return JsonConvert.DeserializeObject(json); - } - catch (JsonException e) - { - throw new ApiException(e.Message, e); - } - } - /// - /// Converts an object into a json string - /// - /// C# model - /// JSON string - public static string ToJson(object model) - { - try - { - return JsonConvert.SerializeObject(model); - } - catch (JsonException e) - { - throw new ApiException(e.Message, e); - } - } - - - /// Unique Twilio user sid - [JsonProperty("id")] - public string Id { get; private set; } - - /// External unique resource id defined by provisioning client - [JsonProperty("externalId")] - public string ExternalId { get; private set; } - - /// Unique username, MUST be same as primary email address - [JsonProperty("userName")] - public string UserName { get; } - - /// User friendly display name - [JsonProperty("displayName")] - public string DisplayName { get; private set; } - - /// The name - [JsonProperty("name")] - public ScimName Name { get; private set; } - - /// Email address list of the user. Primary email must be defined if there are more than 1 email. Primary email must match the username. - [JsonProperty("emails")] - public List Emails { get; private set; } - - /// Indicates whether the user is active - [JsonProperty("active")] - public bool? Active { get; private set; } - - /// User's locale - [JsonProperty("locale")] - public string Locale { get; private set; } - - /// User's time zone - [JsonProperty("timezone")] - public string Timezone { get; private set; } - - /// An array of URIs that indicate the schemas supported for this user resource - [JsonProperty("schemas")] - public List Schemas { get; private set; } - - /// The meta - [JsonProperty("meta")] - public ScimMeta Meta { get; private set; } - - - - private UserResource() { - - } - } -} - diff --git a/examples/csharp/src/Twilio/Rest/PreviewIam/V1/TokenOptions.cs b/examples/csharp/src/Twilio/Rest/PreviewIam/V1/TokenOptions.cs deleted file mode 100644 index 95adbbe9f..000000000 --- a/examples/csharp/src/Twilio/Rest/PreviewIam/V1/TokenOptions.cs +++ /dev/null @@ -1,110 +0,0 @@ -/* - * This code was generated by - * ___ _ _ _ _ _ _ ____ ____ ____ _ ____ ____ _ _ ____ ____ ____ ___ __ __ - * | | | | | | | | | __ | | |__| | __ | __ |___ |\ | |___ |__/ |__| | | | |__/ - * | |_|_| | |___ | |__| |__| | | | |__] |___ | \| |___ | \ | | | |__| | \ - * - * Organization Public API - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * NOTE: This class is auto generated by OpenAPI Generator. - * https://openapi-generator.tech - * Do not edit the class manually. - */ - - -using System; -using System.Collections.Generic; -using Twilio.Base; -using Twilio.Converters; - - - - -namespace Twilio.Rest.PreviewIam.V1 -{ - - /// create - public class CreateTokenOptions : IOptions - { - - /// Grant type is a credential representing resource owner's authorization which can be used by client to obtain access token. - public string GrantType { get; } - - /// A 34 character string that uniquely identifies this OAuth App. - public string ClientId { get; } - - /// The credential for confidential OAuth App. - public string ClientSecret { get; set; } - - /// JWT token related to the authorization code grant type. - public string Code { get; set; } - - /// The redirect uri - public string RedirectUri { get; set; } - - /// The targeted audience uri - public string Audience { get; set; } - - /// JWT token related to refresh access token. - public string RefreshToken { get; set; } - - /// The scope of token - public string Scope { get; set; } - - - /// Construct a new CreateTokenOptions - /// Grant type is a credential representing resource owner's authorization which can be used by client to obtain access token. - /// A 34 character string that uniquely identifies this OAuth App. - public CreateTokenOptions(string grantType, string clientId) - { - GrantType = grantType; - ClientId = clientId; - } - - - /// Generate the necessary parameters - public List> GetParams() - { - var p = new List>(); - - if (GrantType != null) - { - p.Add(new KeyValuePair("grant_type", GrantType)); - } - if (ClientId != null) - { - p.Add(new KeyValuePair("client_id", ClientId)); - } - if (ClientSecret != null) - { - p.Add(new KeyValuePair("client_secret", ClientSecret)); - } - if (Code != null) - { - p.Add(new KeyValuePair("code", Code)); - } - if (RedirectUri != null) - { - p.Add(new KeyValuePair("redirect_uri", RedirectUri)); - } - if (Audience != null) - { - p.Add(new KeyValuePair("audience", Audience)); - } - if (RefreshToken != null) - { - p.Add(new KeyValuePair("refresh_token", RefreshToken)); - } - if (Scope != null) - { - p.Add(new KeyValuePair("scope", Scope)); - } - return p; - } - - - - } -} - diff --git a/examples/csharp/src/Twilio/Rest/PreviewIam/V1/TokenResource.cs b/examples/csharp/src/Twilio/Rest/PreviewIam/V1/TokenResource.cs deleted file mode 100644 index 311407ac9..000000000 --- a/examples/csharp/src/Twilio/Rest/PreviewIam/V1/TokenResource.cs +++ /dev/null @@ -1,192 +0,0 @@ -/* - * This code was generated by - * ___ _ _ _ _ _ _ ____ ____ ____ _ ____ ____ _ _ ____ ____ ____ ___ __ __ - * | | | | | | | | | __ | | |__| | __ | __ |___ |\ | |___ |__/ |__| | | | |__/ - * | |_|_| | |___ | |__| |__| | | | |__] |___ | \| |___ | \ | | | |__| | \ - * - * Organization Public API - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * NOTE: This class is auto generated by OpenAPI Generator. - * https://openapi-generator.tech - * Do not edit the class manually. - */ - - -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using Twilio.Base; -using Twilio.Clients; -using Twilio.Constant; -using Twilio.Converters; -using Twilio.Exceptions; -using Twilio.Http; - - - -namespace Twilio.Rest.PreviewIam.V1 -{ - public class TokenResource : Resource - { - - - - - - private static Request BuildCreateRequest(CreateTokenOptions options, ITwilioRestClient client) - { - - string path = "/v1/token"; - - - return new Request( - HttpMethod.Post, - Rest.Domain.PreviewIam, - path, - contentType: EnumConstants.ContentTypeEnum.FORM_URLENCODED, - postParams: options.GetParams(), - headerParams: null - ); - } - - /// create - /// Create Token parameters - /// Client to make requests to Twilio - /// A single instance of Token - public static TokenResource Create(CreateTokenOptions options, ITwilioRestClient client = null) - { - client = client ?? TwilioClient.GetNoAuthRestClient(); - var response = client.Request(BuildCreateRequest(options, client)); - return FromJson(response.Content); - } - - #if !NET35 - /// create - /// Create Token parameters - /// Client to make requests to Twilio - /// Task that resolves to A single instance of Token - public static async System.Threading.Tasks.Task CreateAsync(CreateTokenOptions options, ITwilioRestClient client = null) - { - client = client ?? TwilioClient.GetNoAuthRestClient(); - var response = await client.RequestAsync(BuildCreateRequest(options, client)); - return FromJson(response.Content); - } - #endif - - /// create - /// Grant type is a credential representing resource owner's authorization which can be used by client to obtain access token. - /// A 34 character string that uniquely identifies this OAuth App. - /// The credential for confidential OAuth App. - /// JWT token related to the authorization code grant type. - /// The redirect uri - /// The targeted audience uri - /// JWT token related to refresh access token. - /// The scope of token - /// Client to make requests to Twilio - /// A single instance of Token - public static TokenResource Create( - string grantType, - string clientId, - string clientSecret = null, - string code = null, - string redirectUri = null, - string audience = null, - string refreshToken = null, - string scope = null, - ITwilioRestClient client = null) - { - var options = new CreateTokenOptions(grantType, clientId){ ClientSecret = clientSecret, Code = code, RedirectUri = redirectUri, Audience = audience, RefreshToken = refreshToken, Scope = scope }; - return Create(options, client); - } - - #if !NET35 - /// create - /// Grant type is a credential representing resource owner's authorization which can be used by client to obtain access token. - /// A 34 character string that uniquely identifies this OAuth App. - /// The credential for confidential OAuth App. - /// JWT token related to the authorization code grant type. - /// The redirect uri - /// The targeted audience uri - /// JWT token related to refresh access token. - /// The scope of token - /// Client to make requests to Twilio - /// Task that resolves to A single instance of Token - public static async System.Threading.Tasks.Task CreateAsync( - string grantType, - string clientId, - string clientSecret = null, - string code = null, - string redirectUri = null, - string audience = null, - string refreshToken = null, - string scope = null, - ITwilioRestClient client = null) - { - var options = new CreateTokenOptions(grantType, clientId){ ClientSecret = clientSecret, Code = code, RedirectUri = redirectUri, Audience = audience, RefreshToken = refreshToken, Scope = scope }; - return await CreateAsync(options, client); - } - #endif - - /// - /// Converts a JSON string into a TokenResource object - /// - /// Raw JSON string - /// TokenResource object represented by the provided JSON - public static TokenResource FromJson(string json) - { - try - { - return JsonConvert.DeserializeObject(json); - } - catch (JsonException e) - { - throw new ApiException(e.Message, e); - } - } - /// - /// Converts an object into a json string - /// - /// C# model - /// JSON string - public static string ToJson(object model) - { - try - { - return JsonConvert.SerializeObject(model); - } - catch (JsonException e) - { - throw new ApiException(e.Message, e); - } - } - - - /// Token which carries the necessary information to access a Twilio resource directly. - [JsonProperty("access_token")] - public string AccessToken { get; private set; } - - /// Token which carries the information necessary to get a new access token. - [JsonProperty("refresh_token")] - public string RefreshToken { get; private set; } - - /// Token which carries the information necessary of user profile. - [JsonProperty("id_token")] - public string IdToken { get; private set; } - - /// Token type - [JsonProperty("token_type")] - public string TokenType { get; private set; } - - /// The expires_in - [JsonProperty("expires_in")] - public long? ExpiresIn { get; private set; } - - - - private TokenResource() { - - } - } -} - diff --git a/examples/csharp/src/Twilio/Rest/Versionless/DeployedDevices/FleetOptions.cs b/examples/csharp/src/Twilio/Rest/Versionless/DeployedDevices/FleetOptions.cs index 9e36d9918..3ed78b086 100644 --- a/examples/csharp/src/Twilio/Rest/Versionless/DeployedDevices/FleetOptions.cs +++ b/examples/csharp/src/Twilio/Rest/Versionless/DeployedDevices/FleetOptions.cs @@ -49,6 +49,7 @@ public List> GetParams() } + /// fetch public class FetchFleetOptions : IOptions { diff --git a/examples/csharp/src/Twilio/Rest/Versionless/DeployedDevices/FleetResource.cs b/examples/csharp/src/Twilio/Rest/Versionless/DeployedDevices/FleetResource.cs index 710744f99..f029cba8d 100644 --- a/examples/csharp/src/Twilio/Rest/Versionless/DeployedDevices/FleetResource.cs +++ b/examples/csharp/src/Twilio/Rest/Versionless/DeployedDevices/FleetResource.cs @@ -99,6 +99,7 @@ public static async System.Threading.Tasks.Task CreateAsync( return await CreateAsync(options, client); } #endif + private static Request BuildFetchRequest(FetchFleetOptions options, ITwilioRestClient client) { diff --git a/examples/java/Dockerfile b/examples/java/Dockerfile index 61cfaa6d7..313a202ee 100644 --- a/examples/java/Dockerfile +++ b/examples/java/Dockerfile @@ -1,8 +1,19 @@ -FROM openjdk:8 +FROM eclipse-temurin:8-jdk -RUN apt-get update && apt-get install maven -y +# Install Maven with proper error handling +RUN apt-get update && \ + apt-get install -y --no-install-recommends maven && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* WORKDIR /app +# Install git +RUN apt-get update && \ + apt-get install -y --no-install-recommends git && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Use HTTPS instead of SSH for git clone RUN git clone https://github.com/twilio/twilio-java.git WORKDIR /app/twilio-java/ diff --git a/examples/spec/twilio_iam_organizations.yaml b/examples/skipped_orgs_spec/twilio_iam_organizations.yaml similarity index 100% rename from examples/spec/twilio_iam_organizations.yaml rename to examples/skipped_orgs_spec/twilio_iam_organizations.yaml diff --git a/examples/spec/twilio_iam_organizations_v1.yaml b/examples/skipped_orgs_spec/twilio_iam_organizations_v1.yaml similarity index 100% rename from examples/spec/twilio_iam_organizations_v1.yaml rename to examples/skipped_orgs_spec/twilio_iam_organizations_v1.yaml diff --git a/examples/spec/twilio_iam_organizations_versionless.yaml b/examples/skipped_orgs_spec/twilio_iam_organizations_versionless.yaml similarity index 100% rename from examples/spec/twilio_iam_organizations_versionless.yaml rename to examples/skipped_orgs_spec/twilio_iam_organizations_versionless.yaml diff --git a/examples/skipped_orgs_spec/twilio_iam_v1.yaml b/examples/skipped_orgs_spec/twilio_iam_v1.yaml new file mode 100644 index 000000000..20fd0aad2 --- /dev/null +++ b/examples/skipped_orgs_spec/twilio_iam_v1.yaml @@ -0,0 +1,826 @@ +components: + securitySchemes: + accountSid_authToken: + scheme: basic + type: http + schemas: + accounts_enum_status: + type: string + enum: + - active + - suspended + - closed + accounts_enum_type: + type: string + enum: + - Trial + - Full + iam.v1.get_keys: + type: object + properties: + sid: + type: string + minLength: 34 + maxLength: 34 + pattern: ^SK[0-9a-fA-F]{32}$ + nullable: true + description: The unique string that we created to identify the Key resource. + friendly_name: + type: string + nullable: true + description: The string that you assigned to describe the resource. + date_created: + type: string + format: date-time-rfc-2822 + nullable: true + description: The date and time in GMT that the resource was created specified + in [RFC 2822](https://www.ietf.org/rfc/rfc2822.txt) format. + date_updated: + type: string + format: date-time-rfc-2822 + nullable: true + description: The date and time in GMT that the resource was last updated + specified in [RFC 2822](https://www.ietf.org/rfc/rfc2822.txt) format. + iam.v1.key: + type: object + properties: + sid: + type: string + minLength: 34 + maxLength: 34 + pattern: ^SK[0-9a-fA-F]{32}$ + nullable: true + description: The unique string that we created to identify the Key resource. + friendly_name: + type: string + nullable: true + description: The string that you assigned to describe the resource. + x-twilio: + pii: + handling: standard + deleteSla: 30 + date_created: + type: string + format: date-time-rfc-2822 + nullable: true + description: The date and time in GMT that the resource was created specified + in [RFC 2822](https://www.ietf.org/rfc/rfc2822.txt) format. + date_updated: + type: string + format: date-time-rfc-2822 + nullable: true + description: The date and time in GMT that the resource was last updated + specified in [RFC 2822](https://www.ietf.org/rfc/rfc2822.txt) format. + policy: + nullable: true + type: object + description: 'The \`Policy\` object is a collection that specifies the allowed + Twilio permissions for the restricted key. + + For more information on the permissions available with restricted API + keys, refer to the [Twilio documentation](https://www.twilio.com/docs/iam/api-keys/restricted-api-keys#permissions-available-with-restricted-api-keys).' + iam.v1.new_key: + type: object + properties: + sid: + type: string + minLength: 34 + maxLength: 34 + pattern: ^SK[0-9a-fA-F]{32}$ + nullable: true + description: The unique string that that we created to identify the NewKey + resource. You will use this as the basic-auth `user` when authenticating + to the API. + friendly_name: + type: string + nullable: true + description: The string that you assigned to describe the resource. + x-twilio: + pii: + handling: standard + deleteSla: 30 + date_created: + type: string + format: date-time-rfc-2822 + nullable: true + description: The date and time in GMT that the API Key was created specified + in [RFC 2822](https://www.ietf.org/rfc/rfc2822.txt) format. + date_updated: + type: string + format: date-time-rfc-2822 + nullable: true + description: The date and time in GMT that the new API Key was last updated + specified in [RFC 2822](https://www.ietf.org/rfc/rfc2822.txt) format. + secret: + type: string + nullable: true + description: The secret your application uses to sign Access Tokens and + to authenticate to the REST API (you will use this as the basic-auth `password`). **Note + that for security reasons, this field is ONLY returned when the API Key + is first created.** + policy: + nullable: true + type: object + description: Collection of allow assertions. + new_key_enum_keytype: + type: string + enum: + - restricted + role_enum_scope_type: + type: string + enum: + - ORGANIZATION + - ACCOUNT + - SUB_ACCOUNT + - RESOURCE + oauth.v1.token: + type: object + properties: + access_token: + type: string + nullable: true + description: Token which carries the necessary information to access a Twilio + resource directly. + refresh_token: + type: string + nullable: true + description: Token which carries the information necessary to get a new + access token. + id_token: + type: string + nullable: true + description: Token which carries the information necessary of user profile. + token_type: + type: string + nullable: true + description: Token type + expires_in: + type: integer + format: int64 + nullable: true + iam.v1.account_search_account: + type: object + properties: + accountSid: + type: string + nullable: true + accountPath: + type: string + nullable: true + status: + type: integer + default: 0 + dormant: + type: boolean + nullable: true + trial: + type: boolean + nullable: true + memberPlatform: + type: string + nullable: true + friendlyName: + type: string + nullable: true + subaccount: + type: boolean + nullable: true + iam.v1.account_search_list_meta: + type: object + properties: + previousToken: + type: string + nullable: true + nextToken: + type: string + nullable: true + pageSize: + type: integer + default: 0 + totalPages: + type: integer + default: 0 + totalResults: + type: integer + default: 0 + iam.v1.account_search_role_response: + type: array + items: + type: object + properties: + roleSid: + type: string + friendlyName: + type: string + nullable: true + description: + type: string + nullable: true + twilio.service_error_response: + type: object + properties: + code: + description: Twilio-specific error code + type: integer + format: int32 + message: + description: Error message + type: string + more_info: + description: Link to Error Code References + type: string + status: + description: HTTP response status code + type: integer + format: int32 + iam.v1.account_search_request: + type: object + properties: + searchString: + type: string + nullable: true + parentAccountId: + type: string + nullable: true + status: + type: array + items: + type: integer + nullable: true + dormant: + type: boolean + nullable: true + trial: + type: boolean + nullable: true + iam.v1.account_stats_response: + type: object + properties: + numberOfAccounts: + type: integer + default: 0 +info: + title: Twilio - Iam + description: This is the public Twilio REST API. + termsOfService: https://www.twilio.com/legal/tos + contact: + name: Twilio Support + url: https://support.twilio.com + email: support@twilio.com + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + version: 1.0.0 +openapi: 3.0.1 +paths: + /v1/Keys: + servers: + - url: https://iam.twilio.com + description: API keys + x-twilio: + defaultOutputProperties: + - sid + - friendly_name + - date_created + mountName: get_api_keys + className: get_api_keys + pathType: list + get: + description: Retrieve a list of all Keys for a account. + tags: + - IamV1GetApiKeys + parameters: + - name: AccountSid + in: query + description: The SID of the [Account](https://www.twilio.com/docs/iam/api/account) + that created the Payments resource. + schema: + type: string + minLength: 34 + maxLength: 34 + pattern: ^AC[0-9a-fA-F]{32}$ + required: true + examples: + readEmpty: + value: ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + readFull: + value: ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + - name: PageSize + in: query + description: How many resources to return in each list page. The default is + 50, and the maximum is 1000. + schema: + type: integer + format: int64 + minimum: 1 + maximum: 1000 + - name: Page + in: query + description: The page index. This value is simply for client state. + schema: + type: integer + minimum: 0 + - name: PageToken + in: query + description: The page token. This is provided by the API. + schema: + type: string + responses: + '200': + content: + application/json: + schema: + type: object + properties: + keys: + type: array + items: + $ref: '#/components/schemas/iam.v1.get_keys' + meta: + properties: + first_page_url: + format: uri + type: string + key: + type: string + next_page_url: + format: uri + nullable: true + type: string + page: + type: integer + page_size: + type: integer + previous_page_url: + format: uri + nullable: true + type: string + url: + format: uri + type: string + type: object + title: ListGetKeysResponse + examples: + readEmpty: + value: + keys: [] + meta: + page: 0 + page_size: 50 + first_page_url: https://iam.twilio.com/v1/Keys?AccountSid=ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&PageSize=50&Page=0 + previous_page_url: null + url: https://iam.twilio.com/v1/Keys?AccountSid=ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&PageSize=50&Page=0 + next_page_url: null + key: keys + readFull: + value: + keys: + - sid: SKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + friendly_name: foo + date_created: Mon, 13 Jun 2016 22:50:08 +0000 + date_updated: Mon, 13 Jun 2016 22:50:08 +0000 + - sid: SKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab + friendly_name: bar + date_created: Mon, 13 Jun 2016 20:50:08 +0000 + date_updated: Mon, 13 Jun 2016 20:50:08 +0000 + meta: + page: 0 + page_size: 50 + first_page_url: https://iam.twilio.com/v1/Keys?AccountSid=ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&PageSize=50&Page=0 + previous_page_url: null + url: https://iam.twilio.com/v1/Keys?AccountSid=ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&PageSize=50&Page=0 + next_page_url: null + key: keys + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + description: OK + security: + - accountSid_authToken: [] + operationId: ListGetKeys + post: + description: Create a new Signing Key for the account making the request. + tags: + - IamV1NewApiKey + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/iam.v1.new_key' + examples: + createStandardKey: + value: + sid: SKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + friendly_name: foo + date_created: Mon, 13 Jun 2016 22:50:08 +0000 + date_updated: Mon, 13 Jun 2016 22:50:08 +0000 + secret: foobar + policy: null + createRestrictedKey: + value: + sid: SKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + friendly_name: foo + date_created: Mon, 13 Jun 2016 22:50:08 +0000 + date_updated: Mon, 13 Jun 2016 22:50:08 +0000 + secret: foobar + policy: + allow: + - /twilio/messaging/messages/read + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + description: Created + security: + - accountSid_authToken: [] + operationId: CreateNewKey + requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + title: CreateNewKeyRequest + properties: + AccountSid: + type: string + minLength: 34 + maxLength: 34 + pattern: ^AC[0-9a-fA-F]{32}$ + description: The SID of the [Account](https://www.twilio.com/docs/iam/api/account) + that created the Payments resource. + FriendlyName: + type: string + description: A descriptive string that you create to describe the + resource. It can be up to 64 characters long. + KeyType: + type: string + $ref: '#/components/schemas/new_key_enum_keytype' + description: 'The \`KeyType\` form parameter is used to specify + the type of key you want to create. + + + **Default Behavior**: If \`KeyType\` is not specified, the API + will generate a standard key. + + + **Restricted Key**: If \`KeyType\` is set to \`restricted\`, the + API will create a new restricted key. In this case, a policy object + is required to define the permissions.' + Policy: + description: 'The \`Policy\` object is a collection that specifies + the allowed Twilio permissions for the restricted key. + + For more information on the permissions available with restricted + API keys, refer to the [Twilio documentation](https://www.twilio.com/docs/iam/api-keys/restricted-api-keys#permissions-available-with-restricted-api-keys).' + required: + - AccountSid + examples: + createStandardKey: + value: + FriendlyName: foo + AccountSid: ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + createRestrictedKey: + value: + FriendlyName: foo + AccountSid: ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + KeyType: restricted + Policy: '{"allow":["/twilio/messaging/messages/read"]}' + x-twilio: + mountName: new_api_key + /v1/Keys/{Sid}: + servers: + - url: https://iam.twilio.com + description: API keys + x-twilio: + defaultOutputProperties: + - sid + - friendly_name + - date_created + mountName: api_key + pathType: instance + get: + description: Fetch a specific Key. + tags: + - IamV1ApiKey + parameters: + - name: Sid + in: path + description: The Twilio-provided string that uniquely identifies the Key resource + to fetch. + schema: + type: string + minLength: 34 + maxLength: 34 + pattern: ^SK[0-9a-fA-F]{32}$ + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/iam.v1.key' + examples: + fetchStandardKey: + value: + sid: SKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + friendly_name: foo + date_created: Mon, 13 Jun 2016 22:50:08 +0000 + date_updated: Mon, 13 Jun 2016 22:50:08 +0000 + policy: null + fetchRestrictedKey: + value: + sid: SKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + friendly_name: foo + date_created: Mon, 13 Jun 2016 22:50:08 +0000 + date_updated: Mon, 13 Jun 2016 22:50:08 +0000 + policy: + allow: + - /twilio/messaging/messages/read + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + description: OK + security: + - accountSid_authToken: [] + operationId: FetchKey + post: + description: Update a specific Key. + tags: + - IamV1ApiKey + parameters: + - name: Sid + in: path + description: The Twilio-provided string that uniquely identifies the Key resource + to update. + schema: + type: string + minLength: 34 + maxLength: 34 + pattern: ^SK[0-9a-fA-F]{32}$ + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/iam.v1.key' + examples: + updateStandardKey: + value: + sid: SKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + friendly_name: foo + date_created: Mon, 13 Jun 2016 22:50:08 +0000 + date_updated: Mon, 13 Jun 2016 22:50:08 +0000 + policy: null + updateRestrictedKey: + value: + sid: SKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + friendly_name: foo + date_created: Mon, 13 Jun 2016 22:50:08 +0000 + date_updated: Mon, 13 Jun 2016 22:50:08 +0000 + policy: + allow: + - /twilio/messaging/messages/read + - /twilio/messaging/messages/update + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + description: OK + security: + - accountSid_authToken: [] + operationId: UpdateKey + requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + title: UpdateKeyRequest + properties: + FriendlyName: + type: string + description: A descriptive string that you create to describe the + resource. It can be up to 64 characters long. + Policy: + description: 'The \`Policy\` object is a collection that specifies + the allowed Twilio permissions for the restricted key. + + For more information on the permissions available with restricted + API keys, refer to the [Twilio documentation](https://www.twilio.com/docs/iam/api-keys/restricted-api-keys#permissions-available-with-restricted-api-keys).' + examples: + updateStandardKey: + value: + FriendlyName: foo + updateRestrictedKey: + value: + FriendlyName: foo + Policy: '{"allow":["/twilio/messaging/messages/read", "/twilio/messaging/messages/update"]}' + delete: + description: Delete a specific Key. + tags: + - IamV1ApiKey + parameters: + - name: Sid + in: path + description: The Twilio-provided string that uniquely identifies the Key resource + to delete. + schema: + type: string + minLength: 34 + maxLength: 34 + pattern: ^SK[0-9a-fA-F]{32}$ + required: true + responses: + '204': + description: The resource was deleted successfully. + security: + - accountSid_authToken: [] + operationId: DeleteKey + /v1/token: + servers: + - url: https://iam.twilio.com + x-twilio: + defaultOutputProperties: [] + pathType: list + post: + security: [] + tags: + - OauthV1Token + summary: Issues a new Access token (optionally identity_token & refresh_token) + in exchange of Oauth grant + operationId: CreateToken + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/oauth.v1.token' + examples: + create: + value: + access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c + refresh_token: ghjbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c + id_token: eyJhbdGciOiIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c + expires_in: 1438315200000 + token_type: bearer + description: Created + requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + title: CreateTokenRequest + properties: + grant_type: + type: string + description: Grant type is a credential representing resource owner's + authorization which can be used by client to obtain access token. + client_id: + type: string + description: A 34 character string that uniquely identifies this + OAuth App. + client_secret: + type: string + description: The credential for confidential OAuth App. + code: + type: string + description: JWT token related to the authorization code grant type. + redirect_uri: + type: string + description: The redirect uri + audience: + type: string + description: The targeted audience uri + refresh_token: + type: string + description: JWT token related to refresh access token. + scope: + type: string + description: The scope of token + required: + - grant_type + - client_id + examples: + create: + value: + client_id: OQ7cda1a615f05a95634e643aaaf7081d7 + client_secret: sUWblrQ4wx_aYkdAWjHXNvHinynkYOgBoiRyEQUeEntpgDEG47qnBFD98yoEzsTh + grant_type: client_credentials + redirect_uri: '' + audience: '' + code: '' + refresh_token: refresh_token + scope: scope + required: true + /search/v1/user-accounts: {} + /search/v1/user-accounts/account/{accountSid}/roles: {} + /search/v1/user-accounts/stats: {} +servers: +- url: https://iam.twilio.com +tags: +- name: IamV1Account +- name: IamV1ApiKey +- name: IamV1Authenticate +- name: IamV1GetApiKeys +- name: IamV1Index +- name: IamV1NewApiKey +- name: IamV1Permission +- name: IamV1PolicyAssignment +- name: IamV1PublicKey +- name: IamV1RefreshToken +- name: IamV1Role +- name: IamV1RoleAssignmentBatch +- name: IamV1RoleBySid +- name: IamV1Saml2 +- name: IamV1Token +- name: IamV1ValidateToken +- name: IamV1Version +security: +- accountSid_authToken: [] diff --git a/examples/test_spec/java/twilio_customfeature_v1.yaml b/examples/test_spec/java/twilio_customfeature_v1.yaml new file mode 100644 index 000000000..4d479ff56 --- /dev/null +++ b/examples/test_spec/java/twilio_customfeature_v1.yaml @@ -0,0 +1,2 @@ +# This spec is twilio-java specific and Tests following +# 1. It tests custom feature for twilio-java examples: constructors, DateInequality \ No newline at end of file diff --git a/examples/test_spec/twilio_auth_v1.yaml b/examples/test_spec/twilio_auth_v1.yaml new file mode 100644 index 000000000..a6d5e7b9d --- /dev/null +++ b/examples/test_spec/twilio_auth_v1.yaml @@ -0,0 +1,10 @@ +components: + securitySchemes: + oAuth2ClientCredentials: + type: oauth2 + flows: + clientCredentials: + tokenUrl: https://preview-iam.twilio.com/v1/token + scopes: {} +paths: + \ No newline at end of file diff --git a/examples/test_spec/twilio_datamodels_v1.yaml b/examples/test_spec/twilio_datamodels_v1.yaml new file mode 100644 index 000000000..57eb06230 --- /dev/null +++ b/examples/test_spec/twilio_datamodels_v1.yaml @@ -0,0 +1,212 @@ +openapi: 3.1.0 +info: + title: OneOf API Examples + version: 1.0.0 +servers: + - url: https://api.twilio.com + +paths: + /v1/directOneOf: + post: + operationId: CreateDirectOneOf + summary: Direct oneOf in request body + requestBody: + required: true + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + responses: + '200': + description: Success + +# /v1/nestedOneOf: +# post: +# operationId: CreateNestedOneOf +# summary: Nested oneOf in request body +# requestBody: +# required: true +# content: +# application/json: +# schema: +# type: object +# properties: +# pet: +# oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' +# owner: +# type: string +# responses: +# '200': +# description: Success +# +# /v1/multipleNestedOneOf: +# post: +# operationId: CreateMultipleDirectOneOf +# summary: Multiple nested oneOf in request body +# requestBody: +# required: true +# content: +# application/json: +# schema: +# type: object +# properties: +# petDetails: +# type: object +# properties: +# pet: +# oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' +# additionalInfo: +# oneOf: +# - $ref: '#/components/schemas/One' +# - $ref: '#/components/schemas/Two' +# owner: +# type: string +# responses: +# '200': +# description: Success +# +# /v1/arrayOfOneOf: +# post: +# operationId: CreateArrayOfOneOf +# summary: Array of oneOf in request body +# requestBody: +# required: true +# content: +# application/json: +# schema: +# type: object +# properties: +# pets: +# type: array +# items: +# oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' +# responses: +# '200': +# description: Success +# /v1/parallelOneOfAndObject: +# post: +# operationId: CreateParallelOneOfAndObject +# summary: OneOf and normal object in parallel +# requestBody: +# required: true +# content: +# application/json: +# schema: +# type: object +# properties: +# pet: +# oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' +# owner: +# type: object +# properties: +# name: +# type: string +# age: +# type: integer +# responses: +# '200': +# description: Success +# +# /v1/oneOfWithAdditionalProperties: +# post: +# operationId: CreateOneOfWithAdditionalProperties +# summary: OneOf with additional properties +# requestBody: +# required: true +# content: +# application/json: +# schema: +# type: object +# properties: +# pet: +# oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' +# metadata: +# type: object +# additionalProperties: +# type: string +# responses: +# '200': +# description: Success +# +# /v1/oneOfWithRequiredFields: +# post: +# operationId: CreateOneOfWithRequiredFields +# summary: OneOf with required fields in parallel +# requestBody: +# required: true +# content: +# application/json: +# schema: +# type: object +# required: +# - pet +# - owner +# properties: +# pet: +# oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' +# owner: +# type: object +# properties: +# name: +# type: string +# contact: +# type: string +# responses: +# '200': +# description: Success + +components: + schemas: + Cat: + type: object + properties: + type: + type: string + enum: [cat] + name: + type: string + huntingSkill: + type: string + enum: [clueless, lazy, adventurous, aggressive] + + Dog: + type: object + properties: + type: + type: string + enum: [dog] + name: + type: string + packSize: + type: integer + minimum: 0 + + One: + type: object + properties: + param1: + type: string + param2: + type: string + + Two: + type: object + properties: + object1: + type: string + object2: + type: string \ No newline at end of file diff --git a/examples/test_spec/twilio_enum_v1.yaml b/examples/test_spec/twilio_enum_v1.yaml new file mode 100644 index 000000000..2de5aaa20 --- /dev/null +++ b/examples/test_spec/twilio_enum_v1.yaml @@ -0,0 +1,106 @@ +info: + contact: + email: support@twilio.com + name: Twilio Support + url: https://support.twilio.com + description: This is the public Twilio REST API. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + termsOfService: https://www.twilio.com/legal/tos + title: Twilio - CONTENT + version: 1.11.0 +openapi: 3.0.1 + +paths: + /v1/content: + servers: + - url: https://enum.twilio.com + get: + summary: Retrieve items with various filter options + parameters: + # PARAMETER_SINGLE + - name: singleParam + in: query + description: A single enum value as a query parameter + required: false + schema: + type: string + enum: + - asc + - desc + example: asc + + # PARAMETER_ARRAY + - name: arrayParam + in: query + description: Order items using an array of enums + required: false + schema: + type: array + items: + type: string + enum: + - asc + - desc + example: [asc] + + # PARAMETER_ARRAY + - name: arrayParamRef + in: query + required: false + description: An array parameter referencing a reusable schema + schema: + type: array + items: + $ref: '#/components/schemas/singleReusable' + + - name: singleParamRef + in: header + schema: + $ref: '#/components/schemas/singleReusable' + + responses: + '200': + description: A list of items + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Item' + +components: + schemas: + Item: + type: object + properties: + # PROPERTY_SINGLE + singleProperty: + type: string + enum: [available, pending, sold] + description: A single enum value as a property in a schema + example: available + + # PROPERTY_ARRAY + arrayProperty: + type: array + items: + type: string + enum: [new, sale, featured] + description: An array of enum values in a schema property + example: [new, featured] + + # REUSABLE_ARRAY + arrayReusable: + type: array + items: + $ref: '#/components/schemas/singleReusable' + description: An array of reusable enum defined in components + example: [electronics, clothing] + + # REUSABLE_SINGLE + singleReusable: + type: string + enum: [electronics, furniture, clothing] + description: A reusable single-value enum defined in components \ No newline at end of file diff --git a/src/main/resources/twilio-java/api_doc.mustache b/examples/test_spec/twilio_format_v1.yaml similarity index 100% rename from src/main/resources/twilio-java/api_doc.mustache rename to examples/test_spec/twilio_format_v1.yaml diff --git a/examples/test_spec/twilio_nestedmodel_v1.yaml b/examples/test_spec/twilio_nestedmodel_v1.yaml new file mode 100644 index 000000000..940719838 --- /dev/null +++ b/examples/test_spec/twilio_nestedmodel_v1.yaml @@ -0,0 +1,2 @@ +# This spec tests followings +# 1. Nested model in request body and component schema \ No newline at end of file diff --git a/examples/test_spec/twilio_oneOf_v1.yaml b/examples/test_spec/twilio_oneOf_v1.yaml new file mode 100644 index 000000000..831bf8a24 --- /dev/null +++ b/examples/test_spec/twilio_oneOf_v1.yaml @@ -0,0 +1,110 @@ +openapi: 3.1.0 +info: + title: Number Pool Service + description: |- + This service is an entry point for all Number Pool CRUD requests. + version: 1.0.0 + contact: + name: 'Number Pool Service' + url: 'https://wiki.hq.twilio.com/display/MSG/Messaging+Services' + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: https://oneOf.twilio.com +paths: + /v1/pets: + post: + operationId: CreatePet + summary: Add a pet (cat or dog) + requestBody: + required: true + content: + application/json: + schema: +# properties: +# RecordingStatusCallback: +# format: uri +# type: string +# RecordingStatusCallbackEvent: +# items: +# type: string +# type: array + $ref: '#/components/schemas/Cat' +# title: MyPet +# oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' + responses: + '200': + description: Returns the created pet (cat or dog) + content: + application/json: + schema: + $ref: '#/components/schemas/Cat' +# allOf: +# - type: object +# properties: +# account_sid: +# type: string +# nullable: true +# - title: MyPet_Response +# $ref: '#/components/schemas/MyPet_Response' +# - oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' + +components: + schemas: + MyPet_Response: + type: object + properties: + cat: + $ref: '#/components/schemas/Cat' + dog: + $ref: '#/components/schemas/Dog' + Cat: + allOf: + - type: object + properties: + account_sid: + type: string + - oneOf: + - $ref: '#/components/schemas/One' + - $ref: '#/components/schemas/Two' +# type: +# type: string +# enum: [cat] +# name: +# type: string +# huntingSkill: +# type: string +# enum: [clueless, lazy, adventurous, aggressive] + + Dog: + type: object + properties: + type: + type: string + enum: [dog] + name: + type: string + packSize: + type: integer + minimum: 0 + One: + type: object + properties: + param1: + type: string + param2: + type: string + dog: + $ref: '#/components/schemas/Dog' + Two: + type: object + properties: + object1: + type: string + object2: + type: string diff --git a/examples/test_spec/twilio_parameters_v1.yaml b/examples/test_spec/twilio_parameters_v1.yaml new file mode 100644 index 000000000..77ce3ab33 --- /dev/null +++ b/examples/test_spec/twilio_parameters_v1.yaml @@ -0,0 +1,78 @@ +# This spec tests followings +# 1. All types of parameters(query, header, path) + +info: + contact: + email: support@twilio.com + name: Twilio Support + url: https://support.twilio.com + description: This is the public Twilio REST API. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + termsOfService: https://www.twilio.com/legal/tos + title: Twilio - PARAMETERS + version: 1.11.0 +openapi: 3.0.1 + +paths: + /v1/parameter/{id}: + servers: + - url: https://testparameter.twilio.com + post: + operationId: CreateParameter + parameters: + - name: id + in: path + required: true + description: The unique identifier for the enum item + schema: + type: string + - name: queryParamDoubleRequired + in: query + description: A single enum value as a query parameter + required: required + schema: + type: string + - name: queryParamBoolean + in: query + description: A single enum value as a query parameter + required: false + schema: + type: boolean + - name: queryParamString + in: query + description: A single enum value as a query parameter + required: false + schema: + type: string + - name: queryParamInteger + in: query + description: A single enum value as a query parameter + required: false + schema: + type: integer + + + requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + title: CreateParameterRequest + properties: + To: + type: string + format: phone-number + responses: + '201': + description: Parameter created successfully + content: + application/json: + schema: + type: object + properties: + id: + type: string + status: + type: string diff --git a/examples/test_spec/twilio_request_v1.yaml b/examples/test_spec/twilio_request_v1.yaml new file mode 100644 index 000000000..cf07b84a3 --- /dev/null +++ b/examples/test_spec/twilio_request_v1.yaml @@ -0,0 +1,101 @@ +# This spec tests followings +# 1. All types of request body(urlencoded, json) +# 2. Tests pagination for both type of request body. + +info: + contact: + email: support@twilio.com + name: Twilio Support + url: https://support.twilio.com + description: This is the public Twilio REST API. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + termsOfService: https://www.twilio.com/legal/tos + title: Twilio - REQUEST BODY TEST + version: 1.11.0 +openapi: 3.0.1 + +components: + schemas: + UpdateRequestBodyRequest: + type: object + properties: + username: + type: string + password: + type: string +paths: + /v1/requestbody: + servers: + - url: https://testparameter.twilio.com + post: + operationId: CreateRequestBody + parameters: + - name: queryParamStringRequired + in: query + description: A single enum value as a query parameter + required: required + schema: + type: string + requestBody: + content: + application/x-www-form-urlencoded: + schema: + # 1. Inline request body + type: object + title: CreateRequestBodyRequest + properties: + username: + type: string + password: + type: string + + responses: + '201': + description: Parameter created successfully + content: + application/json: + schema: + type: object + properties: + id: + type: string + status: + type: string + + /v1/requestbody/{id}: + servers: + - url: https://testparameter.twilio.com + post: + operationId: UpdateRequestBody + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: queryParamStringRequired + in: query + required: required + schema: + type: string + requestBody: + content: + application/x-www-form-urlencoded: + schema: + # 2. Reusable request body + $ref: '#/components/schemas/UpdateRequestBodyRequest' + + responses: + '201': + description: Parameter created successfully + content: + application/json: + schema: + type: object + properties: + id: + type: string + status: + type: string \ No newline at end of file diff --git a/examples/test_spec/twilio_response_v1.yaml b/examples/test_spec/twilio_response_v1.yaml new file mode 100644 index 000000000..3188edba5 --- /dev/null +++ b/examples/test_spec/twilio_response_v1.yaml @@ -0,0 +1,3 @@ +# This spec tests followings +# 1. All types of response body(json) +# 2. Tests paginated response. \ No newline at end of file diff --git a/examples/test_spec/twilio_testenum_v1.yaml b/examples/test_spec/twilio_testenum_v1.yaml new file mode 100644 index 000000000..470aed46a --- /dev/null +++ b/examples/test_spec/twilio_testenum_v1.yaml @@ -0,0 +1,134 @@ +# This spec Tests following +# 1. All types of enums, There are 8 types of Enum to be tested +# 2. Enums as a query, header parameter +info: + contact: + email: support@twilio.com + name: Twilio Support + url: https://support.twilio.com + description: This is the public Twilio REST API. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + termsOfService: https://www.twilio.com/legal/tos + title: Twilio - CONTENT + version: 1.11.0 +openapi: 3.0.1 + +paths: + /v1/enum/{id}: + servers: + - url: https://testenum.twilio.com + get: + operationId: FetchAbc + summary: Retrieve items with various filter options + parameters: + - name: id + in: path + required: true + description: The unique identifier for the enum item + schema: + type: string + # 1. PARAMETER_SINGLE + - name: singleParam + in: query + description: A single enum value as a query parameter + required: false + schema: + type: string + enum: + - asc + - desc + example: asc + + # 2. PARAMETER_ARRAY + - name: arrayParam + in: query + description: Order items using an array of enums + required: false + schema: + type: array + items: + type: string + enum: + - asc + - desc + example: [asc] + + # 3. PARAMETER_ARRAY Referencing Reusable Schema + - name: arrayParamRef + in: query + required: false + description: An array parameter referencing a reusable schema + schema: + type: array + items: + $ref: '#/components/schemas/singleReusable' + + # 4. PARAMETER_REUSABLE_SINGLE + - name: singleParamRef + in: header + schema: + $ref: '#/components/schemas/singleReusable' + + responses: + '200': + description: A list of items + content: + application/json: + schema: + $ref: '#/components/schemas/Item' + +components: + schemas: + Item: + type: object + properties: + # 5. PROPERTY_SINGLE + singleProperty: + type: string + enum: [available, pending, sold] + description: A single enum value as a property in a schema + example: available + + # 6. PROPERTY_ARRAY + arrayProperty: + type: array + items: + type: string + enum: [new, sale, featured] + description: An array of enum values in a schema property + example: [new, featured] + + # 7. REUSABLE_ARRAY + arrayReusable: + type: array + items: + $ref: '#/components/schemas/singleReusable' + description: An array of reusable enum defined in components + example: [electronics, clothing] + status: + $ref: '#/components/schemas/message_enum_status' + + # 8. REUSABLE_SINGLE + singleReusable: + type: string + enum: [electronics, furniture, clothing] + description: A reusable single-value enum defined in components + message_enum_status: + type: string + enum: + - queued + - sending + - sent + - failed + - delivered + - undelivered + - receiving + - received + - accepted + - scheduled + - read + - partially_delivered + - canceled + description: test \ No newline at end of file diff --git a/pom.xml b/pom.xml index 45bf70981..21ba1bdec 100644 --- a/pom.xml +++ b/pom.xml @@ -124,7 +124,7 @@ UTF-8 - 6.6.0 + 7.13.0 1.0.0 4.13.2 diff --git a/scripts/build_twilio_library.py b/scripts/build_twilio_library.py index ddf0bad83..d192cc8fc 100644 --- a/scripts/build_twilio_library.py +++ b/scripts/build_twilio_library.py @@ -80,8 +80,8 @@ def generate_domain_for_language(spec_file: str, config_path: str, spec_folder: 'generatorName': 'terraform-provider-twilio' if language == 'terraform' else f'twilio-{language}', 'inputSpec': full_path, 'outputDir': output_path, - 'inlineSchemaNameDefaults': { - 'arrayItemSuffix': '' + 'inlineSchemaOptions': { + 'ARRAY_ITEM_SUFFIX': '' }, } # print(config) diff --git a/scripts/generate.sh b/scripts/generate.sh index e03b520f5..dca485392 100644 --- a/scripts/generate.sh +++ b/scripts/generate.sh @@ -82,11 +82,11 @@ if should-generate php; then generate twilio-php fi -if should-generate python; then - OUT_DIR=examples/python/twilio/rest - generate twilio-python -DskipFormModel=false - docker-run examples/python/Dockerfile-prettier -fi +#if should-generate python; then +# OUT_DIR=examples/python/twilio/rest +# generate twilio-python -DskipFormModel=false +# docker-run examples/python/Dockerfile-prettier +#fi if should-generate ruby; then OUT_DIR=examples/ruby/lib/twilio-ruby/rest diff --git a/specs_test/test_spec/java/twilio_customfeature_v1.yaml b/specs_test/test_spec/java/twilio_customfeature_v1.yaml new file mode 100644 index 000000000..4d479ff56 --- /dev/null +++ b/specs_test/test_spec/java/twilio_customfeature_v1.yaml @@ -0,0 +1,2 @@ +# This spec is twilio-java specific and Tests following +# 1. It tests custom feature for twilio-java examples: constructors, DateInequality \ No newline at end of file diff --git a/specs_test/test_spec/twilio_auth_v1.yaml b/specs_test/test_spec/twilio_auth_v1.yaml new file mode 100644 index 000000000..a6d5e7b9d --- /dev/null +++ b/specs_test/test_spec/twilio_auth_v1.yaml @@ -0,0 +1,10 @@ +components: + securitySchemes: + oAuth2ClientCredentials: + type: oauth2 + flows: + clientCredentials: + tokenUrl: https://preview-iam.twilio.com/v1/token + scopes: {} +paths: + \ No newline at end of file diff --git a/specs_test/test_spec/twilio_datamodels_v1.yaml b/specs_test/test_spec/twilio_datamodels_v1.yaml new file mode 100644 index 000000000..57eb06230 --- /dev/null +++ b/specs_test/test_spec/twilio_datamodels_v1.yaml @@ -0,0 +1,212 @@ +openapi: 3.1.0 +info: + title: OneOf API Examples + version: 1.0.0 +servers: + - url: https://api.twilio.com + +paths: + /v1/directOneOf: + post: + operationId: CreateDirectOneOf + summary: Direct oneOf in request body + requestBody: + required: true + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + responses: + '200': + description: Success + +# /v1/nestedOneOf: +# post: +# operationId: CreateNestedOneOf +# summary: Nested oneOf in request body +# requestBody: +# required: true +# content: +# application/json: +# schema: +# type: object +# properties: +# pet: +# oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' +# owner: +# type: string +# responses: +# '200': +# description: Success +# +# /v1/multipleNestedOneOf: +# post: +# operationId: CreateMultipleDirectOneOf +# summary: Multiple nested oneOf in request body +# requestBody: +# required: true +# content: +# application/json: +# schema: +# type: object +# properties: +# petDetails: +# type: object +# properties: +# pet: +# oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' +# additionalInfo: +# oneOf: +# - $ref: '#/components/schemas/One' +# - $ref: '#/components/schemas/Two' +# owner: +# type: string +# responses: +# '200': +# description: Success +# +# /v1/arrayOfOneOf: +# post: +# operationId: CreateArrayOfOneOf +# summary: Array of oneOf in request body +# requestBody: +# required: true +# content: +# application/json: +# schema: +# type: object +# properties: +# pets: +# type: array +# items: +# oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' +# responses: +# '200': +# description: Success +# /v1/parallelOneOfAndObject: +# post: +# operationId: CreateParallelOneOfAndObject +# summary: OneOf and normal object in parallel +# requestBody: +# required: true +# content: +# application/json: +# schema: +# type: object +# properties: +# pet: +# oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' +# owner: +# type: object +# properties: +# name: +# type: string +# age: +# type: integer +# responses: +# '200': +# description: Success +# +# /v1/oneOfWithAdditionalProperties: +# post: +# operationId: CreateOneOfWithAdditionalProperties +# summary: OneOf with additional properties +# requestBody: +# required: true +# content: +# application/json: +# schema: +# type: object +# properties: +# pet: +# oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' +# metadata: +# type: object +# additionalProperties: +# type: string +# responses: +# '200': +# description: Success +# +# /v1/oneOfWithRequiredFields: +# post: +# operationId: CreateOneOfWithRequiredFields +# summary: OneOf with required fields in parallel +# requestBody: +# required: true +# content: +# application/json: +# schema: +# type: object +# required: +# - pet +# - owner +# properties: +# pet: +# oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' +# owner: +# type: object +# properties: +# name: +# type: string +# contact: +# type: string +# responses: +# '200': +# description: Success + +components: + schemas: + Cat: + type: object + properties: + type: + type: string + enum: [cat] + name: + type: string + huntingSkill: + type: string + enum: [clueless, lazy, adventurous, aggressive] + + Dog: + type: object + properties: + type: + type: string + enum: [dog] + name: + type: string + packSize: + type: integer + minimum: 0 + + One: + type: object + properties: + param1: + type: string + param2: + type: string + + Two: + type: object + properties: + object1: + type: string + object2: + type: string \ No newline at end of file diff --git a/specs_test/test_spec/twilio_enum_v1.yaml b/specs_test/test_spec/twilio_enum_v1.yaml new file mode 100644 index 000000000..2de5aaa20 --- /dev/null +++ b/specs_test/test_spec/twilio_enum_v1.yaml @@ -0,0 +1,106 @@ +info: + contact: + email: support@twilio.com + name: Twilio Support + url: https://support.twilio.com + description: This is the public Twilio REST API. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + termsOfService: https://www.twilio.com/legal/tos + title: Twilio - CONTENT + version: 1.11.0 +openapi: 3.0.1 + +paths: + /v1/content: + servers: + - url: https://enum.twilio.com + get: + summary: Retrieve items with various filter options + parameters: + # PARAMETER_SINGLE + - name: singleParam + in: query + description: A single enum value as a query parameter + required: false + schema: + type: string + enum: + - asc + - desc + example: asc + + # PARAMETER_ARRAY + - name: arrayParam + in: query + description: Order items using an array of enums + required: false + schema: + type: array + items: + type: string + enum: + - asc + - desc + example: [asc] + + # PARAMETER_ARRAY + - name: arrayParamRef + in: query + required: false + description: An array parameter referencing a reusable schema + schema: + type: array + items: + $ref: '#/components/schemas/singleReusable' + + - name: singleParamRef + in: header + schema: + $ref: '#/components/schemas/singleReusable' + + responses: + '200': + description: A list of items + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Item' + +components: + schemas: + Item: + type: object + properties: + # PROPERTY_SINGLE + singleProperty: + type: string + enum: [available, pending, sold] + description: A single enum value as a property in a schema + example: available + + # PROPERTY_ARRAY + arrayProperty: + type: array + items: + type: string + enum: [new, sale, featured] + description: An array of enum values in a schema property + example: [new, featured] + + # REUSABLE_ARRAY + arrayReusable: + type: array + items: + $ref: '#/components/schemas/singleReusable' + description: An array of reusable enum defined in components + example: [electronics, clothing] + + # REUSABLE_SINGLE + singleReusable: + type: string + enum: [electronics, furniture, clothing] + description: A reusable single-value enum defined in components \ No newline at end of file diff --git a/src/main/resources/twilio-java/api_test.mustache b/specs_test/test_spec/twilio_format_v1.yaml similarity index 100% rename from src/main/resources/twilio-java/api_test.mustache rename to specs_test/test_spec/twilio_format_v1.yaml diff --git a/specs_test/test_spec/twilio_nestedmodel_v1.yaml b/specs_test/test_spec/twilio_nestedmodel_v1.yaml new file mode 100644 index 000000000..940719838 --- /dev/null +++ b/specs_test/test_spec/twilio_nestedmodel_v1.yaml @@ -0,0 +1,2 @@ +# This spec tests followings +# 1. Nested model in request body and component schema \ No newline at end of file diff --git a/specs_test/test_spec/twilio_oneOf_v1.yaml b/specs_test/test_spec/twilio_oneOf_v1.yaml new file mode 100644 index 000000000..7ca5d6e85 --- /dev/null +++ b/specs_test/test_spec/twilio_oneOf_v1.yaml @@ -0,0 +1,168 @@ +openapi: 3.1.0 +info: + title: Number Pool Service + description: |- + This service is an entry point for all Number Pool CRUD requests. + version: 1.0.0 + contact: + name: 'Number Pool Service' + url: 'https://wiki.hq.twilio.com/display/MSG/Messaging+Services' + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: https://oneOf.twilio.com +paths: + /v1/owners: + post: + operationId: CreateOwner + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Owner' + responses: + '200': + description: Returns the created pet (cat or dog) + content: + application/json: + schema: + $ref: '#/components/schemas/Cat' + /v1/pets: + post: + operationId: CreatePet + summary: Add a pet (cat or dog) + requestBody: + required: true + content: + application/json: + schema: + oneOf: + - type: object + required: [ name, livesLeft ] + properties: + name: + type: string + example: "Kitty" + livesLeft: + type: integer + example: 9 + description: "Cat object (inline)" + - type: object + required: [ name, breed ] + properties: + name: + type: string + example: "Bruno" + breed: + type: string + example: "Labrador" + description: "Dog object (inline)" + - type: object + required: [ name, wingSpan ] + properties: + name: + type: string + example: "Tweety" + wingSpan: + type: number + format: float + example: 25.5 + description: "Bird object (inline)" +# properties: +# RecordingStatusCallback: +# format: uri +# type: string +# RecordingStatusCallbackEvent: +# items: +# type: string +# type: array + $ref: '#/components/schemas/Cat' +# title: MyPet +# oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' + responses: + '200': + description: Returns the created pet (cat or dog) + content: + application/json: + schema: + $ref: '#/components/schemas/Cat' +# allOf: +# - type: object +# properties: +# account_sid: +# type: string +# nullable: true +# - title: MyPet_Response +# $ref: '#/components/schemas/MyPet_Response' +# - oneOf: +# - $ref: '#/components/schemas/Cat' +# - $ref: '#/components/schemas/Dog' + +components: + schemas: + Owner: + type: object + required: [ ownerName, pet ] + properties: + ownerName: + type: string + pet: + oneOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + MyPet_Response: + type: object + properties: + cat: + $ref: '#/components/schemas/Cat' + dog: + $ref: '#/components/schemas/Dog' + Cat: + allOf: + - type: object + properties: + account_sid: + type: string + - oneOf: + - $ref: '#/components/schemas/One' + - $ref: '#/components/schemas/Two' +# type: +# type: string +# enum: [cat] +# name: +# type: string +# huntingSkill: +# type: string +# enum: [clueless, lazy, adventurous, aggressive] + + Dog: + type: object + properties: + type: + type: string + enum: [dog] + name: + type: string + packSize: + type: integer + minimum: 0 + One: + type: object + properties: + param1: + type: string + param2: + type: string + dog: + $ref: '#/components/schemas/Dog' + Two: + type: object + properties: + object1: + type: string + object2: + type: string diff --git a/specs_test/test_spec/twilio_parameters_v1.yaml b/specs_test/test_spec/twilio_parameters_v1.yaml new file mode 100644 index 000000000..77ce3ab33 --- /dev/null +++ b/specs_test/test_spec/twilio_parameters_v1.yaml @@ -0,0 +1,78 @@ +# This spec tests followings +# 1. All types of parameters(query, header, path) + +info: + contact: + email: support@twilio.com + name: Twilio Support + url: https://support.twilio.com + description: This is the public Twilio REST API. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + termsOfService: https://www.twilio.com/legal/tos + title: Twilio - PARAMETERS + version: 1.11.0 +openapi: 3.0.1 + +paths: + /v1/parameter/{id}: + servers: + - url: https://testparameter.twilio.com + post: + operationId: CreateParameter + parameters: + - name: id + in: path + required: true + description: The unique identifier for the enum item + schema: + type: string + - name: queryParamDoubleRequired + in: query + description: A single enum value as a query parameter + required: required + schema: + type: string + - name: queryParamBoolean + in: query + description: A single enum value as a query parameter + required: false + schema: + type: boolean + - name: queryParamString + in: query + description: A single enum value as a query parameter + required: false + schema: + type: string + - name: queryParamInteger + in: query + description: A single enum value as a query parameter + required: false + schema: + type: integer + + + requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + title: CreateParameterRequest + properties: + To: + type: string + format: phone-number + responses: + '201': + description: Parameter created successfully + content: + application/json: + schema: + type: object + properties: + id: + type: string + status: + type: string diff --git a/specs_test/test_spec/twilio_request_v1.yaml b/specs_test/test_spec/twilio_request_v1.yaml new file mode 100644 index 000000000..cf07b84a3 --- /dev/null +++ b/specs_test/test_spec/twilio_request_v1.yaml @@ -0,0 +1,101 @@ +# This spec tests followings +# 1. All types of request body(urlencoded, json) +# 2. Tests pagination for both type of request body. + +info: + contact: + email: support@twilio.com + name: Twilio Support + url: https://support.twilio.com + description: This is the public Twilio REST API. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + termsOfService: https://www.twilio.com/legal/tos + title: Twilio - REQUEST BODY TEST + version: 1.11.0 +openapi: 3.0.1 + +components: + schemas: + UpdateRequestBodyRequest: + type: object + properties: + username: + type: string + password: + type: string +paths: + /v1/requestbody: + servers: + - url: https://testparameter.twilio.com + post: + operationId: CreateRequestBody + parameters: + - name: queryParamStringRequired + in: query + description: A single enum value as a query parameter + required: required + schema: + type: string + requestBody: + content: + application/x-www-form-urlencoded: + schema: + # 1. Inline request body + type: object + title: CreateRequestBodyRequest + properties: + username: + type: string + password: + type: string + + responses: + '201': + description: Parameter created successfully + content: + application/json: + schema: + type: object + properties: + id: + type: string + status: + type: string + + /v1/requestbody/{id}: + servers: + - url: https://testparameter.twilio.com + post: + operationId: UpdateRequestBody + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: queryParamStringRequired + in: query + required: required + schema: + type: string + requestBody: + content: + application/x-www-form-urlencoded: + schema: + # 2. Reusable request body + $ref: '#/components/schemas/UpdateRequestBodyRequest' + + responses: + '201': + description: Parameter created successfully + content: + application/json: + schema: + type: object + properties: + id: + type: string + status: + type: string \ No newline at end of file diff --git a/specs_test/test_spec/twilio_response_v1.yaml b/specs_test/test_spec/twilio_response_v1.yaml new file mode 100644 index 000000000..3188edba5 --- /dev/null +++ b/specs_test/test_spec/twilio_response_v1.yaml @@ -0,0 +1,3 @@ +# This spec tests followings +# 1. All types of response body(json) +# 2. Tests paginated response. \ No newline at end of file diff --git a/specs_test/test_spec/twilio_testenum_v1.yaml b/specs_test/test_spec/twilio_testenum_v1.yaml new file mode 100644 index 000000000..470aed46a --- /dev/null +++ b/specs_test/test_spec/twilio_testenum_v1.yaml @@ -0,0 +1,134 @@ +# This spec Tests following +# 1. All types of enums, There are 8 types of Enum to be tested +# 2. Enums as a query, header parameter +info: + contact: + email: support@twilio.com + name: Twilio Support + url: https://support.twilio.com + description: This is the public Twilio REST API. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + termsOfService: https://www.twilio.com/legal/tos + title: Twilio - CONTENT + version: 1.11.0 +openapi: 3.0.1 + +paths: + /v1/enum/{id}: + servers: + - url: https://testenum.twilio.com + get: + operationId: FetchAbc + summary: Retrieve items with various filter options + parameters: + - name: id + in: path + required: true + description: The unique identifier for the enum item + schema: + type: string + # 1. PARAMETER_SINGLE + - name: singleParam + in: query + description: A single enum value as a query parameter + required: false + schema: + type: string + enum: + - asc + - desc + example: asc + + # 2. PARAMETER_ARRAY + - name: arrayParam + in: query + description: Order items using an array of enums + required: false + schema: + type: array + items: + type: string + enum: + - asc + - desc + example: [asc] + + # 3. PARAMETER_ARRAY Referencing Reusable Schema + - name: arrayParamRef + in: query + required: false + description: An array parameter referencing a reusable schema + schema: + type: array + items: + $ref: '#/components/schemas/singleReusable' + + # 4. PARAMETER_REUSABLE_SINGLE + - name: singleParamRef + in: header + schema: + $ref: '#/components/schemas/singleReusable' + + responses: + '200': + description: A list of items + content: + application/json: + schema: + $ref: '#/components/schemas/Item' + +components: + schemas: + Item: + type: object + properties: + # 5. PROPERTY_SINGLE + singleProperty: + type: string + enum: [available, pending, sold] + description: A single enum value as a property in a schema + example: available + + # 6. PROPERTY_ARRAY + arrayProperty: + type: array + items: + type: string + enum: [new, sale, featured] + description: An array of enum values in a schema property + example: [new, featured] + + # 7. REUSABLE_ARRAY + arrayReusable: + type: array + items: + $ref: '#/components/schemas/singleReusable' + description: An array of reusable enum defined in components + example: [electronics, clothing] + status: + $ref: '#/components/schemas/message_enum_status' + + # 8. REUSABLE_SINGLE + singleReusable: + type: string + enum: [electronics, furniture, clothing] + description: A reusable single-value enum defined in components + message_enum_status: + type: string + enum: + - queued + - sending + - sent + - failed + - delivered + - undelivered + - receiving + - received + - accepted + - scheduled + - read + - partially_delivered + - canceled + description: test \ No newline at end of file diff --git a/specs_test/twilio_iam_organizations.yaml b/specs_test/twilio_iam_organizations.yaml new file mode 100644 index 000000000..a13e4e0e7 --- /dev/null +++ b/specs_test/twilio_iam_organizations.yaml @@ -0,0 +1,1392 @@ +openapi: 3.0.1 +security: + - oAuth2ClientCredentials: [] +info: + title: Organization Public API + contact: + name: Twilio Support + url: https://support.twilio.com + email: support@twilio.com + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + version: 1.0.0 +tags: + - name: SCIM + description: SCIM 2.0 User endpoints + - name: OrganizationAccount + description: Organization Account operations + - name: RoleAssignments + description: Role assignment operations + - name: OauthV1Authorize + - name: OauthV1Token +paths: + /Organizations/{organizationSid}/scim/Users: + servers: + - url: https://preview-iam.twilio.com + get: + tags: + - SCIM + summary: List SCIM Users + operationId: ListOrganizationUsers + parameters: + - name: organizationSid + in: path + required: true + schema: + pattern: OR[0-9a-f]{32} + type: string + format: OrganizationSid + example: OR33f4f3aa6fffe840d000f8ef22e883db + - name: filter + in: query + schema: + type: string + responses: + '200': + description: List of users + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimUserPage' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '400': + description: Bad request or business rules violation + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '401': + description: Unauthorized + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '403': + description: Forbidden + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '429': + description: Too many requests + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + post: + tags: + - SCIM + summary: Create SCIM User + operationId: CreateOrganizationUser + parameters: + - name: organizationSid + in: path + required: true + schema: + pattern: OR[0-9a-f]{32} + type: string + format: OrganizationSid + example: ORceef74a747c1ae8d837aafb5a31e475f + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ScimUser' + application/scim+json: + schema: + $ref: '#/components/schemas/ScimUser' + required: true + responses: + '201': + description: Created User + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimUser' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '400': + description: Bad request or business rules violation + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '401': + description: Unauthorized + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '403': + description: Forbidden + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '404': + description: Not found + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '429': + description: Too many requests + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + /Organizations/{organizationSid}/scim/Users/{userSid}: + servers: + - url: https://preview-iam.twilio.com + get: + tags: + - SCIM + summary: Get SCIM User + operationId: FetchOrganizationUser + parameters: + - name: organizationSid + in: path + required: true + schema: + pattern: OR[0-9a-f]{32} + type: string + format: OrganizationSid + example: OR5f3baf01a0f8273e74266afb84341766 + - name: userSid + in: path + required: true + schema: + pattern: US[0-9a-f]{32} + type: string + format: UserSid + example: USb51dccce9ac8e67b938253c7bcaa4f45 + responses: + '200': + description: User + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimUser' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '400': + description: Bad request or business rules violation + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '401': + description: Unauthorized + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '403': + description: Forbidden + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '404': + description: Not found + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '429': + description: Too many requests + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + put: + tags: + - SCIM + summary: Update SCIM User + operationId: UpdateOrganizationUser + parameters: + - name: If-Match + in: header + schema: + type: string + - name: organizationSid + in: path + required: true + schema: + pattern: OR[0-9a-f]{32} + type: string + format: OrganizationSid + example: ORd3a1c06d4942d123cd8fa2a052fe110a + - name: userSid + in: path + required: true + schema: + pattern: US[0-9a-f]{32} + type: string + format: UserSid + example: US14def5586bc0799a5c7aab80247af278 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ScimUser' + application/scim+json: + schema: + $ref: '#/components/schemas/ScimUser' + required: true + responses: + '200': + description: User object with updated attributes + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimUser' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '400': + description: Bad request or business rules violation + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '401': + description: Unauthorized + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '403': + description: Forbidden + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '404': + description: Not found + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '409': + description: Version conflict + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '429': + description: Too many requests + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + delete: + tags: + - SCIM + summary: Delete SCIM User + operationId: DeleteOrganizationUser + parameters: + - name: organizationSid + in: path + required: true + schema: + pattern: OR[0-9a-f]{32} + type: string + format: OrganizationSid + example: OR80b7392892f0a424d07c42f5b11dce2a + - name: userSid + in: path + required: true + schema: + pattern: US[0-9a-f]{32} + type: string + format: UserSid + example: US23c7d4510f1398849aaac5c543475b12 + responses: + '204': + description: No content + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '400': + description: Bad request or business rules violation + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '401': + description: Unauthorized + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '403': + description: Forbidden + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '404': + description: Not found + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + '429': + description: Too many requests + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: POST, OPTIONS + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: Content-Type, Authorization + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: X-Custom-Header1, X-Custom-Header2 + /v1/token: + servers: + - url: https://preview-iam.twilio.com + x-twilio: + defaultOutputProperties: [] + pathType: list + post: + security: [] + tags: + - OauthV1Token + summary: Issues a new Access token (optionally identity_token & refresh_token) + in exchange of Oauth grant + operationId: CreateToken + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/oauth.v1.token' + examples: + create: + value: + access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c + refresh_token: ghjbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c + id_token: eyJhbdGciOiIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c + expires_in: 1438315200000 + token_type: bearer + description: Created + requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + title: CreateTokenRequest + properties: + grant_type: + type: string + description: Grant type is a credential representing resource owner's + authorization which can be used by client to obtain access token. + client_id: + type: string + description: A 34 character string that uniquely identifies this + OAuth App. + client_secret: + type: string + description: The credential for confidential OAuth App. + code: + type: string + description: JWT token related to the authorization code grant type. + redirect_uri: + type: string + description: The redirect uri + audience: + type: string + description: The targeted audience uri + refresh_token: + type: string + description: JWT token related to refresh access token. + scope: + type: string + description: The scope of token + required: + - grant_type + - client_id + examples: + create: + value: + client_id: OQ7cda1a615f05a95634e643aaaf7081d7 + client_secret: sUWblrQ4wx_aYkdAWjHXNvHinynkYOgBoiRyEQUeEntpgDEG47qnBFD98yoEzsTh + grant_type: client_credentials + redirect_uri: '' + audience: '' + code: '' + refresh_token: refresh_token + scope: scope + required: true +components: + securitySchemes: + oAuth2ClientCredentials: + type: oauth2 + flows: + clientCredentials: + tokenUrl: https://oauth.twilio.com/v1/token + scopes: {} + schemas: + ScimUser: + required: + - userName + type: object + properties: + id: + type: string + description: Unique Twilio user sid + externalId: + maxLength: 255 + minLength: 2 + type: string + description: External unique resource id defined by provisioning client + userName: + maxLength: 255 + minLength: 2 + type: string + description: Unique username, MUST be same as primary email address + displayName: + maxLength: 255 + minLength: 0 + type: string + description: User friendly display name + name: + $ref: '#/components/schemas/ScimName' + emails: + maxItems: 2147483647 + minItems: 1 + type: array + description: Email address list of the user. Primary email must be defined + if there are more than 1 email. Primary email must match the username. + items: + $ref: '#/components/schemas/ScimEmailAddress' + active: + type: boolean + description: Indicates whether the user is active + locale: + type: string + description: User's locale + timezone: + type: string + description: User's time zone + schemas: + type: array + description: An array of URIs that indicate the schemas supported for this + user resource + items: + type: string + description: An array of URIs that indicate the schemas supported for + this user resource + meta: + $ref: '#/components/schemas/ScimMeta' + ScimUserPage: + type: object + properties: + Resources: + type: array + items: + $ref: '#/components/schemas/ScimUser' + totalResults: + type: integer + format: int32 + schemas: + type: array + items: + type: string + description: Scim ListResponse schema + ScimEmailAddress: + type: object + properties: + primary: + type: boolean + description: Indicates if this email address is the primary one + value: + maxLength: 160 + minLength: 2 + type: string + description: The actual email address value + type: + maxLength: 64 + minLength: 0 + type: string + description: The type of email address (e.g., work, home, etc.) + description: Email address list of the user. Primary email must be defined if + there are more than 1 email. Primary email must match the username. + ScimMeta: + type: object + properties: + resourceType: + type: string + description: Indicates the type of the resource + created: + type: string + description: The date and time when the resource was created in the system + format: date-time + lastModified: + type: string + description: The date and time when the resource was last modified + format: date-time + version: + type: string + description: A version identifier for the resource. This can be used to + manage resource versioning and concurrency control. + description: Meta + ScimName: + type: object + properties: + givenName: + maxLength: 255 + minLength: 0 + type: string + description: The user's first or given name + familyName: + maxLength: 255 + minLength: 0 + type: string + description: The user's last or family name + TestAnyType: + description: This is any type object + description: User's name + ScimResourceTypes: + type: object + properties: + Resources: + type: array + items: + type: object + properties: + name: + type: string + description: Name of the resource type + description: + type: string + description: Description of the resource type + endpoint: + type: string + description: HTTP-addressable endpoint relative to the Base URL of + the service provider + schema: + type: string + description: Primary/base schema URI + JsonPatch: + type: object + properties: + op: + type: string + enum: + - add + - remove + - replace + path: + type: string + value: + type: string + TwilioServiceErrorResponse: + type: object + properties: + code: + description: Twilio-specific error code + type: integer + format: int32 + message: + description: Error message + type: string + moreInfo: + description: Link to Error Code References + type: string + status: + description: HTTP response status code + type: integer + format: int32 + ScimError: + type: object + properties: + schemas: + type: array + description: Schema URIs that define the contents of the error structure + items: + type: string + description: Schema URIs that define the contents of the error structure + detail: + type: string + description: A human-readable description of the error + scimType: + type: string + description: A scimType error code as defined in RFC7644 + enum: + - invalidFilter + - uniqueness + - mutability + - invalidValue + - invalidSyntax + status: + type: string + description: Http status code + code: + description: Twilio-specific error code + type: integer + format: int32 + moreInfo: + description: Link to Error Code References + type: string + oauth.v1.token: + type: object + properties: + access_token: + type: string + nullable: true + description: Token which carries the necessary information to access a Twilio + resource directly. + refresh_token: + type: string + nullable: true + description: Token which carries the information necessary to get a new + access token. + id_token: + type: string + nullable: true + description: Token which carries the information necessary of user profile. + token_type: + type: string + nullable: true + description: Token type + expires_in: + type: integer + format: int64 + nullable: true diff --git a/specs_test/twilio_iam_organizations_v1.yaml b/specs_test/twilio_iam_organizations_v1.yaml new file mode 100644 index 000000000..65e71658c --- /dev/null +++ b/specs_test/twilio_iam_organizations_v1.yaml @@ -0,0 +1,572 @@ +openapi: 3.0.1 +security: + - oAuth2ClientCredentials: [] +info: + title: Organization Public API + contact: + name: Twilio Support + url: https://support.twilio.com + email: support@twilio.com + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + version: 1.0.0 +tags: + - name: SCIM + description: SCIM 2.0 User endpoints + - name: OrganizationAccount + description: Organization Account operations + - name: RoleAssignments + description: Role assignment operations + - name: OauthV1Authorize + - name: OauthV1Token +paths: + "/v1/authorize": + servers: + - url: https://preview-iam.twilio.com + x-twilio: + defaultOutputProperties: + - redirect_to + pathType: list + get: + tags: + - OauthV1Authorize + security: [] + summary: Retrieves authorize uri + operationId: FetchAuthorize + parameters: + - name: response_type + in: query + description: Response Type + schema: + type: string + example: code + - name: client_id + in: query + description: The Client Identifier + schema: + type: string + example: OQ7cda1a615f05a95634e643aaaf7081d7 + - name: redirect_uri + in: query + description: The url to which response will be redirected to + schema: + type: string + example: www.twilio.com + - name: scope + in: query + description: The scope of the access request + schema: + type: string + example: offline_access + - name: state + in: query + description: An opaque value which can be used to maintain state between the + request and callback + schema: + type: string + example: xvz + responses: + '302': + content: + application/json: + schema: + "$ref": "#/components/schemas/oauth.v1.authorize" + examples: + fetch: + value: + redirect_to: https://www.twilio.com/authorize?response_type=code&client_id=OQ7cda1a615f05a95634e643aaaf7081d7&redirect_uri=www.twilio.com&scope=offline_access&state=xvz + description: Found + "/v1/token": + servers: + - url: https://preview-iam.twilio.com + x-twilio: + defaultOutputProperties: [] + pathType: list + post: + security: [] + tags: + - OauthV1Token + summary: Issues a new Access token (optionally identity_token & refresh_token) + in exchange of Oauth grant + operationId: CreateToken + responses: + '201': + content: + application/json: + schema: + "$ref": "#/components/schemas/oauth.v1.token" + examples: + create: + value: + access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c + refresh_token: ghjbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c + id_token: eyJhbdGciOiIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c + expires_in: 1438315200000 + token_type: bearer + description: Created + requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + title: CreateTokenRequest + properties: + grant_type: + type: string + description: Grant type is a credential representing resource owner's + authorization which can be used by client to obtain access token. + client_id: + type: string + description: A 34 character string that uniquely identifies this + OAuth App. + client_secret: + type: string + description: The credential for confidential OAuth App. + code: + type: string + description: JWT token related to the authorization code grant type. + redirect_uri: + type: string + description: The redirect uri + audience: + type: string + description: The targeted audience uri + refresh_token: + type: string + description: JWT token related to refresh access token. + scope: + type: string + description: The scope of token + required: + - grant_type + - client_id + examples: + create: + value: + client_id: OQ7cda1a615f05a95634e643aaaf7081d7 + client_secret: sUWblrQ4wx_aYkdAWjHXNvHinynkYOgBoiRyEQUeEntpgDEG47qnBFD98yoEzsTh + grant_type: client_credentials + redirect_uri: '' + audience: '' + code: '' + refresh_token: refresh_token + scope: scope + required: true +components: + securitySchemes: + oAuth2ClientCredentials: + type: oauth2 + flows: + clientCredentials: + tokenUrl: https://preview-iam.twilio.com/v1/token + scopes: {} + schemas: + ScimUser: + required: + - userName + type: object + properties: + id: + type: string + description: Unique Twilio user sid + externalId: + maxLength: 255 + minLength: 2 + type: string + description: External unique resource id defined by provisioning client + userName: + maxLength: 255 + minLength: 2 + type: string + description: Unique username, MUST be same as primary email address + displayName: + maxLength: 255 + minLength: 0 + type: string + description: User friendly display name + name: + "$ref": "#/components/schemas/ScimName" + emails: + maxItems: 2147483647 + minItems: 1 + type: array + description: Email address list of the user. Primary email must be defined + if there are more than 1 email. Primary email must match the username. + items: + "$ref": "#/components/schemas/ScimEmailAddress" + active: + type: boolean + description: Indicates whether the user is active + locale: + type: string + description: User's locale + timezone: + type: string + description: User's time zone + schemas: + type: array + description: An array of URIs that indicate the schemas supported for this + user resource + items: + type: string + description: An array of URIs that indicate the schemas supported for + this user resource + meta: + "$ref": "#/components/schemas/ScimMeta" + ScimUserPage: + type: object + properties: + Resources: + type: array + items: + "$ref": "#/components/schemas/ScimUser" + totalResults: + type: integer + format: int32 + schemas: + type: array + items: + type: string + description: Scim ListResponse schema + ScimEmailAddress: + type: object + properties: + primary: + type: boolean + description: Indicates if this email address is the primary one + value: + maxLength: 160 + minLength: 2 + type: string + description: The actual email address value + type: + maxLength: 64 + minLength: 0 + type: string + description: The type of email address (e.g., work, home, etc.) + description: Email address list of the user. Primary email must be defined if + there are more than 1 email. Primary email must match the username. + ScimMeta: + type: object + properties: + resourceType: + type: string + description: Indicates the type of the resource + created: + type: string + description: The date and time when the resource was created in the system + format: date-time + lastModified: + type: string + description: The date and time when the resource was last modified + format: date-time + version: + type: string + description: A version identifier for the resource. This can be used to + manage resource versioning and concurrency control. + description: Meta + ScimName: + type: object + properties: + givenName: + maxLength: 255 + minLength: 0 + type: string + description: The user's first or given name + familyName: + maxLength: 255 + minLength: 0 + type: string + description: The user's last or family name + description: User's name + ScimResourceTypes: + type: object + properties: + Resources: + type: array + items: + type: object + properties: + name: + type: string + description: Name of the resource type + description: + type: string + description: Description of the resource type + endpoint: + type: string + description: HTTP-addressable endpoint relative to the Base URL of + the service provider + schema: + type: string + description: Primary/base schema URI + JsonPatch: + type: object + properties: + op: + type: string + enum: + - add + - remove + - replace + path: + type: string + value: + type: string + PublicApiCreateAccountRequest: + required: + - friendlyName + type: object + properties: + friendlyName: + maxLength: 255 + minLength: 1 + type: string + description: Account friendly name + ownerSid: + pattern: US[0-9a-f]{32} + type: string + description: Optional owner sid. If not provided, the owner will be the + organization owner. + format: UserSid + example: USa4faef6467378082de67039e533b515a + PublicApiCreateAccountResponse: + type: object + properties: + accountSid: + pattern: AC[0-9a-f]{32} + type: string + description: Twilio account sid for the new account, creation is asynchronous + owner. + format: AccountSid + example: ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + PublicApiAccountResponse: + type: object + properties: + account_sid: + pattern: AC[0-9a-f]{32} + type: string + description: Twilio account sid + format: AccountSid + example: ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + friendly_name: + type: string + description: Account friendly name + status: + type: string + description: Account status + example: active + enum: + - active + - suspended + - pending_closure + - closed + owner_sid: + pattern: US[0-9a-f]{32} + type: string + description: Twilio account sid + format: UserSid + example: US9a6d63d00bdbb50aa1c1889b3066bd30 + date_created: + type: string + description: The date and time when the account was created in the system + format: date-time + description: Page content + PublicApiAccountResponsePage: + type: object + properties: + content: + type: array + description: Page content + items: + "$ref": "#/components/schemas/PublicApiAccountResponse" + meta: + properties: + first_page_url: + format: uri + type: string + key: + type: string + next_page_url: + format: uri + nullable: true + type: string + page: + type: integer + page_size: + type: integer + previous_page_url: + format: uri + nullable: true + type: string + url: + format: uri + type: string + type: object + PublicApiCreateRoleAssignmentRequest: + required: + - role_sid + - scope + - identity + type: object + properties: + role_sid: + pattern: IX[0-9a-f]{32} + type: string + description: Twilio Role Sid representing assigned role + format: IamRoleSid + example: IXc4ddb9d0befdb122b0eff334e3084544 + scope: + pattern: "^[A-Z]{2}[0-9a-fA-F]{32}$" + type: string + description: Twilio Sid representing scope of this assignment + format: Sid + example: ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + identity: + pattern: "^[A-Z]{2}[0-9a-fA-F]{32}$" + type: string + description: Twilio Sid representing identity of this assignment + format: Sid + example: USc4ddb9d0befdb122b0eff334e3084544 + PublicApiCreateRoleAssignmentResponsePage: + type: object + properties: + content: + type: array + description: Page content + items: + "$ref": "#/components/schemas/PublicApiRoleAssignmentResponse" + meta: + properties: + first_page_url: + format: uri + type: string + key: + type: string + next_page_url: + format: uri + nullable: true + type: string + page: + type: integer + page_size: + type: integer + previous_page_url: + format: uri + nullable: true + type: string + url: + format: uri + type: string + type: object + PublicApiRoleAssignmentResponse: + type: object + properties: + sid: + pattern: IY[0-9a-f]{32} + type: string + description: Twilio Role Assignment Sid representing this role assignment + format: IamRoleAssignmentSid + example: IYc4ddb9d0befdb122b0eff334e3084544 + role_sid: + pattern: IX[0-9a-f]{32} + type: string + description: Twilio Role Sid representing assigned role + format: IamRoleSid + example: IXc4ddb9d0befdb122b0eff334e3084544 + scope: + pattern: "^[A-Z]{2}[0-9a-fA-F]{32}$" + type: string + description: Twilio Sid representing identity of this assignment + format: Sid + example: ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + identity: + pattern: "^[A-Z]{2}[0-9a-fA-F]{32}$" + type: string + description: Twilio Sid representing scope of this assignment + format: Sid + example: USc4ddb9d0befdb122b0eff334e3084544 + TwilioServiceErrorResponse: + type: object + properties: + code: + description: Twilio-specific error code + type: integer + format: int32 + message: + description: Error message + type: string + moreInfo: + description: Link to Error Code References + type: string + status: + description: HTTP response status code + type: integer + format: int32 + ScimError: + type: object + properties: + schemas: + type: array + description: Schema URIs that define the contents of the error structure + items: + type: string + description: Schema URIs that define the contents of the error structure + detail: + type: string + description: A human-readable description of the error + scimType: + type: string + description: A scimType error code as defined in RFC7644 + enum: + - invalidFilter + - uniqueness + - mutability + - invalidValue + - invalidSyntax + status: + type: string + description: Http status code + code: + description: Twilio-specific error code + type: integer + format: int32 + moreInfo: + description: Link to Error Code References + type: string + oauth.v1.authorize: + type: object + properties: + redirect_to: + type: string + format: uri + nullable: true + description: The callback URL + oauth.v1.token: + type: object + properties: + access_token: + type: string + nullable: true + description: Token which carries the necessary information to access a Twilio + resource directly. + refresh_token: + type: string + nullable: true + description: Token which carries the information necessary to get a new + access token. + id_token: + type: string + nullable: true + description: Token which carries the information necessary of user profile. + token_type: + type: string + nullable: true + description: Token type + expires_in: + type: integer + format: int64 + nullable: true +servers: + - url: https://preview-iam.twilio.com diff --git a/specs_test/twilio_iam_organizations_versionless.yaml b/specs_test/twilio_iam_organizations_versionless.yaml new file mode 100644 index 000000000..dfbcda84b --- /dev/null +++ b/specs_test/twilio_iam_organizations_versionless.yaml @@ -0,0 +1,2233 @@ +openapi: 3.0.1 +security: + - oAuth2ClientCredentials: [] +info: + title: Organization Public API + contact: + name: Twilio Support + url: 'https://support.twilio.com' + email: support@twilio.com + license: + name: Apache 2.0 + url: 'https://www.apache.org/licenses/LICENSE-2.0.html' + version: 1.0.0 +tags: + - name: SCIM + description: SCIM 2.0 User endpoints + - name: OrganizationAccount + description: Organization Account operations + - name: RoleAssignments + description: Role assignment operations + - name: OauthV1Authorize + - name: OauthV1Token +paths: + '/Organizations/{OrganizationSid}': + x-twilio: + dependentProperties: + users: + mapping: + organization_sid: organization_sid + resource_url: '/Organizations/{organization_sid}/scim/Users' + accounts: + mapping: + organization_sid: organization_sid + resource_url: '/Organizations/{organization_sid}/Accounts' + roleAssignments: + mapping: + organization_sid: organization_sid + resource_url: '/Organizations/{organization_sid}/RoleAssignments' + pathType: instance + mountName: organization + servers: + - url: 'https://preview-iam.twilio.com' + get: + summary: List SCIM Users + operationId: FetchOrganization + parameters: + - name: OrganizationSid + in: path + required: true + schema: + pattern: 'OR[0-9a-f]{32}' + type: string + format: OrganizationSid + example: OR33f4f3aa6fffe840d000f8ef22e883db + x-twilio: + ignoreOperation: true + responses: + '403': + description: Forbidden + content: + application/scim+json: + schema: {} + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '/Organizations/{OrganizationSid}/scim/ResourceTypes': + servers: + - url: 'https://preview-iam.twilio.com' + x-twilio: + pathType: list + parent: '/{OrganizationSid}' + '/Organizations/{OrganizationSid}/scim/Users': + servers: + - url: 'https://preview-iam.twilio.com' + get: + tags: + - SCIM + summary: List SCIM Users + operationId: ListOrganizationUsers + parameters: + - name: OrganizationSid + in: path + required: true + schema: + pattern: 'OR[0-9a-f]{32}' + type: string + format: OrganizationSid + example: OR33f4f3aa6fffe840d000f8ef22e883db + - name: filter + in: query + schema: + type: string + responses: + '200': + description: List of users + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimUserPage' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '400': + description: Bad request or business rules violation + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '401': + description: Unauthorized + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '403': + description: Forbidden + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '429': + description: Too many requests + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + post: + tags: + - SCIM + summary: Create SCIM User + operationId: CreateOrganizationUser + parameters: + - name: OrganizationSid + in: path + required: true + schema: + pattern: 'OR[0-9a-f]{32}' + type: string + format: OrganizationSid + example: ORceef74a747c1ae8d837aafb5a31e475f + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ScimUser' + application/scim+json: + schema: + $ref: '#/components/schemas/ScimUser' + required: true + responses: + '201': + description: Created User + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimUser' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '400': + description: Bad request or business rules violation + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '401': + description: Unauthorized + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '403': + description: Forbidden + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '404': + description: Not found + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '429': + description: Too many requests + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + x-twilio: + pathType: list + parent: '/{OrganizationSid}' + '/Organizations/{OrganizationSid}/scim/Users/{Id}': + servers: + - url: 'https://preview-iam.twilio.com' + get: + tags: + - SCIM + summary: Get SCIM User + operationId: FetchOrganizationUser + parameters: + - name: OrganizationSid + in: path + required: true + schema: + pattern: 'OR[0-9a-f]{32}' + type: string + format: OrganizationSid + example: OR5f3baf01a0f8273e74266afb84341766 + - name: Id + in: path + required: true + schema: + pattern: 'US[0-9a-f]{32}' + type: string + format: Id + example: USb51dccce9ac8e67b938253c7bcaa4f45 + responses: + '200': + description: User + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimUser' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '400': + description: Bad request or business rules violation + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '401': + description: Unauthorized + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '403': + description: Forbidden + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '404': + description: Not found + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '429': + description: Too many requests + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + put: + tags: + - SCIM + summary: Update SCIM User + operationId: UpdateOrganizationUser + parameters: + - name: If-Match + in: header + schema: + type: string + - name: OrganizationSid + in: path + required: true + schema: + pattern: 'OR[0-9a-f]{32}' + type: string + format: OrganizationSid + example: ORd3a1c06d4942d123cd8fa2a052fe110a + - name: Id + in: path + required: true + schema: + pattern: 'US[0-9a-f]{32}' + type: string + format: Id + example: US14def5586bc0799a5c7aab80247af278 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ScimUser' + application/scim+json: + schema: + $ref: '#/components/schemas/ScimUser' + required: true + responses: + '200': + description: User object with updated attributes + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimUser' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '400': + description: Bad request or business rules violation + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '401': + description: Unauthorized + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '403': + description: Forbidden + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '404': + description: Not found + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '409': + description: Version conflict + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '429': + description: Too many requests + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + delete: + tags: + - SCIM + summary: Delete SCIM User + operationId: DeleteOrganizationUser + parameters: + - name: OrganizationSid + in: path + required: true + schema: + pattern: 'OR[0-9a-f]{32}' + type: string + format: OrganizationSid + example: OR80b7392892f0a424d07c42f5b11dce2a + - name: Id + in: path + required: true + schema: + pattern: 'US[0-9a-f]{32}' + type: string + format: Id + example: US23c7d4510f1398849aaac5c543475b12 + responses: + '204': + description: No content + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '400': + description: Bad request or business rules violation + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '401': + description: Unauthorized + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '403': + description: Forbidden + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '404': + description: Not found + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '429': + description: Too many requests + content: + application/scim+json: + schema: + $ref: '#/components/schemas/ScimError' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + x-twilio: + pathType: instance + parent: '/{OrganizationSid}' + '/Organizations/{OrganizationSid}/Accounts': + servers: + - url: 'https://preview-iam.twilio.com' + get: + tags: + - OrganizationAccounts + summary: List organization accounts + operationId: ListOrganizationAccounts + parameters: + - name: OrganizationSid + in: path + required: true + schema: + pattern: 'OR[0-9a-f]{32}' + type: string + format: OrganizationSid + example: ORa36de9717566c7eb6363671f54b87ba9 + - name: PageSize + in: query + schema: + maximum: 100 + minimum: 1 + type: integer + format: int32 + default: 50 + - name: PageToken + in: query + schema: + maxLength: 4096 + minLength: 1 + type: string + responses: + '200': + description: Organization account list + content: + application/json: + schema: + $ref: '#/components/schemas/PublicApiAccountResponsePage' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '403': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/TwilioServiceErrorResponse' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '404': + description: Account not found + content: + application/json: + schema: + $ref: '#/components/schemas/TwilioServiceErrorResponse' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + x-twilio: + pathType: list + parent: '/{OrganizationSid}' + '/Organizations/{OrganizationSid}/Accounts/{AccountSid}': + servers: + - url: 'https://preview-iam.twilio.com' + get: + tags: + - OrganizationAccounts + summary: Get details of organization account + operationId: FetchOrganizationAccount + parameters: + - name: OrganizationSid + in: path + required: true + schema: + pattern: 'OR[0-9a-f]{32}' + type: string + format: OrganizationSid + example: ORf9618e7f043b4bc13832e4946fde06c9 + - name: AccountSid + in: path + required: true + schema: + pattern: 'AC[0-9a-f]{32}' + type: string + format: AccountSid + example: ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + responses: + '200': + description: Get details of organization account + content: + application/json: + schema: + $ref: '#/components/schemas/PublicApiAccountResponse' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '403': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/TwilioServiceErrorResponse' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '404': + description: Account does not belong to Organization + content: + application/json: + schema: + $ref: '#/components/schemas/TwilioServiceErrorResponse' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + x-twilio: + pathType: instance + parent: '/{OrganizationSid}' + '/Organizations/{OrganizationSid}/RoleAssignments': + servers: + - url: 'https://preview-iam.twilio.com' + get: + tags: + - RoleAssignments + summary: List role assignments + description: List role assignments for the given organization + operationId: ListRoleAssignments + parameters: + - name: OrganizationSid + in: path + required: true + schema: + pattern: 'OR[0-9a-f]{32}' + type: string + format: OrganizationSid + example: OR33f4f3aa6fffe840d000f8ef22e883db + - name: PageSize + in: query + schema: + maximum: 100 + minimum: 1 + type: integer + format: int32 + default: 100 + - name: PageToken + in: query + schema: + maxLength: 4096 + minLength: 1 + type: string + - name: Identity + in: query + required: false + schema: + pattern: '^[A-Z]{2}[0-9a-fA-F]{32}$' + type: string + format: Sid + example: USa36de9717566c7eb6363671f54b87ba9 + - name: Scope + in: query + required: false + schema: + pattern: '^[A-Z]{2}[0-9a-fA-F]{32}$' + type: string + format: Sid + example: ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + responses: + '200': + description: Returned list of role assignments + content: + application/json: + schema: + $ref: '#/components/schemas/PublicApiCreateRoleAssignmentResponsePage' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/TwilioServiceErrorResponse' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '403': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/TwilioServiceErrorResponse' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + post: + tags: + - RoleAssignments + summary: Create a role assignment + description: Create a role assignment for the given organization + operationId: CreateRoleAssignment + parameters: + - name: OrganizationSid + in: path + required: true + schema: + pattern: 'OR[0-9a-f]{32}' + type: string + format: OrganizationSid + example: ORa36de9717566c7eb6363671f54b87ba9 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PublicApiCreateRoleAssignmentRequest' + required: true + responses: + '201': + description: Created + content: + application/json: + schema: + $ref: '#/components/schemas/PublicApiRoleAssignmentResponse' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '400': + description: Bad request or business rules violation + content: + application/scim+json: + schema: + $ref: '#/components/schemas/TwilioServiceErrorResponse' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '403': + description: Unauthorized + content: + application/scim+json: + schema: + $ref: '#/components/schemas/TwilioServiceErrorResponse' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + x-twilio: + pathType: list + parent: '/{OrganizationSid}' + '/Organizations/{OrganizationSid}/RoleAssignments/{Sid}': + servers: + - url: 'https://preview-iam.twilio.com' + delete: + tags: + - RoleAssignments + summary: Delete a role assignment + description: Delete a role assignment for the given organization + operationId: DeleteRoleAssignment + parameters: + - name: OrganizationSid + in: path + required: true + schema: + pattern: 'OR[0-9a-f]{32}' + type: string + format: OrganizationSid + example: ORa36de9717566c7eb6363671f54b87ba9 + - name: Sid + in: path + required: true + schema: + pattern: 'IY[0-9a-f]{32}' + type: string + format: IamSid + example: IYa36de9717566c7eb6363671f54b87ba9 + responses: + '204': + description: No content + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '400': + description: Invalid request provided + content: + application/scim+json: + schema: + $ref: '#/components/schemas/TwilioServiceErrorResponse' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + '403': + description: Unauthorized + content: + application/scim+json: + schema: + $ref: '#/components/schemas/TwilioServiceErrorResponse' + headers: + Access-Control-Allow-Origin: + description: Specify the origin(s) allowed to access the resource + schema: + type: string + example: '*' + Access-Control-Allow-Methods: + description: Specify the HTTP methods allowed when accessing the resource + schema: + type: string + example: 'POST, OPTIONS' + Access-Control-Allow-Headers: + description: Specify the headers allowed when accessing the resource + schema: + type: string + example: 'Content-Type, Authorization' + Access-Control-Allow-Credentials: + description: Indicates whether the browser should include credentials + schema: + type: boolean + Access-Control-Expose-Headers: + description: Headers exposed to the client + schema: + type: string + example: 'X-Custom-Header1, X-Custom-Header2' + x-twilio: + pathType: instance + parent: '/{OrganizationSid}' +components: + securitySchemes: + oAuth2ClientCredentials: + type: oauth2 + flows: + clientCredentials: + tokenUrl: 'https://preview-iam.twilio.com/v1/token' + scopes: {} + schemas: + ScimUser: + required: + - userName + type: object + properties: + id: + type: string + description: Unique Twilio user sid + externalId: + maxLength: 255 + minLength: 2 + type: string + description: External unique resource id defined by provisioning client + userName: + maxLength: 255 + minLength: 2 + type: string + description: 'Unique username, MUST be same as primary email address' + displayName: + maxLength: 255 + minLength: 0 + type: string + description: User friendly display name + name: + $ref: '#/components/schemas/ScimName' + emails: + maxItems: 2147483647 + minItems: 1 + type: array + description: >- + Email address list of the user. Primary email must be defined if + there are more than 1 email. Primary email must match the username. + items: + $ref: '#/components/schemas/ScimEmailAddress' + active: + type: boolean + description: Indicates whether the user is active + locale: + type: string + description: User's locale + timezone: + type: string + description: User's time zone + schemas: + type: array + description: >- + An array of URIs that indicate the schemas supported for this user + resource + items: + type: string + description: >- + An array of URIs that indicate the schemas supported for this user + resource + meta: + $ref: '#/components/schemas/ScimMeta' + ScimUserPage: + type: object + properties: + Resources: + type: array + items: + $ref: '#/components/schemas/ScimUser' + totalResults: + type: integer + format: int32 + schemas: + type: array + items: + type: string + description: Scim ListResponse schema + ScimEmailAddress: + type: object + properties: + primary: + type: boolean + description: Indicates if this email address is the primary one + value: + maxLength: 160 + minLength: 2 + type: string + description: The actual email address value + type: + maxLength: 64 + minLength: 0 + type: string + description: 'The type of email address (e.g., work, home, etc.)' + description: >- + Email address list of the user. Primary email must be defined if there + are more than 1 email. Primary email must match the username. + ScimMeta: + type: object + properties: + resourceType: + type: string + description: Indicates the type of the resource + created: + type: string + description: The date and time when the resource was created in the system + format: date-time + lastModified: + type: string + description: The date and time when the resource was last modified + format: date-time + version: + type: string + description: >- + A version identifier for the resource. This can be used to manage + resource versioning and concurrency control. + description: Meta + ScimName: + type: object + properties: + givenName: + maxLength: 255 + minLength: 0 + type: string + description: The user's first or given name + familyName: + maxLength: 255 + minLength: 0 + type: string + description: The user's last or family name + description: User's name + ScimResourceTypes: + type: object + properties: + Resources: + type: array + items: + type: object + properties: + name: + type: string + description: Name of the resource type + description: + type: string + description: Description of the resource type + endpoint: + type: string + description: >- + HTTP-addressable endpoint relative to the Base URL of the + service provider + schema: + type: string + description: Primary/base schema URI + ScimPatchRequest: + type: object + properties: + schemas: + type: array + items: + type: string + Operations: + type: array + items: + $ref: '#/components/schemas/ScimPatchOperation' + ScimPatchOperation: + type: object + properties: + op: + type: string + description: The operation to perform + path: + type: string + value: + type: object + JsonPatch: + type: object + properties: + op: + type: string + enum: + - add + - remove + - replace + path: + type: string + value: + type: string + PublicApiCreateAccountRequest: + required: + - friendlyName + type: object + properties: + friendlyName: + maxLength: 255 + minLength: 1 + type: string + description: Account friendly name + ownerSid: + pattern: 'US[0-9a-f]{32}' + type: string + description: >- + Optional owner sid. If not provided, the owner will be the + organization owner. + format: Id + example: USa4faef6467378082de67039e533b515a + PublicApiCreateAccountResponse: + type: object + properties: + accountSid: + pattern: 'AC[0-9a-f]{32}' + type: string + description: >- + Twilio account sid for the new account, creation is asynchronous + owner. + format: AccountSid + example: ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + PublicApiAccountResponse: + type: object + properties: + account_sid: + pattern: 'AC[0-9a-f]{32}' + type: string + description: Twilio account sid + format: AccountSid + example: ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + friendly_name: + type: string + description: Account friendly name + status: + type: string + description: Account status + example: active + enum: + - active + - suspended + - pending_closure + - closed + owner_sid: + pattern: 'US[0-9a-f]{32}' + type: string + description: Twilio account sid + format: Id + example: US9a6d63d00bdbb50aa1c1889b3066bd30 + date_created: + type: string + description: The date and time when the account was created in the system + format: date-time + description: Page content + PublicApiAccountResponsePage: + type: object + properties: + content: + type: array + description: Page content + items: + $ref: '#/components/schemas/PublicApiAccountResponse' + meta: + properties: + first_page_url: + format: uri + type: string + key: + type: string + next_page_url: + format: uri + nullable: true + type: string + page: + type: integer + page_size: + type: integer + previous_page_url: + format: uri + nullable: true + type: string + url: + format: uri + type: string + type: object + PublicApiCreateRoleAssignmentRequest: + required: + - role_sid + - scope + - identity + type: object + properties: + role_sid: + pattern: 'IX[0-9a-f]{32}' + type: string + description: Twilio Role Sid representing assigned role + format: IamRoleSid + example: IXc4ddb9d0befdb122b0eff334e3084544 + scope: + pattern: '^[A-Z]{2}[0-9a-fA-F]{32}$' + type: string + description: Twilio Sid representing scope of this assignment + format: Sid + example: ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + identity: + pattern: '^[A-Z]{2}[0-9a-fA-F]{32}$' + type: string + description: Twilio Sid representing identity of this assignment + format: Sid + example: USc4ddb9d0befdb122b0eff334e3084544 + PublicApiCreateRoleAssignmentResponsePage: + type: object + properties: + content: + type: array + description: Page content + items: + $ref: '#/components/schemas/PublicApiRoleAssignmentResponse' + meta: + properties: + first_page_url: + format: uri + type: string + key: + type: string + next_page_url: + format: uri + nullable: true + type: string + page: + type: integer + page_size: + type: integer + previous_page_url: + format: uri + nullable: true + type: string + url: + format: uri + type: string + type: object + PublicApiRoleAssignmentResponse: + type: object + properties: + sid: + pattern: 'IY[0-9a-f]{32}' + type: string + description: Twilio Role Assignment Sid representing this role assignment + format: IamSid + example: IYc4ddb9d0befdb122b0eff334e3084544 + role_sid: + pattern: 'IX[0-9a-f]{32}' + type: string + description: Twilio Role Sid representing assigned role + format: IamRoleSid + example: IXc4ddb9d0befdb122b0eff334e3084544 + scope: + pattern: '^[A-Z]{2}[0-9a-fA-F]{32}$' + type: string + description: Twilio Sid representing identity of this assignment + format: Sid + example: ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + identity: + pattern: '^[A-Z]{2}[0-9a-fA-F]{32}$' + type: string + description: Twilio Sid representing scope of this assignment + format: Sid + example: USc4ddb9d0befdb122b0eff334e3084544 + TwilioServiceErrorResponse: + type: object + properties: + code: + description: Twilio-specific error code + type: integer + format: int32 + message: + description: Error message + type: string + moreInfo: + description: Link to Error Code References + type: string + status: + description: HTTP response status code + type: integer + format: int32 + ScimError: + type: object + properties: + schemas: + type: array + description: Schema URIs that define the contents of the error structure + items: + type: string + description: Schema URIs that define the contents of the error structure + detail: + type: string + description: A human-readable description of the error + scimType: + type: string + description: A scimType error code as defined in RFC7644 + enum: + - invalidFilter + - uniqueness + - mutability + - invalidValue + - invalidSyntax + status: + type: string + description: Http status code + code: + description: Twilio-specific error code + type: integer + format: int32 + moreInfo: + description: Link to Error Code References + type: string + oauth.v1.authorize: + type: object + properties: + redirect_to: + type: string + format: uri + nullable: true + description: The callback URL + oauth.v1.token: + type: object + properties: + access_token: + type: string + nullable: true + description: >- + Token which carries the necessary information to access a Twilio + resource directly. + refresh_token: + type: string + nullable: true + description: >- + Token which carries the information necessary to get a new access + token. + id_token: + type: string + nullable: true + description: Token which carries the information necessary of user profile. + token_type: + type: string + nullable: true + description: Token type + expires_in: + type: integer + format: int64 + nullable: true +servers: + - url: 'https://preview-iam.twilio.com' diff --git a/src/main/java/com/twilio/oai/DirectoryStructureService.java b/src/main/java/com/twilio/oai/DirectoryStructureService.java index 339eda529..e2b3e118e 100644 --- a/src/main/java/com/twilio/oai/DirectoryStructureService.java +++ b/src/main/java/com/twilio/oai/DirectoryStructureService.java @@ -251,10 +251,9 @@ public List processOperations(final OperationsMap results) { for(CodegenOperation co : operations){ if(co.produces != null) for(Map map : co.produces){ - Map.Entry firstEntry = map.entrySet().iterator().next(); List> successProduce = new ArrayList<>(); Map successMap = new HashMap<>(); - successMap.put(firstEntry.getKey(), firstEntry.getValue()); + successMap.putAll(map); successProduce.add(successMap); co.vendorExtensions.put("successProduce", successProduce); break; diff --git a/src/main/java/com/twilio/oai/LoggerUtil.java b/src/main/java/com/twilio/oai/LoggerUtil.java new file mode 100644 index 000000000..6ee6c8d48 --- /dev/null +++ b/src/main/java/com/twilio/oai/LoggerUtil.java @@ -0,0 +1,26 @@ +package com.twilio.oai; + +import java.util.logging.Logger; + + +import java.util.logging.Logger; + +public class LoggerUtil { + private static final Logger LOGGER = Logger.getLogger(LoggerUtil.class.getName()); + + private LoggerUtil() { + // Private constructor to prevent instantiation + } + + public static void logWarning(String className, String message) { + LOGGER.warning("[" + className + "] " + message); + } + + public static void logInfo(String className, String message) { + LOGGER.info("[" + className + "] " + message); + } + + public static void logSevere(String className, String message) { + LOGGER.severe("[" + className + "] " + message); + } +} diff --git a/src/main/java/com/twilio/oai/TwilioJavaGenerator.java b/src/main/java/com/twilio/oai/TwilioJavaGenerator.java index dbd6f9981..16a327730 100644 --- a/src/main/java/com/twilio/oai/TwilioJavaGenerator.java +++ b/src/main/java/com/twilio/oai/TwilioJavaGenerator.java @@ -157,12 +157,12 @@ protected ImmutableMap.Builder addMustacheLambdas() { @Override public String getName() { - return EnumConstants.Generator.TWILIO_JAVA.getValue(); + return EnumConstants.Generator.TWILIO_JAVA_LEGACY.getValue(); } @Override public String getHelp() { - return "Generates the twilio-java helper library."; + return "Generates the twilio-java-legacy helper library."; } private JavaApiResources processCodegenOperations(List opList) { @@ -174,7 +174,7 @@ private JavaApiResources processCodegenOperations(List opList) .updateApiPath() .updateTemplate(); final Boolean isIngress = twilioCodegen.getToggles(JSON_INGRESS). - get(EnumConstants.Generator.TWILIO_JAVA.getValue()); + get(EnumConstants.Generator.TWILIO_JAVA_LEGACY.getValue()); javaApiResourceBuilder.updateOperations(new JavaParameterResolver(conventionMapper)) .updateResponseModel(new JavaPropertyResolver(conventionMapper), codegenModelResolver); if (isIngress) { diff --git a/src/main/java/com/twilio/oai/TwilioJavaGeneratorModern.java b/src/main/java/com/twilio/oai/TwilioJavaGeneratorModern.java new file mode 100644 index 000000000..20cb24a60 --- /dev/null +++ b/src/main/java/com/twilio/oai/TwilioJavaGeneratorModern.java @@ -0,0 +1,164 @@ +package com.twilio.oai; + +import com.google.common.collect.ImmutableMap; +import com.samskivert.mustache.Mustache.Lambda; +import com.twilio.oai.common.ApplicationConstants; +import com.twilio.oai.common.EnumConstants; +import com.twilio.oai.common.Utility; +import com.twilio.oai.java.JavaApiResource; +import com.twilio.oai.java.JavaApiResourceBuilder; +import com.twilio.oai.java.JavaTemplateUpdater; +import com.twilio.oai.java.cache.ResourceCache2; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.format.JavaUpdateDefaultMapping; +import com.twilio.oai.resolver.java.JavaCaseResolver; +import com.twilio.oai.resource.ResourceMap; +import com.twilio.oai.templating.mustache.ReplaceHyphenLambda; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.Schema; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.languages.JavaClientCodegen; +import org.openapitools.codegen.model.ModelMap; +import org.openapitools.codegen.model.ModelsMap; +import org.openapitools.codegen.model.OperationsMap; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + + +public class TwilioJavaGeneratorModern extends JavaClientCodegen { + + ResourceCache2 resourceCache2 = new ResourceCache2(); + JavaUpdateDefaultMapping javaUpdateDefaultMapping = new JavaUpdateDefaultMapping(); + private final TwilioCodegenAdapter twilioCodegen; + JavaTemplateUpdater templateUpdater = new JavaTemplateUpdater(); + private final DirectoryStructureService directoryStructureService = new DirectoryStructureService( + additionalProperties, + new ResourceMap(new Inflector()), + new JavaCaseResolver()); + private final Map modelFormatMap = new HashMap<>(); + + public TwilioJavaGeneratorModern() { + super(); + ResourceCacheContext.clear(); + ResourceCacheContext.set(resourceCache2); + this.additionalProperties.put("serializationLibrary", "jackson"); + twilioCodegen = new TwilioCodegenAdapter(this, getName()); + sourceFolder = ""; + } + @Override + public String toExampleValue(Schema schema) { + return super.toExampleValue(schema); + } + @Override + public void processOpts() { + super.processOpts(); + this.modelTemplateFiles.clear(); + javaUpdateDefaultMapping.typeMapping(this.typeMapping); + javaUpdateDefaultMapping.importMapping(this.importMapping); + javaUpdateDefaultMapping.removeReservedWords(this.reservedWords); + javaUpdateDefaultMapping.modelTemplateFiles(this.modelTemplateFiles); + twilioCodegen.processOpts(); + } + + // Run once per spec + @Override + public void processOpenAPI(final OpenAPI openAPI) { + String apiStdVersion = null; + if (openAPI.getInfo().getExtensions() != null && openAPI.getInfo().getExtensions().containsKey("x-twilio")) { + LinkedHashMap xTwilio = (LinkedHashMap)openAPI.getInfo().getExtensions().get("x-twilio"); + apiStdVersion = (String) xTwilio.get("apiStandards"); + } + boolean isV1 = ApplicationConstants.isV1.test(apiStdVersion); + ResourceCacheContext.get().setV1(isV1); + + String domain = twilioCodegen.getDomainFromOpenAPI(openAPI); + String version = twilioCodegen.getVersionFromOpenAPI(openAPI); + twilioCodegen.setDomain(domain); + twilioCodegen.setVersion(version); + twilioCodegen.setOutputDir(domain, version); + javaUpdateDefaultMapping.removePropertiesFromCustomModels(openAPI); + directoryStructureService.configure(openAPI); + } + + @Override + public String toApiFilename(final String name) { + return directoryStructureService.toApiFilename(super.toApiFilename(name)); + } + + // DO NOT REMOVE this method even though it is not override. + @Override + public String getTypeDeclaration(Schema schema) { + return super.getTypeDeclaration(schema); + } + + // Run once per spec. + @Override + public Map postProcessAllModels(final Map allModels) { + final Map results = super.postProcessAllModels(allModels); + ResourceCache2 cache2 = ResourceCacheContext.get(); + ResourceCacheContext.set(cache2); + ResourceCacheContext.clear(); + //ResourceCache.clearAllModelsByDefaultGenerator(); + // Update allModels from Default generator in ResourceCache. + Utility.addModelsToLocalModelList(results, cache2.getAllModelsByDefaultGenerator()); + directoryStructureService.postProcessAllModels(results, modelFormatMap); + + // Return an empty collection so no model files get generated. + return new HashMap<>(); + } + + @Override + public String getSchemaType(Schema p) { + String schemaType = super.getSchemaType(p); + return schemaType; + } + + // Run once per operation groups + @Override + public OperationsMap postProcessOperationsWithModels(final OperationsMap objs, List allModels) { + final OperationsMap results = super.postProcessOperationsWithModels(objs, allModels); + //ResourceCache.clear(); + ResourceCacheContext.clear(); + final List opList = directoryStructureService.processOperations(results); + JavaApiResource apiResource = processCodegenOperations(opList); + results.put("resources", apiResource); + return results; + } + + @Override + protected ImmutableMap.Builder addMustacheLambdas() { + ImmutableMap.Builder lambdaBuilder = super.addMustacheLambdas(); + lambdaBuilder.put("replacehyphen", new ReplaceHyphenLambda()); + return lambdaBuilder; + } + + @Override + public String toParamName(final String name) { + return super.toVarName(twilioCodegen.toParamName(name)); + } + + @Override + public String getName() { + return EnumConstants.Generator.TWILIO_JAVA.getValue(); + } + + @Override + public String getHelp() { + return "Generates the twilio-java-modern helper library."; + } + + private JavaApiResource processCodegenOperations(List operations) { + //DataModelManager.getInstance().apply(); + templateUpdater.addApiTemplate(this, operations); + JavaApiResource apiResource = new JavaApiResourceBuilder(this, operations) + .resourceName() + .recordKey() + .processOperations() + .namespaceSubPart(operations.get(0)) + .build(); + return apiResource; + } +} diff --git a/src/main/java/com/twilio/oai/TwilioPythonGenerator.java b/src/main/java/com/twilio/oai/TwilioPythonGenerator.java index 3a8629731..70b2286d0 100644 --- a/src/main/java/com/twilio/oai/TwilioPythonGenerator.java +++ b/src/main/java/com/twilio/oai/TwilioPythonGenerator.java @@ -24,14 +24,14 @@ import io.swagger.v3.oas.models.PathItem; import org.openapitools.codegen.CodegenModel; import org.openapitools.codegen.CodegenOperation; -import org.openapitools.codegen.languages.PythonLegacyClientCodegen; +import org.openapitools.codegen.languages.PythonClientCodegen; import org.openapitools.codegen.model.ModelMap; import org.openapitools.codegen.model.ModelsMap; import org.openapitools.codegen.model.OperationsMap; import static com.twilio.oai.common.ApplicationConstants.CONFIG_PYTHON_JSON_PATH; -public class TwilioPythonGenerator extends PythonLegacyClientCodegen { +public class TwilioPythonGenerator extends PythonClientCodegen { private final TwilioCodegenAdapter twilioCodegen; private final PythonApiActionTemplate actionTemplate = new PythonApiActionTemplate(this); private final IResourceTree resourceTree = new ResourceMap(new Inflector()); @@ -54,6 +54,14 @@ public TwilioPythonGenerator() { @Override public void processOpts() { twilioCodegen.processOpts(); + // setting this since oai generator is prefixing var_ for reserved words + Map staticReservedWords = Map.of( + "date", "date", + "from", "_from", + "field", "field" + ); + + staticReservedWords.forEach((key, value) -> reservedWordsMappings().put(key, value)); } @Override diff --git a/src/main/java/com/twilio/oai/api/CsharpApiResourceBuilder.java b/src/main/java/com/twilio/oai/api/CsharpApiResourceBuilder.java index c1c3f362d..54a086a6b 100644 --- a/src/main/java/com/twilio/oai/api/CsharpApiResourceBuilder.java +++ b/src/main/java/com/twilio/oai/api/CsharpApiResourceBuilder.java @@ -38,6 +38,14 @@ public class CsharpApiResourceBuilder extends ApiResourceBuilder { public String authMethod = ""; + /** + * List of C# primitive types that require a nullable marker (?) when nullable + */ + private static final Set CSHARP_PRIMITIVE_TYPES = new HashSet<>(Arrays.asList( + "int", "long", "float", "double", "decimal", "bool", "char", "byte", + "sbyte", "short", "ushort", "uint", "ulong", "DateTime" + )); + public CsharpApiResourceBuilder(IApiActionTemplate template, List codegenOperations, List allModels) { super(template, codegenOperations, allModels); @@ -92,6 +100,7 @@ public ApiResourceBuilder updateOperations(Resolver codegenPar super.updateOperations(codegenParameterIResolver); processAuthMethods(this.codegenOperationList); this.codegenOperationList.forEach(co -> { + co.allParams.forEach(this::handleNullableParameter); co.headerParams.forEach(e -> codegenParameterIResolver.resolve(e, this)); populateRequestBodyArgument(co); resolveIngressModel(co); @@ -231,28 +240,54 @@ public ApiResourceBuilder updateResponseModel(Resolver codegenP } public Set getDistinctResponseModel(List responseModels) { - HashSet modelVars = new HashSet<>(); + HashMap propertyMap = new HashMap<>(); Set distinctResponseModels = new LinkedHashSet<>(); + for (CodegenModel codegenModel: responseModels) { for (CodegenProperty property: codegenModel.vars) { property.nameInCamelCase = StringHelper.camelize(property.nameInSnakeCase); - Boolean isOverridden = property.isOverridden; - if(isOverridden != null && isOverridden == false) - property.isOverridden = null; + handleNullableProperty(property); + // Check for operation name conflicts or nested model name conflicts if (Arrays.stream(EnumConstants.Operation.values()) .anyMatch(value -> value.getValue().equals(property.nameInCamelCase)) || isNestedModelPresentWithPropertyName(property)) { property.nameInCamelCase = "_" + property.nameInCamelCase; } + + // Check if property with same name already exists, but has different metadata + // This handles cases where properties have the same name but different types or model flags + String propertyKey = property.name; + if (propertyMap.containsKey(propertyKey)) { + CodegenProperty existingProperty = propertyMap.get(propertyKey); + + // Check if the properties are functionally different enough to warrant duplication + // Only consider properties truly different if they have different data types + // Differences in isModel or isOverridden flags alone should not cause duplication + if (!Objects.equals(existingProperty.dataType, property.dataType)) { + property.nameInCamelCase = "_" + property.nameInCamelCase; + } else { + // If they're functionally the same (same data type), merge any metadata if needed + // and skip adding this property + continue; + } + } + + // Store the property in the map for future duplicate checks + propertyMap.put(propertyKey, property); distinctResponseModels.add(property); - property.isOverridden = isOverridden; } } - for(CodegenProperty s : distinctResponseModels){ - if(modelVars.contains(s.name)){ - s.nameInCamelCase = "_" + s.nameInCamelCase; - }else modelVars.add(s.nameInCamelCase); + + // Final check for name collisions in camelCase names (which are used in C# code) + HashSet modelVars = new HashSet<>(); + for (CodegenProperty property : distinctResponseModels) { + if (modelVars.contains(property.nameInCamelCase)) { + property.nameInCamelCase = "_" + property.nameInCamelCase; + } else { + modelVars.add(property.nameInCamelCase); + } } + return distinctResponseModels; } @@ -358,4 +393,36 @@ public boolean isNestedModelPresentWithPropertyName(final CodegenProperty proper .findFirst(); return foundModel.isPresent(); } + + /** + * Handle nullable property in C# by appending "?" to primitive types when nullable. + * Reference types (arrays, objects, custom classes) are already nullable in C#. + * + * @param property The CodegenProperty to process + */ + protected void handleNullableProperty(CodegenProperty property) { + if (property.isNullable && !property.dataType.endsWith("?")) { + // Only add nullable marker to primitive types + if (CSHARP_PRIMITIVE_TYPES.contains(property.dataType)) { + property.dataType = property.dataType + "?"; + } + } + } + + protected void handleNullableParameter(CodegenParameter parameter) { + CodegenModel model = getModel(parameter.dataType); + if(model != null) { + for(CodegenProperty property: model.vars) { + handleNullableProperty(property); + } + } + else { + if (parameter.isNullable && !parameter.dataType.endsWith("?")) { + // Only add nullable marker to primitive types + if (CSHARP_PRIMITIVE_TYPES.contains(parameter.dataType)) { + parameter.dataType = parameter.dataType + "?"; + } + } + } + } } diff --git a/src/main/java/com/twilio/oai/common/ApplicationConstants.java b/src/main/java/com/twilio/oai/common/ApplicationConstants.java index aa404443f..ba5c08dd5 100644 --- a/src/main/java/com/twilio/oai/common/ApplicationConstants.java +++ b/src/main/java/com/twilio/oai/common/ApplicationConstants.java @@ -58,5 +58,13 @@ public class ApplicationConstants { public static final Predicate SUCCESS = i -> i != null && i >= 200 && i < 400; public static final String[] VERSION_LESS_SPECS = {"organizations"}; + + public static final String X_DATATYPE = "x-var-datatype"; + public static final String X_VARIABLE_NAME = "x-var-name"; + public static final String X_ENUM_TYPE = "x-enum-type"; // EnumConstants.OpenApiEnumType + public static final String X_MODEL_TYPE = "x-model-type"; // EnumConstants.OpenApiEnumType + public static final String X_IS_MODEL = "x-is-model"; + public static final String X_REQUEST_CONTENT_TYPE = "x-request-content-type"; + public static final Predicate isV1 = input -> input != null && input.startsWith("v1"); // Usage: isV1.test("v1.0"); } diff --git a/src/main/java/com/twilio/oai/common/EnumConstants.java b/src/main/java/com/twilio/oai/common/EnumConstants.java index af94060f9..06b8b6ccd 100644 --- a/src/main/java/com/twilio/oai/common/EnumConstants.java +++ b/src/main/java/com/twilio/oai/common/EnumConstants.java @@ -10,6 +10,9 @@ public class EnumConstants { public enum Generator { TWILIO_CSHARP("twilio-csharp"), TWILIO_JAVA("twilio-java"), + TWILIO_JAVA_LEGACY("twilio-java-legacy"), + TWILIO_JAVA_MODERN("twilio-java-modern"), + TWILIO_JAVA_TEST("twilio-java-test"), TWILIO_NODE("twilio-node"), TWILIO_PHP("twilio-php"), TWILIO_PYTHON("twilio-python"), @@ -133,4 +136,48 @@ public enum CsharpHttpMethod { private final String value; } + + public enum OpenApiEnumType { + PARAMETER_INLINE, // A single enum value used as a parameter value + PARAMETER_LIST_INLINE, // An array of enum values used in parameters + PARAMETER_REF, // An array of enum values used in parameters + PARAMETER_LIST_REF, // An array of enum values used in parameters + PROPERTY_INLINE, // A single enum value used as a property in a schema + PROPERTY_LIST, // An array of enum values used as a property in a schema + PROPERTY_REF, + PROPERTY_LIST_REF, // An array of enum values used as a property in a schema + FORM_PARAM_INLINE, + FORM_PARAM_LIST_INLINE, + FORM_PARAM_REF, + FORM_PARAM_LIST_REF, + } + + public enum ModelType { + SINGLE, + LIST + } + + @Getter + @RequiredArgsConstructor + public enum SupportedOperation { + X_CREATE("x-create-operation"), + X_LIST("x-list-operation"), + X_UPDATE("x-update-operation"), + X_FETCH("x-fetch-operation"), + X_DELETE("x-delete-operation"); + + private final String value; + } + + @Getter + @RequiredArgsConstructor + public enum SerializationTypes { + X_CREATE("x-create-operation"), + X_LIST("x-list-operation"), + X_UPDATE("x-update-operation"), + X_FETCH("x-fetch-operation"), + X_DELETE("x-delete-operation"); + + private final String value; + } } diff --git a/src/main/java/com/twilio/oai/common/StringUtils.java b/src/main/java/com/twilio/oai/common/StringUtils.java new file mode 100644 index 000000000..bf59ae556 --- /dev/null +++ b/src/main/java/com/twilio/oai/common/StringUtils.java @@ -0,0 +1,44 @@ +package com.twilio.oai.common; + +import org.apache.commons.text.CaseUtils; +import org.apache.commons.text.WordUtils; + +public class StringUtils { + + public static String toCamelCase(String input) { + if (input == null || input.isEmpty()) { + return input; + } + + String normalized = input.replaceAll("[^a-zA-Z0-9]", " "); + normalized = normalized.replaceAll("(?<=[a-z])(?=[A-Z])", " "); + normalized = normalized.replaceAll("(?<=[A-Z])(?=[A-Z][a-z])", " "); + String pascalCase = WordUtils.capitalizeFully(normalized).replaceAll(" ", ""); + return Character.toLowerCase(pascalCase.charAt(0)) + pascalCase.substring(1); + } + +// public static String toPascalCase(String input) { +// if (input == null || input.isEmpty()) { +// return input; +// } +// String normalized = input.replaceAll("[^a-zA-Z0-9]", " "); +// return WordUtils.capitalizeFully(normalized).replaceAll(" ", ""); +// } + + public static String toPascalCase(String input) { + if (input == null || input.isEmpty()) { + return input; + } + + String normalized = input.replaceAll("[^a-zA-Z0-0]", " "); + normalized = normalized.replaceAll("(?<=[a-z])(?=[A-Z])", " "); + normalized = normalized.replaceAll("(?<=[A-Z])(?=[A-Z][a-z])", " "); + return WordUtils.capitalizeFully(normalized).replaceAll(" ", ""); + } + + public static void main(String[] args) { + String input = "hello-world-example"; + String pascalCase = toPascalCase(input); + System.out.println("Pascal Case Output: " + pascalCase); // Output: helloWorldExample + } +} diff --git a/src/main/java/com/twilio/oai/common/Utility.java b/src/main/java/com/twilio/oai/common/Utility.java index 9268f6a25..891562731 100644 --- a/src/main/java/com/twilio/oai/common/Utility.java +++ b/src/main/java/com/twilio/oai/common/Utility.java @@ -10,9 +10,13 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; +import com.twilio.oai.java.cache.ResourceCacheContext; import lombok.experimental.UtilityClass; +import org.apache.commons.lang3.StringUtils; import org.openapitools.codegen.CodegenModel; import org.openapitools.codegen.CodegenOperation; import org.openapitools.codegen.CodegenProperty; @@ -20,6 +24,7 @@ import org.openapitools.codegen.model.ModelsMap; import static com.twilio.oai.common.ApplicationConstants.ARRAY; +import static com.twilio.oai.common.ApplicationConstants.DOT; import static com.twilio.oai.common.ApplicationConstants.OBJECT; @UtilityClass @@ -88,6 +93,21 @@ public String populateCrudOperations(final CodegenOperation operation) { return method.name(); } + + /* + responses: + '200': + content: + application/json: + schema: + title: ListMessageResponse + type: object + properties: + messages: -----------------> recordKey + type: array + items: + $ref: '#/components/schemas/api.v2010.account.message' + */ public String getRecordKey(final List models, final List codegenOperationList) { return codegenOperationList @@ -140,4 +160,118 @@ public static void resolveContentType(CodegenOperation co) { } } } + + public static String extractDatatypeFromContainer(String input) { + // Define the regular expression pattern + Pattern pattern = Pattern.compile("<([^>]+)>"); + + // Create a matcher object + Matcher matcher = pattern.matcher(input); + + // Check if the pattern matches + if (matcher.find()) { + // Return the captured group which is the custom type + return matcher.group(1); + } + return null; // Return null if no match is found + } + + public static String replaceDatatypeInContainer(String input, String replacement) { + // Define the regular expression pattern to extract the custom type + Pattern pattern = Pattern.compile("<([^>]+)>"); + Matcher matcher = pattern.matcher(input); + + // If a match is found, perform the replacement + if (matcher.find()) { + // Extract the custom type + String customType = matcher.group(1); + // Replace the custom type with the provided replacement string + return input.replace(customType, replacement); + } + // Return the input unchanged if no match is found + return input; + } + + public static String appendResourceNameToEnum(String name) { + if (name == null || name.isEmpty()) { + return null; + } + String prefix = ResourceCacheContext.get().getResourceName() + DOT; + if (name.startsWith(prefix)) { + return name; + } + return prefix + com.twilio.oai.common.StringUtils.toPascalCase(name); + } + + public static String getEnumNameFromRef(final String ref) { + String schemaName = ref.replaceFirst("#/components/schemas/", ""); + String[] enumNameArray = schemaName.split("_enum_"); + return enumNameArray[enumNameArray.length - 1]; + } + + /* For request body(urlencoded) enums with ref, it will be processed by default + Example1: + singleBodyRef: + $ref: '#/components/schemas/singleReusable' + + Example2: + status: + $ref: '#/components/schemas/message_enum_status' + */ + public static String getEnumNameFromDefaultDatatype(final String ref) { + if (ref == null) return null; + String schemaName = ref.replaceFirst("#/components/schemas/", ""); + if (ref.equals(schemaName)) { + // No change in schemaName + return getEnumNameFromDatatype(ref); + } + String[] enumNameArray = schemaName.split("_enum_"); + return enumNameArray[enumNameArray.length - 1]; + } + + public static String getEnumNameFromDatatype(final String datatype) { + if (datatype == null || datatype.isEmpty()) { + return null; + } + String[] enumNameArray = datatype.split("Enum"); + return enumNameArray[enumNameArray.length - 1]; + } + + /* + Type1: + types: + $ref: '#/components/schemas/types' + + */ + public static CodegenModel getModelFromOpenApiType(CodegenProperty codegenProperty) { + // Ref occurs for 2 cases, + // 1. one when there is no ref, in that case the name will contain parent names. + // 2. When model is defined using ref(reusable), name will not contain parent names. + if (StringUtils.isBlank(codegenProperty.openApiType)) { + return null; + } + String modelClassName = codegenProperty.isContainer ? codegenProperty.items.openApiType: codegenProperty.openApiType; + for (CodegenModel codegenModel: ResourceCacheContext.get().getAllModelsByDefaultGenerator()) { + if (modelClassName.equals(codegenModel.classname)) { + return codegenModel; + } + } + return null; + } + + public static void main(String[] args) { + String ref = "#/components/schemas/api.v2010.account.message"; + + System.out.println(getModelFromRef(ref)); + } + public static CodegenModel getModelFromRef(String ref) { + String schemaName = ref.replaceFirst("#/components/schemas/", ""); + List allModels = ResourceCacheContext.get().getAllModelsByDefaultGenerator(); + for (CodegenModel model: allModels) { + if (model.name.equals(schemaName)) { + return model; + } + } + return null; + } } diff --git a/src/main/java/com/twilio/oai/java/JavaApiResource.java b/src/main/java/com/twilio/oai/java/JavaApiResource.java new file mode 100644 index 000000000..c37745427 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/JavaApiResource.java @@ -0,0 +1,37 @@ +package com.twilio.oai.java; + +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheEnum; +import com.twilio.oai.java.nestedmodels.MustacheModel; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenProperty; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class JavaApiResource { + String resourceName; + String recordKey; + Set mustacheEnums; + Set mustacheModels; + List operations; + Set response; + String namespaceSubPart; + + Boolean responseFlag = null; // true or NUll + Boolean isApiV1 = null; // true or NUll + + public JavaApiResource(JavaApiResourceBuilder builder) { + resourceName = ResourceCacheContext.get().getResourceName(); + recordKey = builder.recordKey; + this.operations = builder.operations; + this.mustacheEnums = new HashSet<>(ResourceCacheContext.get().getEnumsClassesForMustache()); + this.mustacheModels = new HashSet<>(ResourceCacheContext.get().getModelClassesForMustache()); + this.response = ResourceCacheContext.get().getResponse(); + if (response != null && !response.isEmpty()) responseFlag = true; + this.namespaceSubPart = builder.namespaceSubPart; + if (ResourceCacheContext.get().isV1()) isApiV1 = true; + } +} + diff --git a/src/main/java/com/twilio/oai/java/JavaApiResourceBuilder.java b/src/main/java/com/twilio/oai/java/JavaApiResourceBuilder.java new file mode 100644 index 000000000..3f06f3f71 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/JavaApiResourceBuilder.java @@ -0,0 +1,75 @@ +package com.twilio.oai.java; + +import com.twilio.oai.TwilioJavaGeneratorModern; +import com.twilio.oai.common.Utility; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.processor.JavaOperationProcessor; +import org.apache.commons.lang3.StringUtils; +import org.openapitools.codegen.CodegenOperation; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static com.twilio.oai.common.ApplicationConstants.PATH_SEPARATOR_PLACEHOLDER; + +public class JavaApiResourceBuilder { + // ApiName, example: Message + String resourceName; + // key used for pagination in list operation + String recordKey; + TwilioJavaGeneratorModern twilioJavaGenerator; + final JavaOperationProcessor operationProcessor; + List operations; + String namespaceSubPart; + public JavaApiResourceBuilder(TwilioJavaGeneratorModern twilioJavaGenerator, List operations) { + this.twilioJavaGenerator = twilioJavaGenerator; + this.operations = operations; + this.operationProcessor = JavaOperationProcessor.getInstance(); + } + + // Bug: path should not end with '/' + // example: /2010-04-01/Accounts.json, otherwise directory structure will not be created properly. + public JavaApiResourceBuilder resourceName() { + //ResourceCacheContext.get().setResourceName(""); // Clear + operations.forEach(co -> { + List filePathArray = new ArrayList<>(Arrays.asList(co.baseName.split(PATH_SEPARATOR_PLACEHOLDER))); + if (!filePathArray.isEmpty() && StringUtils.isNotBlank(filePathArray.get(filePathArray.size() - 1))) { + resourceName = filePathArray.get(filePathArray.size() - 1); + } + }); + ResourceCacheContext.get().setResourceName(resourceName); + return this; + } + + public JavaApiResourceBuilder recordKey() { + this.recordKey = Utility.getRecordKey(ResourceCacheContext.get().getAllModelsByDefaultGenerator(), operations); + return this; + } + + public JavaApiResourceBuilder processOperations() { + if (this.resourceName == null) { + throw new RuntimeException("Resource name must be set before processing operations."); + } + operations.forEach(operation -> operationProcessor.process(operation)); + return this; + } + + public JavaApiResourceBuilder namespaceSubPart(CodegenOperation codegenOperation) { + List filePathArray = new ArrayList<>(Arrays.asList(codegenOperation.baseName.split(PATH_SEPARATOR_PLACEHOLDER))); + filePathArray.remove(filePathArray.size()-1); + if (!filePathArray.isEmpty()) { + final String namespacePath = filePathArray + .stream() + .map(String::toLowerCase) + .collect(Collectors.joining(".")); + namespaceSubPart = "." + namespacePath; + } + return this; + } + + public JavaApiResource build() { + return new JavaApiResource(this); + } +} diff --git a/src/main/java/com/twilio/oai/java/JavaTemplateUpdater.java b/src/main/java/com/twilio/oai/java/JavaTemplateUpdater.java new file mode 100644 index 000000000..97d618ca5 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/JavaTemplateUpdater.java @@ -0,0 +1,152 @@ +package com.twilio.oai.java; + +import com.twilio.oai.TwilioJavaGeneratorModern; +import com.twilio.oai.common.EnumConstants; +import com.twilio.oai.java.constants.MustacheConstants; +import org.openapitools.codegen.CodegenOperation; + +import java.util.AbstractMap; +import java.util.Map; + +import static com.twilio.oai.java.constants.MustacheConstants.ActionMethod; +import static com.twilio.oai.java.constants.MustacheConstants.ActionType; + +/* +The JavaTemplateFile class is responsible for managing template mappings for Java code generation. +It defines mappings between operation IDs (starting strings) +and corresponding template files (mustache files) along with their generated file extensions. +Example: + Key: Represents the starting string of the operationId (e.g., "create", "fetch"). + Value: Represents a mapping between the mustache template file and the generated file extension using AbstractMap.SimpleEntry. +Note: We don't creating mapping based in http method, we create mapping using operationId. + */ +public class JavaTemplateUpdater { + public static final String API_TEMPLATE = "api.mustache"; + public static final String NESTED_MODELS = "models.mustache"; + + Map apiOperationTemplate; + Map apiTemplate; + + public JavaTemplateUpdater() { + // Available templates for Java code generation. + apiOperationTemplate = Map.of( + "create", new AbstractMap.SimpleEntry<>("creator.mustache", "Creator.java"), + "fetch", new AbstractMap.SimpleEntry<>("fetcher.mustache", "Fetcher.java"), + "delete", new AbstractMap.SimpleEntry<>("deleter.mustache", "Deleter.java"), + "list", new AbstractMap.SimpleEntry<>("reader.mustache", "Reader.java"), + "update", new AbstractMap.SimpleEntry<>("updater.mustache", "Updater.java") + ); + apiTemplate = Map.of( + API_TEMPLATE, new AbstractMap.SimpleEntry<>("api.mustache", ".java") + ); +// Map nestedModelTemplate = Map.of( +// NESTED_MODELS, new AbstractMap.SimpleEntry<>("models.mustache", "Model.java") +// ); + } + + public void addApiTemplate(TwilioJavaGeneratorModern twilioJavaGenerator, java.util.List operations) { + clearApiTemplate(twilioJavaGenerator); + for (CodegenOperation operation : operations) { + String operationId = operation.operationId; + if (operationId == null || operationId.isEmpty()) { + throw new RuntimeException("Operation ID cannot be null or empty for path: " + operation.path); + } + if (Create.isCreate(operation)) { + Create.add(twilioJavaGenerator, operation, apiOperationTemplate); + } else if (List.isList(operation)) { + List.add(twilioJavaGenerator, operation, apiOperationTemplate); + } else if (Update.isUpdate(operation)) { + Update.add(twilioJavaGenerator, operation, apiOperationTemplate); + } else if (Delete.isDelete(operation)) { + Delete.add(twilioJavaGenerator, operation, apiOperationTemplate); + } else if (Fetch.isFetch(operation)) { + Fetch.add(twilioJavaGenerator, operation, apiOperationTemplate); + } else { + throw new RuntimeException("Unsupported operation type for operationId: " + operationId); + } + } + } + + void clearApiTemplate(TwilioJavaGeneratorModern twilioJavaGenerator) { + // Clear the existing templates + twilioJavaGenerator.apiTemplateFiles().clear(); + // Add the default API template + twilioJavaGenerator.apiTemplateFiles().put(API_TEMPLATE, ".java"); + } +} + +class Create { + public static void add(TwilioJavaGeneratorModern twilioJavaGenerator, CodegenOperation codegenOperation, Map apiOperationTemplate) { + codegenOperation.vendorExtensions.put(EnumConstants.SupportedOperation.X_CREATE.getValue(), true); + String key = (String) apiOperationTemplate.get("create").getKey(); + String value = (String) apiOperationTemplate.get("create").getValue(); + twilioJavaGenerator.apiTemplateFiles().put(key, value); + + codegenOperation.vendorExtensions.put(MustacheConstants.ACTION_TYPE, ActionType.CREATOR.getValue()); + codegenOperation.vendorExtensions.put(MustacheConstants.ACTION_METHOD, ActionMethod.CREATE.getValue()); + } + public static boolean isCreate(CodegenOperation codegenOperation) { + return codegenOperation.operationId.toLowerCase().startsWith("create"); + } +} + +class List { + public static void add(TwilioJavaGeneratorModern twilioJavaGenerator, CodegenOperation codegenOperation, Map apiOperationTemplate) { + codegenOperation.vendorExtensions.put(EnumConstants.SupportedOperation.X_LIST.getValue(), true); + String key = (String) apiOperationTemplate.get("list").getKey(); + String value = (String) apiOperationTemplate.get("list").getValue(); + twilioJavaGenerator.apiTemplateFiles().put(key, value); + codegenOperation.vendorExtensions.put(MustacheConstants.X_IS_LIST_OP, true); + + codegenOperation.vendorExtensions.put(MustacheConstants.ACTION_TYPE, ActionType.READER.getValue()); + codegenOperation.vendorExtensions.put(MustacheConstants.ACTION_METHOD, ActionMethod.READ.getValue()); + } + public static boolean isList(CodegenOperation codegenOperation) { + return codegenOperation.operationId.toLowerCase().startsWith("list"); + } +} + +class Update { + public static void add(TwilioJavaGeneratorModern twilioJavaGenerator, CodegenOperation codegenOperation, Map apiOperationTemplate) { + codegenOperation.vendorExtensions.put(EnumConstants.SupportedOperation.X_UPDATE.getValue(), true); + String key = (String) apiOperationTemplate.get("update").getKey(); + String value = (String) apiOperationTemplate.get("update").getValue(); + twilioJavaGenerator.apiTemplateFiles().put(key, value); + + codegenOperation.vendorExtensions.put(MustacheConstants.ACTION_TYPE, ActionType.UPDATER.getValue()); + codegenOperation.vendorExtensions.put(MustacheConstants.ACTION_METHOD, ActionMethod.UPDATE.getValue()); + } + public static boolean isUpdate(CodegenOperation codegenOperation) { + return codegenOperation.operationId.toLowerCase().startsWith("update"); + } +} + +class Delete { + public static void add(TwilioJavaGeneratorModern twilioJavaGenerator, CodegenOperation codegenOperation, Map apiOperationTemplate) { + codegenOperation.vendorExtensions.put(EnumConstants.SupportedOperation.X_DELETE.getValue(), true); + String key = (String) apiOperationTemplate.get("delete").getKey(); + String value = (String) apiOperationTemplate.get("delete").getValue(); + twilioJavaGenerator.apiTemplateFiles().put(key, value); + + codegenOperation.vendorExtensions.put(MustacheConstants.ACTION_TYPE, ActionType.DELETER.getValue()); + codegenOperation.vendorExtensions.put(MustacheConstants.ACTION_METHOD, ActionMethod.DELETE.getValue()); + } + public static boolean isDelete(CodegenOperation codegenOperation) { + return codegenOperation.operationId.toLowerCase().startsWith("delete"); + } +} + +class Fetch { + public static void add(TwilioJavaGeneratorModern twilioJavaGenerator, CodegenOperation codegenOperation, Map apiOperationTemplate) { + codegenOperation.vendorExtensions.put(EnumConstants.SupportedOperation.X_FETCH.getValue(), true); + String key = (String) apiOperationTemplate.get("fetch").getKey(); + String value = (String) apiOperationTemplate.get("fetch").getValue(); + twilioJavaGenerator.apiTemplateFiles().put(key, value); + + codegenOperation.vendorExtensions.put(MustacheConstants.ACTION_TYPE, ActionType.FETCHER.getValue()); + codegenOperation.vendorExtensions.put(MustacheConstants.ACTION_METHOD, ActionMethod.FETCH.getValue()); + } + public static boolean isFetch(CodegenOperation codegenOperation) { + return codegenOperation.operationId.toLowerCase().startsWith("fetch"); + } +} \ No newline at end of file diff --git a/src/main/java/com/twilio/oai/java/ResourceCache.java b/src/main/java/com/twilio/oai/java/ResourceCache.java new file mode 100644 index 000000000..b5f9f5519 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/ResourceCache.java @@ -0,0 +1,54 @@ +package com.twilio.oai.java; + +import com.twilio.oai.java.nestedmodels.MustacheEnum; +import com.twilio.oai.java.nestedmodels.MustacheModel;; +import lombok.Getter; +import lombok.Setter; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenProperty; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +public class ResourceCache { + @Getter + @Setter + public static String resourceName; + + @Getter + @Setter + public static Set response = new TreeSet<>((p1, p2) -> p1.baseName.compareTo(p2.baseName)); + + @Getter + public static List allModelsByDefaultGenerator = new ArrayList<>(); + @Getter + public static Set modelClassesForMustache = new HashSet<>(); + + @Getter + public static Set enumsClassesForMustache = new HashSet<>(); + + public static void setAllModelsByDefaultGenerator(List allModelsByDefaultGenerator) { + ResourceCache.allModelsByDefaultGenerator = new ArrayList<>(allModelsByDefaultGenerator); + } + + public static void addToModelClasses(MustacheModel mustacheModel) { + ResourceCache.modelClassesForMustache.add(mustacheModel); + } + + public static void addToEnumClasses(MustacheEnum mustacheEnum) { + ResourceCache.enumsClassesForMustache.add(mustacheEnum); + } + + public static void clear() { + resourceName = null; + modelClassesForMustache.clear(); + enumsClassesForMustache.clear(); + response.clear(); + } + public static void clearAllModelsByDefaultGenerator() { + allModelsByDefaultGenerator.clear(); + } +} diff --git a/src/main/java/com/twilio/oai/java/cache/ResourceCache2.java b/src/main/java/com/twilio/oai/java/cache/ResourceCache2.java new file mode 100644 index 000000000..d8a06e1ee --- /dev/null +++ b/src/main/java/com/twilio/oai/java/cache/ResourceCache2.java @@ -0,0 +1,70 @@ +package com.twilio.oai.java.cache; + +import com.twilio.oai.java.nestedmodels.MustacheEnum; +import com.twilio.oai.java.nestedmodels.MustacheModel; +import com.twilio.oai.java.nestedmodels.MustacheOneOfIface; +import lombok.Getter; +import lombok.Setter; +import org.checkerframework.checker.units.qual.A; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenProperty; + +import java.util.*; + +public class ResourceCache2 { + + @Getter + @Setter + private String resourceName; + + @Getter + @Setter + private Set response = new TreeSet<>((p1, p2) -> p1.baseName.compareTo(p2.baseName)); + + @Getter + private ArrayList allModelsByDefaultGenerator = new ArrayList<>(); + @Getter + private Set modelClassesForMustache = new HashSet<>(); + + @Getter + private Set oneOfInterfaces = new HashSet<>(); + + @Getter + private Set enumsClassesForMustache = new HashSet<>(); + + @Getter + @Setter + private boolean isV1; + + public void setAllModelsByDefaultGenerator(ArrayList allModelsByDefaultGenerator) { + this.allModelsByDefaultGenerator = new ArrayList<>(allModelsByDefaultGenerator); + } + + public ArrayList getAllModelsByDefaultGenerator() { + return this.allModelsByDefaultGenerator; + } + public void addToModelClasses(MustacheModel mustacheModel) { + this.modelClassesForMustache.add(mustacheModel); + } + + public void addToEnumClasses(MustacheEnum mustacheEnum) { + this.enumsClassesForMustache.add(mustacheEnum); + } + + public void addToOneOfInterfaces(MustacheOneOfIface oneOfIFace) { + this.oneOfInterfaces.add(oneOfIFace); + } + + // Clear at group of operation level, at method: postProcessOperationsWithModels + public void clear() { + resourceName = ""; + modelClassesForMustache.clear(); + enumsClassesForMustache.clear(); + response.clear(); + } + + // No need to clear + public void clearAllModelsByDefaultGenerator() { + allModelsByDefaultGenerator.clear(); + } +} diff --git a/src/main/java/com/twilio/oai/java/cache/ResourceCacheContext.java b/src/main/java/com/twilio/oai/java/cache/ResourceCacheContext.java new file mode 100644 index 000000000..c6e8651c5 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/cache/ResourceCacheContext.java @@ -0,0 +1,19 @@ +package com.twilio.oai.java.cache; + + +public class ResourceCacheContext { + private static final ThreadLocal CACHE = new ThreadLocal<>(); + + public static void set(ResourceCache2 cache) { + CACHE.set(cache); + } + + public static ResourceCache2 get() { + return CACHE.get(); + } + + public static void clear() { + if (CACHE.get() != null) CACHE.get().clear(); + } +} + diff --git a/src/main/java/com/twilio/oai/java/constants/MustacheConstants.java b/src/main/java/com/twilio/oai/java/constants/MustacheConstants.java new file mode 100644 index 000000000..6dce31699 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/constants/MustacheConstants.java @@ -0,0 +1,55 @@ +package com.twilio.oai.java.constants; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; + +import java.util.Map; + + +// This class contains only those constants which are used in mustache templates. +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MustacheConstants { + // It is used to define the content type of the request body in mustache templates which is defined in twilio-java. + // If content type constant changes in twilio-java then it's value should be updated as well. + public static final String X_REQUEST_LANGUAGE_CONTENT_TYPE_CONSTANT = "x-request-content-type"; + public static final String X_REQUEST_HTTP_METHOD = "x-http-method"; + public static final String X_IS_LIST_OP = "x-is-list-op"; + public static final String ACTION_TYPE = "x-common-action-type"; + public static final String ACTION_METHOD = "x-common-action-method"; + + public static final Map serializaationMapping = Map.of( + "application/x-www-form-urlencoded", "if ($paramName != null) { request.addPostParam($stringCapParamName, $paramName.toString())}", + "application/json", "Json", + "multipart/form-data", "MultipartFormData" + ); + + + // Used with "x-common-action-type" + @Getter + @RequiredArgsConstructor + public enum ActionType { + CREATOR("Creator"), + READER("Reader"), + UPDATER("Updater"), + DELETER("Deleter"), + FETCHER("Fetcher"); + + private final String value; + } + + // Used with "x-common-action-method" + @Getter + @RequiredArgsConstructor + public enum ActionMethod { + CREATE("create"), + READ("read"), + UPDATE("update"), + DELETE("delete"), + FETCH("fetch"); + + private final String value; + } + +} diff --git a/src/main/java/com/twilio/oai/java/feature/Inequality.java b/src/main/java/com/twilio/oai/java/feature/Inequality.java new file mode 100644 index 000000000..9438c3382 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/feature/Inequality.java @@ -0,0 +1,69 @@ +package com.twilio.oai.java.feature; + +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenParameter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/* + * Main aim is to identify inequality fields in the parameters, so that serialization can be handled correctly. + */ +public class Inequality { + public void process(CodegenOperation codegenOperation) { + Map> groupedItems = new HashMap<>(); + + codegenOperation.queryParams.forEach(param -> groupItems(param, groupedItems)); + addVendorExtension(groupedItems); + groupedItems.clear(); + // Currently supported only for query parameters. + +// codegenOperation.pathParams.forEach(param -> groupItems(param, groupedItems)); +// addVendorExtension(groupedItems); +// groupedItems.clear(); +// +// codegenOperation.headerParams.forEach(param -> groupItems(param, groupedItems)); +// addVendorExtension(groupedItems); +// groupedItems.clear(); +// +// codegenOperation.formParams.forEach(param -> groupItems(param, groupedItems)); +// addVendorExtension(groupedItems); +// groupedItems.clear(); + } + + private void groupItems (CodegenParameter codegenParameter, Map> groupedItems) { + String baseName = getBaseName(codegenParameter); + if (!groupedItems.containsKey(baseName)) { + groupedItems.put(baseName, new ArrayList<>()); + } + groupedItems.get(baseName).add(codegenParameter); + } + + private void addVendorExtension(Map> groupedItems) { + for (Map.Entry> entry : groupedItems.entrySet()) { + List values = entry.getValue(); + if (values.size() > 1) { + // Add a vendor extension to indicate that there are multiple parameters with the same base name + String baseName = entry.getKey(); + for (CodegenParameter param : values) { + if (baseName.equals(param.baseName)) { + param.vendorExtensions.put("x-inequality-main", true); + } else { + param.vendorExtensions.put("x-has-before-or-after", true); + } + } + } + } + } + + // Input: DateCreated, DateCreated>, DateCreated< + // Output: DateCreated, DateCreated, DateCreated + private String getBaseName(CodegenParameter codegenParameter) { + if (codegenParameter.baseName.endsWith(">") || codegenParameter.baseName.endsWith("<")) { + return codegenParameter.baseName.substring(0, codegenParameter.baseName.length() - 1); + } + return codegenParameter.baseName; + } +} diff --git a/src/main/java/com/twilio/oai/java/feature/SetterMethodGenerator.java b/src/main/java/com/twilio/oai/java/feature/SetterMethodGenerator.java new file mode 100644 index 000000000..b9d3dc95b --- /dev/null +++ b/src/main/java/com/twilio/oai/java/feature/SetterMethodGenerator.java @@ -0,0 +1,38 @@ +package com.twilio.oai.java.feature; + +import com.twilio.oai.java.constants.MustacheConstants; +import com.twilio.oai.java.processor.enums.EnumProcessorFactory; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenParameter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +// Add all setter variables for an operation which is non path parameters +public class SetterMethodGenerator { + public static SetterMethodGenerator instance; + + private SetterMethodGenerator() { + } + public static synchronized SetterMethodGenerator getInstance() { + if (instance == null) { + synchronized (SetterMethodGenerator.class) { + if (instance == null) { + instance = new SetterMethodGenerator(); + } + } + } + return instance; + } + + public void apply(final CodegenOperation codegenOperation) { + //List setterParameters = codegenOperation.allParams.stream().filter(param -> !param.isPathParam).collect(Collectors.toList()); + List setterParameters = new ArrayList<>(codegenOperation.bodyParams); + setterParameters.addAll(codegenOperation.formParams); + setterParameters.addAll(codegenOperation.queryParams); + setterParameters.addAll(codegenOperation.headerParams); + codegenOperation.vendorExtensions.put("x-setter-methods", setterParameters); + } +} diff --git a/src/main/java/com/twilio/oai/java/feature/constructor/ConstructorFactory.java b/src/main/java/com/twilio/oai/java/feature/constructor/ConstructorFactory.java new file mode 100644 index 000000000..d375ce937 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/feature/constructor/ConstructorFactory.java @@ -0,0 +1,38 @@ +package com.twilio.oai.java.feature.constructor; + +import org.openapitools.codegen.CodegenOperation; + +import java.util.List; + +public class ConstructorFactory { + public static ConstructorFactory instance; + + public static synchronized ConstructorFactory getInstance() { + if (instance == null) { + synchronized (ConstructorFactory.class) { + if (instance == null) { + instance = new ConstructorFactory(); + } + } + } + return instance; + } + + private final List constructorGenerators; + + private ConstructorFactory() { + constructorGenerators = List.of( + new JsonConstructorGenerator(), + new UrlencodedBodyConstructorGenerator() + ); + } + + public void applyFeature(CodegenOperation codegenOperation) { + for (ConstructorGenerator constructorGenerator: constructorGenerators) { + if (constructorGenerator.shouldApply(codegenOperation)) { + constructorGenerator.apply(codegenOperation); + return; // Exit after the first processor that applies + } + } + } +} diff --git a/src/main/java/com/twilio/oai/java/feature/constructor/ConstructorGenerator.java b/src/main/java/com/twilio/oai/java/feature/constructor/ConstructorGenerator.java new file mode 100644 index 000000000..cb79f541a --- /dev/null +++ b/src/main/java/com/twilio/oai/java/feature/constructor/ConstructorGenerator.java @@ -0,0 +1,16 @@ +package com.twilio.oai.java.feature.constructor; + +import com.twilio.oai.StringHelper; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenParameter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.stream.Collectors; + +public abstract class ConstructorGenerator { + abstract void apply(CodegenOperation codegenOperation); + abstract boolean shouldApply(CodegenOperation codegenOperation); +} diff --git a/src/main/java/com/twilio/oai/java/feature/constructor/JsonConstructorGenerator.java b/src/main/java/com/twilio/oai/java/feature/constructor/JsonConstructorGenerator.java new file mode 100644 index 000000000..38761f549 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/feature/constructor/JsonConstructorGenerator.java @@ -0,0 +1,93 @@ +package com.twilio.oai.java.feature.constructor; + +import com.google.common.collect.Lists; +import com.twilio.oai.StringHelper; +import com.twilio.oai.java.cache.ResourceCacheContext; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenParameter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static com.twilio.oai.api.JavaApiResourceBuilder.SIGNATURE_LIST; +import static com.twilio.oai.common.ApplicationConstants.ACCOUNT_SID_VEND_EXT; +import static com.twilio.oai.common.ApplicationConstants.DOT; + +public class JsonConstructorGenerator extends ConstructorGenerator { + + @Override + public void apply(CodegenOperation codegenOperation) { + // This method is intentionally left empty as the JSON constructor does not require any specific processing. + // The JSON constructor is automatically generated by the OpenAPI generator. + codegenOperation.vendorExtensions.put("x-java-constructor", true); + + List> constructors = generateSignatureListModern(codegenOperation); + + codegenOperation.vendorExtensions.put(SIGNATURE_LIST, constructors); + + } + + @Override + public boolean shouldApply(CodegenOperation codegenOperation) { + if (codegenOperation.consumes == null || codegenOperation.consumes.isEmpty()) { + return false; + } + boolean shouldApply = codegenOperation.consumes.stream() + .anyMatch(mediaType -> mediaType.get("mediaType").equals("application/json")); + return shouldApply; + } + + public List> generateSignatureListModern(final CodegenOperation codegenOperation) { + // Step 1 + List requiredParams = getRequiredParameters(codegenOperation); + // Step 2 + CodegenParameter accountSidParam = getAccountSidParameter(codegenOperation); + // Step 3 + List> listOfConstructors = combineParameters(requiredParams, accountSidParam); + return listOfConstructors; + } + + private List getRequiredParameters(CodegenOperation codegenOperation) { + List requiredParams; + requiredParams = codegenOperation.pathParams.stream() + .filter(param -> !param.vendorExtensions.containsKey(ACCOUNT_SID_VEND_EXT)) + .collect(Collectors.toList()); + requiredParams.addAll(codegenOperation.queryParams.stream() + .filter(param -> param.required) + .collect(Collectors.toList())); + requiredParams.addAll(codegenOperation.bodyParams.stream() + .filter(param -> param.required) + .collect(Collectors.toList())); + requiredParams.addAll(codegenOperation.headerParams.stream() + .filter(param -> param.required) + .collect(Collectors.toList())); + return requiredParams; + } + + private CodegenParameter getAccountSidParameter(CodegenOperation codegenOperation) { + return codegenOperation.pathParams.stream() + .filter(param -> param.vendorExtensions.containsKey(ACCOUNT_SID_VEND_EXT)) + .findAny() + .orElse(null); + } + private List> combineParameters(List requiredParams, CodegenParameter accountSidParam) { + List> signatureList = new ArrayList<>(); + signatureList.add(addAllToList(requiredParams)); + if (accountSidParam != null) { + signatureList.add(addAllToList(List.of(accountSidParam), requiredParams)); + } + return signatureList; + } + + + public List> lookForConditionalParameterInBody(List> conditionalParamDoubleList, CodegenOperation codegenOperation) { + return new ArrayList<>(); + } + + private List addAllToList(List... lists) { + return Arrays.stream(lists).flatMap(List::stream).collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/twilio/oai/java/feature/constructor/UrlencodedBodyConstructorGenerator.java b/src/main/java/com/twilio/oai/java/feature/constructor/UrlencodedBodyConstructorGenerator.java new file mode 100644 index 000000000..d8760a54e --- /dev/null +++ b/src/main/java/com/twilio/oai/java/feature/constructor/UrlencodedBodyConstructorGenerator.java @@ -0,0 +1,170 @@ +package com.twilio.oai.java.feature.constructor; + +import com.google.common.collect.Lists; +import com.twilio.oai.StringHelper; +import org.checkerframework.checker.units.qual.A; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenParameter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static com.twilio.oai.api.JavaApiResourceBuilder.SIGNATURE_LIST; +import static com.twilio.oai.common.ApplicationConstants.ACCOUNT_SID_VEND_EXT; + +/* + This class builds the constructor parameters from mandatory fields from parameter(path, query, header), request body and conditional fields + from request body. + */ +public class UrlencodedBodyConstructorGenerator extends ConstructorGenerator { + public void apply(CodegenOperation codegenOperation) { + codegenOperation.vendorExtensions.put("x-java-constructor", true); + codegenOperation.vendorExtensions.put(SIGNATURE_LIST, generateSignatureListModern(codegenOperation)); + } + + public boolean shouldApply(CodegenOperation codegenOperation) { + // TODO + //return true; + // Check if the operation consumes application/x-www-form-urlencoded + if (codegenOperation.consumes == null || codegenOperation.consumes.isEmpty()) { + return true; + } + boolean shouldApply = codegenOperation.consumes.stream() + .anyMatch(mediaType -> mediaType.get("mediaType").equals("application/x-www-form-urlencoded")); + return shouldApply; + } + + /* + Steps: + 1. Get required parameters from path, query, header, body except accountSid + 2. Get accountSid parameter from path if exists + 3. Get conditional parameters from body + 4. Get cartesian product of conditional parameters + 5. Filter out similar datatype parameters because they will create same constructors + 6. Combine required and conditional parameters to form the signature list + 7. If accountSid exists, add it to the beginning of each signature + 8. Return the signature list + */ + public List> generateSignatureListModern(final CodegenOperation codegenOperation) { + // Step 1 + List requiredParams = getRequiredParameters(codegenOperation); + // Step 2 + CodegenParameter accountSidParam = getAccountSidParameter(codegenOperation); + // Step 3 + List> conditionalParameters = getConditionalParameters(codegenOperation); + // Step 4 + List> cartesianProducts = Lists.cartesianProduct(conditionalParameters); + // Step 5 + List> filteredConditionalCodegenParam = filterConditionalParameters(cartesianProducts); + // Step 6 + List> listOfConstructors = combineParameters(requiredParams, filteredConditionalCodegenParam, accountSidParam); + return listOfConstructors; + } + + private List getRequiredParameters(CodegenOperation codegenOperation) { + List requiredParams; + requiredParams = codegenOperation.pathParams.stream() + .filter(param -> !param.vendorExtensions.containsKey(ACCOUNT_SID_VEND_EXT)) + .collect(Collectors.toList()); + requiredParams.addAll(codegenOperation.queryParams.stream() + .filter(param -> param.required) + .collect(Collectors.toList())); + requiredParams.addAll(codegenOperation.formParams.stream() + .filter(param -> param.required) + .collect(Collectors.toList())); + requiredParams.addAll(codegenOperation.headerParams.stream() + .filter(param -> param.required) + .collect(Collectors.toList())); + return requiredParams; + } + private CodegenParameter getAccountSidParameter(CodegenOperation codegenOperation) { + return codegenOperation.pathParams.stream() + .filter(param -> param.vendorExtensions.containsKey(ACCOUNT_SID_VEND_EXT)) + .findAny() + .orElse(null); + } + + public List> getConditionalParameters(CodegenOperation codegenOperation) { + List> conditionalParamDoubleList = new ArrayList<>(); + try { + conditionalParamDoubleList = (List>) ((HashMap) codegenOperation.vendorExtensions.get("x-twilio")).get("conditional"); + } catch (NullPointerException nullPointerException) { + // skip list do not exist. + } + if (conditionalParamDoubleList == null || conditionalParamDoubleList.isEmpty()) { + return List.of(); + } + List> conditionalCodegenParam = lookForConditionalParameterInBody(conditionalParamDoubleList, codegenOperation); + + // added filter to prevent same signature types + conditionalCodegenParam = conditionalCodegenParam.stream().filter(cpList -> (cpList.size() <=1 || !cpList.get(0).dataType.equals(cpList.get(1).dataType))).collect(Collectors.toList()); + return conditionalCodegenParam; + } + + /* + * The `conditionalParameterDoubleList` contains combinations of constructors derived solely from conditional parameters. + * It is necessary to filter out constructors with similar parameter combinations to ensure uniqueness. + */ + public List> filterConditionalParameters(List> conditionalParams) { + List> filteredConditionalCodegenParam = new ArrayList<>(); + HashSet> signatureHashSet = new HashSet<>(); + for (List paramList : conditionalParams) { + List orderedParamList = paramList.stream().map(p -> p.dataType).collect(Collectors.toList()); + if (signatureHashSet.add(orderedParamList)) { + filteredConditionalCodegenParam.add(paramList); + } + } + return filteredConditionalCodegenParam; + } + + private List> combineParameters(List requiredParams, + List> filteredConditionalCodegenParam, + CodegenParameter accountSidParam) { + List> signatureList = new ArrayList<>(); + for (List paramList : filteredConditionalCodegenParam) { + signatureList.add(addAllToList(requiredParams, paramList)); + if (accountSidParam != null) { + signatureList.add(addAllToList(List.of(accountSidParam), requiredParams, paramList)); + } + } + return signatureList; + } + + public List> lookForConditionalParameterInBody(List> conditionalParamDoubleList, CodegenOperation codegenOperation) { + List> conditionalCodegenParam = new ArrayList<>(); + for (List conditionalParamList : conditionalParamDoubleList) { + List foundParameters = new ArrayList<>(); + for (String cp : conditionalParamList) { + CodegenParameter matchedParam = null; + for (CodegenParameter formParam : codegenOperation.formParams) { + if (!formParam.required + && StringHelper.camelize(formParam.baseName, true) + .equals(StringHelper.camelize(cp, true))) { + matchedParam = formParam; + break; + } + } + if (matchedParam == null) { + throw new IllegalArgumentException("Parameter not found: " + cp); + } + foundParameters.add(matchedParam); + } + conditionalCodegenParam.add(foundParameters); + } + return conditionalCodegenParam; + } + + @SafeVarargs + private final List mergeLists(List... lists) { + return Arrays.stream(lists).flatMap(List::stream).collect(Collectors.toList()); + } + + private List addAllToList(List... lists) { + return Arrays.stream(lists).flatMap(List::stream).collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/src/main/java/com/twilio/oai/java/feature/datamodels/DataModel.java b/src/main/java/com/twilio/oai/java/feature/datamodels/DataModel.java new file mode 100644 index 000000000..4d7e7526b --- /dev/null +++ b/src/main/java/com/twilio/oai/java/feature/datamodels/DataModel.java @@ -0,0 +1,9 @@ +package com.twilio.oai.java.feature.datamodels; + +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenOperation; + +public interface DataModel { + void apply(CodegenOperation codegenOperation); + boolean shouldApply(CodegenModel codegenModel); +} diff --git a/src/main/java/com/twilio/oai/java/feature/datamodels/DataModelManager.java b/src/main/java/com/twilio/oai/java/feature/datamodels/DataModelManager.java new file mode 100644 index 000000000..98f0e9320 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/feature/datamodels/DataModelManager.java @@ -0,0 +1,49 @@ +package com.twilio.oai.java.feature.datamodels; + +import com.twilio.oai.java.cache.ResourceCacheContext; +import org.openapitools.codegen.CodegenModel; + +import java.util.List; + +public class DataModelManager { + + public static DataModelManager instance; + List dataModels; + + private DataModelManager() { + dataModels = List.of( + new OneOf() + ); + } + + public static synchronized DataModelManager getInstance() { + if (instance == null) { + synchronized (DataModelManager.class) { + if (instance == null) { + instance = new DataModelManager(); + } + } + } + return instance; + } + + public void apply() { + for (CodegenModel codegenModel: ResourceCacheContext.get().getAllModelsByDefaultGenerator()) { + for (DataModel dataModel: dataModels) { + if (dataModel.shouldApply(codegenModel)) { + //dataModel.apply(); + // Can a CodegenModel have multiple datamodels at same level, if yes don't return ? + } + } + } + } + + public boolean shouldApply(final CodegenModel codegenModel) { + for (DataModel dataModel : dataModels) { + if (dataModel.shouldApply(codegenModel)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/com/twilio/oai/java/feature/datamodels/OneOf.java b/src/main/java/com/twilio/oai/java/feature/datamodels/OneOf.java new file mode 100644 index 000000000..74b884b2a --- /dev/null +++ b/src/main/java/com/twilio/oai/java/feature/datamodels/OneOf.java @@ -0,0 +1,46 @@ +package com.twilio.oai.java.feature.datamodels; + +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheOneOfIface; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenOperation; + +import java.util.Map; +import java.util.Set; + +/* + This class has 2 responsibilities + 1. Identifying oneOf interfaces and ignore it so that concrete classes shouldn't generate. + 2. Identify the concrete classes from interfaces and create relationship between concrete class and interface. +*/ +public class OneOf implements DataModel { + Map allModelsMap = ResourceCacheContext.get().getAllModelsByDefaultGenerator().stream() + .collect(java.util.stream.Collectors.toMap(m -> m.name, m -> m)); + + @Override + public void apply(final CodegenOperation codegenOperation) { + + } + + private void resolveOneOf(CodegenOperation codegenOperation) { + + } + + @Override + public boolean shouldApply(final CodegenModel codegenModel) { + if (codegenModel == null || codegenModel.oneOf == null || codegenModel.oneOf.isEmpty()) { + return false; + } + return true; + } + + public void addInterfaceMustache(CodegenModel codegenModel) { + MustacheOneOfIface oneOfIface = new MustacheOneOfIface(codegenModel.classname); + ResourceCacheContext.get().addToOneOfInterfaces(oneOfIface); + + } + + public void addImplMustache() { + + } +} diff --git a/src/main/java/com/twilio/oai/java/format/Deserializer.java b/src/main/java/com/twilio/oai/java/format/Deserializer.java new file mode 100644 index 000000000..22ae9af02 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/format/Deserializer.java @@ -0,0 +1,14 @@ +package com.twilio.oai.java.format; + +import org.openapitools.codegen.CodegenProperty; + +public class Deserializer { + + public static void addDeserializer(CodegenProperty codegenProperty) { + if (codegenProperty.getFormat() != null && OpenApiSpecFormatFeatureConstants.DESERIALIZER.containsKey(codegenProperty.getFormat())) { + String deserializer = OpenApiSpecFormatFeatureConstants.DESERIALIZER.get(codegenProperty.getFormat()); + codegenProperty.vendorExtensions.put("x-deserializer", deserializer); + System.out.println(deserializer); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/twilio/oai/java/format/JavaUpdateDefaultMapping.java b/src/main/java/com/twilio/oai/java/format/JavaUpdateDefaultMapping.java new file mode 100644 index 000000000..dea363e2d --- /dev/null +++ b/src/main/java/com/twilio/oai/java/format/JavaUpdateDefaultMapping.java @@ -0,0 +1,94 @@ +package com.twilio.oai.java.format; + +import com.twilio.oai.java.format.OpenApiSpecFormatFeatureConstants; +import io.swagger.v3.oas.models.OpenAPI; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class JavaUpdateDefaultMapping { + HashSet customFormatWithProperties = new HashSet<>(); + + /* + If a property in the OpenAPI specification is defined as + date_generated: + type: string + format: date-time + The expected datatype for the above is: OffsetDateTime + The expected import is: java.time.OffsetDateTime + + Example: + typeMapping.put("string+date-time", "OffsetDateTime"); + importMapping.put("OffsetDateTime", "java.time.OffsetDateTime"); + + class AbstractJavaCodegen, method: public String getSchemaType(Schema p) at this place dataType is set + */ + // TODO: Anytype is pending + public void typeMapping(Map typeMapping) { + typeMapping.putAll(OpenApiSpecFormatFeatureConstants.getPredefinedTypeMappings()); + } + + public void importMapping(Map importMapping) { + // This is an example of how to add a custom import mapping. + importMapping.putAll(OpenApiSpecFormatFeatureConstants.getPredefinedImportMappings()); + } + + public void modelTemplateFiles(Map modelTemplateFiles) { + // Do not generate models + modelTemplateFiles.clear(); + } + + public void removeReservedWords(Set reservedWords) { + // Do not generate models + reservedWords.remove("localdate"); + } + + /* + If a parameter or property in the OpenAPI specification has properties defined, then generator considers it as a complex type. + So to avoid that, we remove the properties from the custom models, So that typeMapping can be used to map the type to a custom class. + + Alternative is to remove properties from the OpenAPI specification itself, but that might be used by doc team. + + Example: + dummyName: + type: object + format: ice-server + properties: + credential: + type: string + username: + type: string + url: + type: string + urls: + type: string + */ + public void removePropertiesFromCustomModels(OpenAPI openAPI) { + customFormatWithProperties.add("ice-server"); + customFormatWithProperties.add("subscribe-rule"); + customFormatWithProperties.add("recording-rule"); + customFormatWithProperties.add("inbound-call-price"); + customFormatWithProperties.add("inbound-sms-price"); + customFormatWithProperties.add("outbound-call-price"); + customFormatWithProperties.add("outbound-call-price-with-origin"); + customFormatWithProperties.add("outbound-prefix-price"); + customFormatWithProperties.add("outbound-sms-price"); + customFormatWithProperties.add("phone-number-capabilities"); + customFormatWithProperties.add("phone-number-price"); + customFormatWithProperties.add("prefixed-collapsible-map"); + customFormatWithProperties.add("prefixed-collapsible-map-AddOns"); + customFormatWithProperties.add("outbound-prefix-price-with-origin"); + customFormatWithProperties.add("string-map"); + customFormatWithProperties.add("uri-map"); + + openAPI.getComponents().getSchemas() + .forEach((name, schema) -> { + if (customFormatWithProperties.contains(schema.getFormat())) { + if (schema.getProperties() != null) { + schema.setProperties(null); + } + } + }); + } +} \ No newline at end of file diff --git a/src/main/java/com/twilio/oai/java/format/OpenApiSpecFormatFeatureConstants.java b/src/main/java/com/twilio/oai/java/format/OpenApiSpecFormatFeatureConstants.java new file mode 100644 index 000000000..044188da5 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/format/OpenApiSpecFormatFeatureConstants.java @@ -0,0 +1,119 @@ +package com.twilio.oai.java.format; + +import java.util.HashMap; +import java.util.Map; + +/* +Must be kept in sync with src/main/resources/config/java.json + */ +public class OpenApiSpecFormatFeatureConstants { + + /* + * key (format) -> The key is the format defined in the OpenAPI Spec. + * inputType -> Customer will provide inputType. + * promoter -> Promoter will use this to convert the inputType to the desired type. + * + * This can be applied to setters. For example, if a query parameter is of the format "phone-number", + * two setters will be created: one for `PhoneNumber` and another for `String`. + * The promoter logic will be applied to the `String` setter. + */ + public final static Map PROMOTIONS = Map.of( + "uri", new Promotion("String", "Promoter.uriFromString({})"), + "phone-number", new Promotion("String", "Promoter.phoneNumberFromString({})"), + "twiml", new Promotion("String", "Promoter.twimlFromString({})") + ); + + /* + * key (format) -> The key is the format defined in the OpenAPI Spec. + * value -> deserializer class name in twilio-java + */ + public final static Map DESERIALIZER = Map.of( + // Covers Hydrate mentioned in java.json + "date-time-rfc-2822", "com.twilio.converter.RFC2822Deserializer", + "date-time", "com.twilio.converter.ISO8601Deserializer", + "date", "com.twilio.converter.LocalDateDeserializer", + // Covers deserialize mentioned in java.json + "currency", "com.twilio.converter.CurrencyDeserializer" + ); + + /* + * key -> The key is the combination of type+format defined in the OpenAPI Spec. + * value -> The value is the Java type that should be used for that combination. + */ + final static Map getPredefinedTypeMappings() { + final Map predefinedTypeMappings = new HashMap<>(); + // The following two mappings may seem unnecessary, but they are essential. + // They address a bug that incorrectly converts Map to MapStringString. + predefinedTypeMappings.put("Map", "Map"); + predefinedTypeMappings.put("Map", "Map"); + + predefinedTypeMappings.put("string+phone-number", "com.twilio.type.PhoneNumber"); + predefinedTypeMappings.put("com.twilio.type.PhoneNumber", "com.twilio.type.PhoneNumber"); + predefinedTypeMappings.put("string+endpoint", "com.twilio.type.Endpoint"); + predefinedTypeMappings.put("com.twilio.type.Endpoint", "com.twilio.type.Endpoint"); + predefinedTypeMappings.put("string+twiml", "com.twilio.type.Twiml"); + predefinedTypeMappings.put("com.twilio.type.Twiml", "com.twilio.type.Twiml"); + + + predefinedTypeMappings.put("string+uri", "URI"); + predefinedTypeMappings.put("string+url", "URI"); + predefinedTypeMappings.put("string+currency", "Currency"); + predefinedTypeMappings.put("string+date-time", "ZonedDateTime"); + predefinedTypeMappings.put("string+date", "LocalDate"); + //predefinedTypeMappings.put("LocalDate", "LocalDate"); + predefinedTypeMappings.put("string+http-method", "HttpMethod"); + predefinedTypeMappings.put("string+date-time-rfc-2822", "ZonedDateTime"); + predefinedTypeMappings.put("object+ice-server", "IceServer"); + predefinedTypeMappings.put("object+subscribe-rule", "SubscribeRule"); + predefinedTypeMappings.put("object+recording-rule", "RecordingRule"); + predefinedTypeMappings.put("object+inbound-call-price", "InboundCallPrice"); + predefinedTypeMappings.put("object+inbound-sms-price", "InboundSmsPrice"); + predefinedTypeMappings.put("object+outbound-call-price", "OutboundCallPrice"); + predefinedTypeMappings.put("object+outbound-call-price-with-origin", "OutboundCallPriceWithOrigin"); + predefinedTypeMappings.put("object+outbound-prefix-price", "OutboundPrefixPrice"); + predefinedTypeMappings.put("object+outbound-sms-price", "OutboundSmsPrice"); + predefinedTypeMappings.put("object+phone-number-capabilities", "PhoneNumberCapabilities"); + predefinedTypeMappings.put("object+phone-number-price", "PhoneNumberPrice"); + predefinedTypeMappings.put("object+prefixed-collapsible-map", "Map"); + predefinedTypeMappings.put("object+prefixed-collapsible-map-AddOns", "Map"); + predefinedTypeMappings.put("object+outbound-prefix-price-with-origin", "OutboundPrefixPriceWithOrigin"); + predefinedTypeMappings.put("object+string-map", "Map"); + predefinedTypeMappings.put("object+uri-map", "Map"); + return predefinedTypeMappings; + } + + /* + * key -> Java datatype + * value -> Java import statement for key + */ + public static Map getPredefinedImportMappings() { + + Map predefinedImportMappings = new HashMap<>(); + predefinedImportMappings.put("PhoneNumber", "com.twilio.type.PhoneNumber"); + predefinedImportMappings.put("URI", "java.net.URI"); + predefinedImportMappings.put("Currency", "java.util.Currency"); + predefinedImportMappings.put("HttpMethod", "com.twilio.http.HttpMethod"); + predefinedImportMappings.put("Endpoint", "com.twilio.type.Endpoint"); + predefinedImportMappings.put("ZonedDateTime", "java.time.ZonedDateTime"); + + predefinedImportMappings.put("IceServer", "com.twilio.type.IceServer"); + predefinedImportMappings.put("SubscribeRule", "com.twilio.type.SubscribeRule"); + predefinedImportMappings.put("RecordingRule", "com.twilio.type.RecordingRule"); + predefinedImportMappings.put("PhoneNumberCapabilities", "com.twilio.type.PhoneNumberCapabilities"); + predefinedImportMappings.put("FeedbackIssue", "com.twilio.type.FeedbackIssue"); + predefinedImportMappings.put("PhoneNumberPrice", "com.twilio.type.PhoneNumberPrice"); + predefinedImportMappings.put("OutboundSmsPrice", "com.twilio.type.OutboundSmsPrice"); + predefinedImportMappings.put("InboundSmsPrice", "com.twilio.type.InboundSmsPrice"); + predefinedImportMappings.put("OutboundPrefixPrice", "com.twilio.type.OutboundPrefixPrice"); + predefinedImportMappings.put("InboundCallPrice", "com.twilio.type.InboundCallPrice"); + predefinedImportMappings.put("OutboundCallPrice", "com.twilio.type.OutboundCallPrice"); + predefinedImportMappings.put("OutboundCallPriceWithOrigin", "com.twilio.type.OutboundCallPriceWithOrigin"); + predefinedImportMappings.put("OutboundPrefixPriceWithOrigin", "com.twilio.type.OutboundPrefixPriceWithOrigin"); + predefinedImportMappings.put("PrefixedCollapsibleMap", "com.twilio.converter.PrefixedCollapsibleMap"); + //predefinedImportMappings.put("Map", "java.util.Map"); + + return predefinedImportMappings; + } +} + + diff --git a/src/main/java/com/twilio/oai/java/format/Promoter.java b/src/main/java/com/twilio/oai/java/format/Promoter.java new file mode 100644 index 000000000..4aa8f180e --- /dev/null +++ b/src/main/java/com/twilio/oai/java/format/Promoter.java @@ -0,0 +1,44 @@ +package com.twilio.oai.java.format; + +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenParameter; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/* + * The `Promoter` class is responsible for adding additional methods to provide flexibility + * for customers to pass `String` as an input parameter instead of specific objects. + * + * Promoters are applied only to inputs such as query, header, and URL-encoded form body parameters. + * These additional methods are generated alongside the required setter methods. + * + * Note: + * - Promoters cannot be applied to path parameters because path parameters cannot be custom objects + * defined in `PROMOTIONS`. + * - The promoter logic uses the `{{paramName}}` placeholder in the setter method argument to ensure + * proper substitution of parameter names. + */ +public class Promoter { + public static void addPromoter(final CodegenParameter codegenParameter) { + if (codegenParameter.dataFormat != null && OpenApiSpecFormatFeatureConstants.PROMOTIONS.containsKey(codegenParameter.dataFormat)) { + Promotion promotion = OpenApiSpecFormatFeatureConstants.PROMOTIONS.get(codegenParameter.dataFormat); + String promoter = promotion.getPromoter(); + String promoterToBeUsedInMustache = promoter.replace("{}", codegenParameter.paramName); + codegenParameter.vendorExtensions.put("x-promotion", promoterToBeUsedInMustache); + } + } + + public static void addPromoter(final CodegenOperation codegenOperation) { + //List setterParameters = codegenOperation.allParams.stream().filter(param -> !param.isPathParam).collect(Collectors.toList()); + // Add promoter to following input variables. + List setterParameters = new ArrayList<>(codegenOperation.bodyParams); + setterParameters.addAll(codegenOperation.formParams); + setterParameters.addAll(codegenOperation.queryParams); + setterParameters.addAll(codegenOperation.headerParams); + setterParameters.forEach(param -> addPromoter(param)); + } +} + + diff --git a/src/main/java/com/twilio/oai/java/format/Promotion.java b/src/main/java/com/twilio/oai/java/format/Promotion.java new file mode 100644 index 000000000..141a2d556 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/format/Promotion.java @@ -0,0 +1,12 @@ +package com.twilio.oai.java.format; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +public class Promotion { + @Getter + String inputType; + @Getter + String promoter; +} diff --git a/src/main/java/com/twilio/oai/java/nestedmodels/MustacheEnum.java b/src/main/java/com/twilio/oai/java/nestedmodels/MustacheEnum.java new file mode 100644 index 000000000..c8573171c --- /dev/null +++ b/src/main/java/com/twilio/oai/java/nestedmodels/MustacheEnum.java @@ -0,0 +1,120 @@ +package com.twilio.oai.java.nestedmodels; + +import com.twilio.oai.common.StringUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +// Currently only String enums are Supported +/* + public enum Direction { + INBOUND("inbound"), + OUTBOUND_API("outbound-api"), + OUTBOUND_CALL("outbound-call"), + OUTBOUND_REPLY("outbound-reply"); + + private final String value; + + private Direction(final String value) { + this.value = value; + } + + public String toString() { + return value; + } + + @JsonCreator + public static Direction forValue(final String value) { + return Promoter.enumFromString(value, Direction.values()); + } + } + */ +public class MustacheEnum { + String className; + Map values; + + /* + Allowed Keys: + name: Enum value name, typically in capital letter (INBOUND, OUTBOUND_API, etc.) + value: Enum value as in open api spec. (inbound, outbound-api, etc.) + */ + List> enumValues; + + public MustacheEnum(String className, List> enumValues) { + if (org.apache.commons.lang3.StringUtils.isBlank(className) || enumValues == null || enumValues.isEmpty()) { + throw new RuntimeException("MustacheEnum requires a non-empty className and values map."); + } + this.className = StringUtils.toPascalCase(className); + this.enumValues = new ArrayList<>(enumValues); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + MustacheEnum that = (MustacheEnum) obj; + return className != null && className.equals(that.className); + } + + @Override + public int hashCode() { + return className != null ? className.hashCode() : 0; + } +} + +/* +# Fetching class name for enum +Example1: +--------- +- in: query + name: PauseBehaviorMethod + required: true + schema: + type: string + enum: + - Trial + - Full + +name = PascalCase(codegenParameter.baseName) + +Example2: +--------- +- in: header + name: X-Twilio-Webhook-Enabled + schema: + type: string + $ref: '#/components/schemas/account_enum_X_Twilio_Webhook_Enabled' + + + + +Example3: this is passed as property (parameter.items --> codegenProperty) +--------- +- in: header + name: DummyStatus + required: true + schema: + type: array + items: + $ref: '#/components/schemas/test_enum_status' +SplitEnum(codegenProperty.datatypeWithEnum) + +Example4: +--------- +- in: header + name: SomeStatus + required: true + schema: + type: array + items: + type: string + enum: + - active + - inactive + - pending + +PascalCase(codegenParameter.baseName) + */ diff --git a/src/main/java/com/twilio/oai/java/nestedmodels/MustacheModel.java b/src/main/java/com/twilio/oai/java/nestedmodels/MustacheModel.java new file mode 100644 index 000000000..e9d657c32 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/nestedmodels/MustacheModel.java @@ -0,0 +1,71 @@ +package com.twilio.oai.java.nestedmodels; + +import com.twilio.oai.common.Utility; +import org.checkerframework.checker.units.qual.A; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenParameter; +import org.openapitools.codegen.CodegenProperty; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +// Models can be created out of json request body or json response body. +public class MustacheModel { + String className; + + // Used in either builder or setter + List allProperties; + + // Used in constructor + List mandatoryProperties; + + List optionalProperties; + + public MustacheModel(CodegenProperty codegenProperty, CodegenModel codegenModel) { + this.className = codegenModel.classname; + + this.allProperties = new ArrayList<>(codegenModel.vars); + + this.mandatoryProperties = codegenModel.vars.stream() + .filter(codegenProperty1 -> codegenProperty1.required) + .collect(Collectors.toList()); + + this.optionalProperties = codegenModel.vars.stream() + .filter(codegenProperty1 -> !codegenProperty1.required) + .collect(Collectors.toList()); + } + + public MustacheModel(CodegenParameter codegenParameter, CodegenModel codegenModel) { + this.className = codegenModel.classname; + + this.allProperties = new ArrayList<>(codegenModel.vars); + + this.mandatoryProperties = codegenModel.vars.stream() + .filter(codegenProperty1 -> codegenProperty1.required) + .collect(Collectors.toList()); + + this.optionalProperties = codegenModel.vars.stream() + .filter(codegenProperty1 -> !codegenProperty1.required) + .collect(Collectors.toList()); + } + + public MustacheModel(String className, List mandatoryProperties, List allProperties) { + this.className = className; + this.mandatoryProperties = new ArrayList<>(mandatoryProperties); + this.allProperties = new ArrayList<>(allProperties); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + MustacheModel that = (MustacheModel) obj; + return className != null && className.equals(that.className); + } + + @Override + public int hashCode() { + return className != null ? className.hashCode() : 0; + } +} diff --git a/src/main/java/com/twilio/oai/java/nestedmodels/MustacheOneOf.java b/src/main/java/com/twilio/oai/java/nestedmodels/MustacheOneOf.java new file mode 100644 index 000000000..ad79d2a6f --- /dev/null +++ b/src/main/java/com/twilio/oai/java/nestedmodels/MustacheOneOf.java @@ -0,0 +1,25 @@ +package com.twilio.oai.java.nestedmodels; + +// Implementation of OneOf interface for Mustache templates +public class MustacheOneOf { + String className; + String discriminator; + + public MustacheOneOf(String className, String discriminator) { + this.className = className; + this.discriminator = discriminator; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + MustacheOneOf that = (MustacheOneOf) obj; + return className != null && className.equals(that.className); + } + + @Override + public int hashCode() { + return className != null ? className.hashCode() : 0; + } +} diff --git a/src/main/java/com/twilio/oai/java/nestedmodels/MustacheOneOfIface.java b/src/main/java/com/twilio/oai/java/nestedmodels/MustacheOneOfIface.java new file mode 100644 index 000000000..c25bbd140 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/nestedmodels/MustacheOneOfIface.java @@ -0,0 +1,15 @@ +package com.twilio.oai.java.nestedmodels; + +public class MustacheOneOfIface { + String interfaceClassName; + String discriminator; + + public MustacheOneOfIface(String interfaceClassName) { + this.interfaceClassName = interfaceClassName; + } + + public MustacheOneOfIface(String interfaceClassName, String discriminator) { + this.interfaceClassName = interfaceClassName; + this.discriminator = discriminator; + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/JavaOperationProcessor.java b/src/main/java/com/twilio/oai/java/processor/JavaOperationProcessor.java new file mode 100644 index 000000000..4266ac9b3 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/JavaOperationProcessor.java @@ -0,0 +1,41 @@ +package com.twilio.oai.java.processor; + +import com.twilio.oai.java.feature.SetterMethodGenerator; +import com.twilio.oai.java.feature.constructor.ConstructorFactory; +import com.twilio.oai.java.format.Promoter; +import com.twilio.oai.java.processor.auth.SecuritySchemeManager; +import com.twilio.oai.java.processor.parameter.ParameterProcessor; +import com.twilio.oai.java.processor.requestbody.RequestBodyProcessorFactory; +import com.twilio.oai.java.processor.responsebody.ResponseProcessorFactory; +import org.openapitools.codegen.CodegenOperation; + +public class JavaOperationProcessor { + + public static JavaOperationProcessor instance; + public static synchronized JavaOperationProcessor getInstance() { + if (instance == null) { + synchronized (JavaOperationProcessor.class) { + if (instance == null) { + instance = new JavaOperationProcessor(); + } + } + } + return instance; + } + + private JavaOperationProcessor() { } + + public void process(final CodegenOperation codegenOperation) { + SecuritySchemeManager.getInstance().applyProcessor(codegenOperation); + + ParameterProcessor.getInstance().process(codegenOperation); + RequestBodyProcessorFactory.getInstance().process(codegenOperation); + ResponseProcessorFactory.getInstance().process(codegenOperation); + + + // All Features should be applied after processors are completed + ConstructorFactory.getInstance().applyFeature(codegenOperation); + SetterMethodGenerator.getInstance().apply(codegenOperation); + Promoter.addPromoter(codegenOperation); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/PaginationStrategy.java b/src/main/java/com/twilio/oai/java/processor/PaginationStrategy.java new file mode 100644 index 000000000..baf90d45a --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/PaginationStrategy.java @@ -0,0 +1,7 @@ +package com.twilio.oai.java.processor; + +/* +There are 2 types pagination strategies are supported nextPrev and direct. + */ +public interface PaginationStrategy { +} diff --git a/src/main/java/com/twilio/oai/java/processor/auth/Auth.java b/src/main/java/com/twilio/oai/java/processor/auth/Auth.java new file mode 100644 index 000000000..be584e029 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/auth/Auth.java @@ -0,0 +1,26 @@ +package com.twilio.oai.java.processor.auth; + +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenSecurity; + +import java.util.HashMap; +import java.util.List; + +import static com.twilio.oai.resolver.java.JavaConventionResolver.AUTH_IMPORT_CLASS; +import static com.twilio.oai.resolver.java.JavaConventionResolver.HTTP_CLASS_PREFIX; + +public class Auth implements SecuritySchemeProcessor { + @Override + public void process(CodegenOperation codegenOperation) { + } + + @Override + public boolean shouldProcess(CodegenOperation codegenOperation) { + List securities = codegenOperation.authMethods; + if (securities == null || securities.isEmpty()) return false; // No Authentication + return true; +// if (securities.size() > 1) { +// throw new RuntimeException("Multiple auth methods are not supported. Please use only one auth method per operation."); +// } + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/auth/NoAuth.java b/src/main/java/com/twilio/oai/java/processor/auth/NoAuth.java new file mode 100644 index 000000000..b2623af32 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/auth/NoAuth.java @@ -0,0 +1,28 @@ +package com.twilio.oai.java.processor.auth; + +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenSecurity; + +import java.util.HashMap; +import java.util.List; + +import static com.twilio.oai.resolver.java.JavaConventionResolver.AUTH_IMPORT_CLASS; +import static com.twilio.oai.resolver.java.JavaConventionResolver.HTTP_CLASS_PREFIX; +import static com.twilio.oai.resolver.java.JavaConventionResolver.NOAUTH_HTTP_CLASS_PREFIX; +import static com.twilio.oai.resolver.java.JavaConventionResolver.NOAUTH_IMPORT_CLASS; + +public class NoAuth implements SecuritySchemeProcessor { + + @Override + public void process(CodegenOperation codegenOperation) { + codegenOperation.vendorExtensions.put(noAuth, true); + } + + @Override + public boolean shouldProcess(CodegenOperation codegenOperation) { + // This processor is for operations that do not require authentication + List securities = codegenOperation.authMethods; + if (securities == null || securities.isEmpty()) return true; + return false; + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/auth/SecuritySchemeManager.java b/src/main/java/com/twilio/oai/java/processor/auth/SecuritySchemeManager.java new file mode 100644 index 000000000..6afce19a3 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/auth/SecuritySchemeManager.java @@ -0,0 +1,57 @@ +package com.twilio.oai.java.processor.auth; + +import org.openapitools.codegen.CodegenOperation; + +import java.util.List; + +public class SecuritySchemeManager { + public static SecuritySchemeManager instance; + private final List securitySchemeProcessors; + + public static synchronized SecuritySchemeManager getInstance() { + if (instance == null) { + synchronized (SecuritySchemeManager.class) { + if (instance == null) { + instance = new SecuritySchemeManager(); + } + } + } + return instance; + } + + private SecuritySchemeManager() { + this.securitySchemeProcessors = List.of( + new NoAuth(), + new Auth() + ); + } + + public void applyProcessor(CodegenOperation codegenOperation) { + + for (SecuritySchemeProcessor securitySchemeProcessor : securitySchemeProcessors) { + if (securitySchemeProcessor.shouldProcess(codegenOperation)) { + securitySchemeProcessor.process(codegenOperation); + } + } + } +} +/* +ArrayList authMethods = (ArrayList) co.authMethods; +HashMap authAttributes = new HashMap<>(); + if(authMethods == null){ + authAttributes.put(AUTH_IMPORT_CLASS, NOAUTH_IMPORT_CLASS); + authAttributes.put(HTTP_CLASS_PREFIX, NOAUTH_HTTP_CLASS_PREFIX); + }else{ + for(CodegenSecurity c : authMethods){ + if(c.isOAuth == true){ + authAttributes.put(AUTH_IMPORT_CLASS, BEARER_AUTH_IMPORT_CLASS); + authAttributes.put(HTTP_CLASS_PREFIX, BEARER_AUTH_HTTP_CLASS_PREFIX); + } + else{ + authAttributes.put(AUTH_IMPORT_CLASS, EMPTY_STRING); + authAttributes.put(HTTP_CLASS_PREFIX, EMPTY_STRING); + } + } + } + co.vendorExtensions.put("x-auth-attributes", authAttributes); + */ \ No newline at end of file diff --git a/src/main/java/com/twilio/oai/java/processor/auth/SecuritySchemeProcessor.java b/src/main/java/com/twilio/oai/java/processor/auth/SecuritySchemeProcessor.java new file mode 100644 index 000000000..31a57bd21 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/auth/SecuritySchemeProcessor.java @@ -0,0 +1,12 @@ +package com.twilio.oai.java.processor.auth; + +import org.openapitools.codegen.CodegenOperation; + +// Orgs OAuth and Basic Auth has different RestClients. +// Set "x-auth-attributes" for different type of authentication +public interface SecuritySchemeProcessor { + String authAttributesExtension = "x-auth-attributes"; + String noAuth = "x-no-auth"; + void process(CodegenOperation codegenOperation); + boolean shouldProcess(CodegenOperation codegenOperation); +} diff --git a/src/main/java/com/twilio/oai/java/processor/enums/EnumProcessor.java b/src/main/java/com/twilio/oai/java/processor/enums/EnumProcessor.java new file mode 100644 index 000000000..d1d8db015 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/EnumProcessor.java @@ -0,0 +1,9 @@ +package com.twilio.oai.java.processor.enums; + +import com.twilio.oai.common.EnumConstants.OpenApiEnumType; + +public interface EnumProcessor { + boolean shouldProcess(T schema); + void process(T schema); + OpenApiEnumType getType(); +} diff --git a/src/main/java/com/twilio/oai/java/processor/enums/EnumProcessorFactory.java b/src/main/java/com/twilio/oai/java/processor/enums/EnumProcessorFactory.java new file mode 100644 index 000000000..5b52c4628 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/EnumProcessorFactory.java @@ -0,0 +1,129 @@ +package com.twilio.oai.java.processor.enums; + +import com.twilio.oai.java.processor.enums.parameter.ParameterEnumProcessor; +import com.twilio.oai.java.processor.enums.parameter.body.InlineBodyEnumProcessor; +import com.twilio.oai.java.processor.enums.parameter.body.InlineBodyListEnumProcessor; +import com.twilio.oai.java.processor.enums.parameter.body.ReusableBodyEnumProcessor; +import com.twilio.oai.java.processor.enums.parameter.body.ReusableBodyListEnumProcessor; +import com.twilio.oai.java.processor.enums.parameter.param.InlineListParamEnumProcessor; +import com.twilio.oai.java.processor.enums.parameter.param.InlineParamEnumProcessor; +import com.twilio.oai.java.processor.enums.parameter.param.ReusableListParamEnumProcessor; +import com.twilio.oai.java.processor.enums.parameter.param.ReusableParamEnumProcessor; +import com.twilio.oai.java.processor.enums.property.InlineListPropEnumProcessor; +import com.twilio.oai.java.processor.enums.property.InlinePropEnumProcessor; +import com.twilio.oai.java.processor.enums.property.PropertyEnumProcessor; +import com.twilio.oai.java.processor.enums.property.ReusableListPropEnumProcessor; +import com.twilio.oai.java.processor.enums.property.ReusablePropEnumProcessor; +import org.openapitools.codegen.CodegenParameter; +import org.openapitools.codegen.CodegenProperty; + +import java.util.List; + +import static com.twilio.oai.common.ApplicationConstants.X_DATATYPE; + +/* + * Factory class to manage and apply enum processors for CodegenParameter and CodegenProperty. + * + * This class is implemented as a singleton to ensure that only one instance of the factory exists + * throughout the application. + * + * The processors (e.g., `InlineBodyEnumProcessor`, `ReusablePropEnumProcessor`) are instantiated + * during the initialization of the factory. Since the factory is a singleton, these processor + * instances effectively behave as singletons within the context of the factory. There is no need + * to make these processor classes singleton themselves, as their lifecycle is already managed + * by the factory. + * + */ +public class EnumProcessorFactory { + + public static EnumProcessorFactory instance; + private final List parameterEnumProcessors; + private final List propertyEnumProcessors; + + public static synchronized EnumProcessorFactory getInstance() { + if (instance == null) { + synchronized (EnumProcessorFactory.class) { + if (instance == null) { + instance = new EnumProcessorFactory(); + } + } + } + return instance; + } + + private EnumProcessorFactory() { + this.parameterEnumProcessors = List.of( + new InlineBodyEnumProcessor(), + new InlineBodyListEnumProcessor(), + new ReusableBodyEnumProcessor(), + new ReusableBodyListEnumProcessor(), + + new InlineListParamEnumProcessor(), + new InlineParamEnumProcessor(), + new ReusableListParamEnumProcessor(), + new ReusableParamEnumProcessor() + ); + + this.propertyEnumProcessors = List.of( + new InlineListPropEnumProcessor(), + new InlinePropEnumProcessor(), + new ReusableListPropEnumProcessor(), + new ReusablePropEnumProcessor() + ); + } + + public void applyProcessor(CodegenParameter codegenParameter) { + if (codegenParameter.dataFormat != null && codegenParameter.dataFormat.equals("http-method")) { + return; + } + for (ParameterEnumProcessor parameterEnumProcessor: parameterEnumProcessors) { + if (parameterEnumProcessor.shouldProcess(codegenParameter)) { + parameterEnumProcessor.process(codegenParameter); + // TODO: to be deleted later. + addDataType(codegenParameter); + return; // Exit after the first processor that applies + } + } + } + + // TODO: to be deleted later. + private void addDataType(CodegenParameter codegenParameter) { + codegenParameter.dataType = (String)codegenParameter.vendorExtensions.get(X_DATATYPE); + } + + // TODO: to be deleted later. + private void addDataType(CodegenProperty codegenProperty) { + codegenProperty.dataType = (String)codegenProperty.vendorExtensions.get(X_DATATYPE); + } + + public void applyProcessor(CodegenProperty codegenProperty) { + if (codegenProperty.dataFormat != null && codegenProperty.dataFormat.equals("http-method")) { + return; + } + for (PropertyEnumProcessor propertyEnumProcessor: propertyEnumProcessors) { + if (propertyEnumProcessor.shouldProcess(codegenProperty)) { + propertyEnumProcessor.process(codegenProperty); + addDataType(codegenProperty); + return; // Exit after the first processor that applies + } + } + } + + public boolean isEnum(final CodegenParameter codegenParameter) { + for (ParameterEnumProcessor parameterEnumProcessor: parameterEnumProcessors) { + if (parameterEnumProcessor.shouldProcess(codegenParameter)) { + return true; // If any processor can process, it's considered an enum + } + } + return false; + } + + public boolean isEnum(final CodegenProperty codegenProperty) { + for (PropertyEnumProcessor propertyEnumProcessor : propertyEnumProcessors) { + if (propertyEnumProcessor.shouldProcess(codegenProperty)) { + return true; // If any processor can process, it's considered an enum + } + } + return false; + } +} \ No newline at end of file diff --git a/src/main/java/com/twilio/oai/java/processor/enums/enum.puml b/src/main/java/com/twilio/oai/java/processor/enums/enum.puml new file mode 100644 index 000000000..30d0d9018 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/enum.puml @@ -0,0 +1,66 @@ +@startuml + interface EnumProcessor { + + boolean shouldProcess(T schema) + + void process(T schema) + + OpenApiEnumType getType() + } + + + interface ParameterEnumProcessor { + + boolean shouldProcess(CodegenParameter schema) + + void process(CodegenParameter schema) + + OpenApiEnumType getType() + } + + interface PropertyEnumProcessor { + + boolean shouldProcess(CodegenProperty schema) + + void process(CodegenProperty schema) + + OpenApiEnumType getType() + } + + class EnumProcessorFactory { + - List parameterEnumProcessors + - List propertyEnumProcessors + + EnumProcessorFactory() + + void applyProcessor(CodegenParameter codegenParameter) + + void applyProcessor(CodegenProperty codegenProperty) + } + + + class InlineBodyEnumProcessor + class InlineBodyListEnumProcessor + class ReusableBodyEnumProcessor + class ReusableBodyListEnumProcessor + class InlineListParamEnumProcessor + class InlineParamEnumProcessor + class ReusableListParamEnumProcessor + class ReusableParamEnumProcessor + + + + class InlineListPropEnumProcessor + class InlinePropEnumProcessor + class ReusableListPropEnumProcessor + class ReusablePropEnumProcessor + + +EnumProcessor <|.. ParameterEnumProcessor +EnumProcessor <|.. PropertyEnumProcessor + +EnumProcessorFactory o-- ParameterEnumProcessor +EnumProcessorFactory o-- PropertyEnumProcessor + +ParameterEnumProcessor <|-- InlineBodyEnumProcessor +ParameterEnumProcessor <|-- InlineBodyListEnumProcessor +ParameterEnumProcessor <|-- ReusableBodyEnumProcessor +ParameterEnumProcessor <|-- ReusableBodyListEnumProcessor +ParameterEnumProcessor <|-- InlineListParamEnumProcessor +ParameterEnumProcessor <|-- InlineParamEnumProcessor +ParameterEnumProcessor <|-- ReusableListParamEnumProcessor +ParameterEnumProcessor <|-- ReusableParamEnumProcessor + +PropertyEnumProcessor <|-- InlineListPropEnumProcessor +PropertyEnumProcessor <|-- InlinePropEnumProcessor +PropertyEnumProcessor <|-- ReusableListPropEnumProcessor +PropertyEnumProcessor <|-- ReusablePropEnumProcessor +@enduml \ No newline at end of file diff --git a/src/main/java/com/twilio/oai/java/processor/enums/parameter/ParameterEnumProcessor.java b/src/main/java/com/twilio/oai/java/processor/enums/parameter/ParameterEnumProcessor.java new file mode 100644 index 000000000..78c069bcc --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/parameter/ParameterEnumProcessor.java @@ -0,0 +1,7 @@ +package com.twilio.oai.java.processor.enums.parameter; + +import com.twilio.oai.java.processor.enums.EnumProcessor; +import org.openapitools.codegen.CodegenParameter; + +public interface ParameterEnumProcessor extends EnumProcessor { +} diff --git a/src/main/java/com/twilio/oai/java/processor/enums/parameter/body/InlineBodyEnumProcessor.java b/src/main/java/com/twilio/oai/java/processor/enums/parameter/body/InlineBodyEnumProcessor.java new file mode 100644 index 000000000..c60944fcf --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/parameter/body/InlineBodyEnumProcessor.java @@ -0,0 +1,74 @@ +package com.twilio.oai.java.processor.enums.parameter.body; + +import com.twilio.oai.common.EnumConstants; +import com.twilio.oai.common.StringUtils; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheEnum; +import com.twilio.oai.java.processor.enums.parameter.ParameterEnumProcessor; +import org.openapitools.codegen.CodegenParameter; + +import java.util.List; +import java.util.Map; + +import static com.twilio.oai.common.ApplicationConstants.DOT; +import static com.twilio.oai.common.ApplicationConstants.X_DATATYPE; +import static com.twilio.oai.common.ApplicationConstants.X_ENUM_TYPE; +import static com.twilio.oai.common.ApplicationConstants.X_VARIABLE_NAME; + +/* + application/x-www-form-urlencoded: + schema: + type: object + properties: + # PROPERTY_SINGLE + singleBody: + type: string + enum: + - available + - pending + - sold + */ +// Renamed from FormParamInlineStrategy +public class InlineBodyEnumProcessor implements ParameterEnumProcessor { + @Override + public boolean shouldProcess(CodegenParameter codegenParameter) { + if (codegenParameter.getSchema() != null) return false; + if (codegenParameter._enum != null && codegenParameter.isEnum && !codegenParameter.isContainer) { + return true; + } + return false; + } + + @Override + public void process(CodegenParameter codegenParameter) { + if (!shouldProcess(codegenParameter)) return; + type(codegenParameter); + variableName(codegenParameter); + datatype(codegenParameter); + cacheEnumClass(codegenParameter); + } + + @Override + public EnumConstants.OpenApiEnumType getType() { + return null; + } + + + private void type(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_ENUM_TYPE, EnumConstants.OpenApiEnumType.FORM_PARAM_INLINE); + } + private void variableName(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_VARIABLE_NAME, StringUtils.toCamelCase(codegenParameter.baseName)); + } + private void datatype(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_DATATYPE, + ResourceCacheContext.get().getResourceName() + DOT + StringUtils.toPascalCase(codegenParameter.baseName)); + } + + private void cacheEnumClass(CodegenParameter codegenParameter) { + List> enumValues = (List>) codegenParameter.allowableValues.get("enumVars"); + + MustacheEnum mustacheEnum = new MustacheEnum(StringUtils.toPascalCase(codegenParameter.baseName), enumValues); + ResourceCacheContext.get().addToEnumClasses(mustacheEnum); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/enums/parameter/body/InlineBodyListEnumProcessor.java b/src/main/java/com/twilio/oai/java/processor/enums/parameter/body/InlineBodyListEnumProcessor.java new file mode 100644 index 000000000..a3aa5d4b0 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/parameter/body/InlineBodyListEnumProcessor.java @@ -0,0 +1,84 @@ +package com.twilio.oai.java.processor.enums.parameter.body; + +import com.twilio.oai.common.EnumConstants; +import com.twilio.oai.common.StringUtils; +import com.twilio.oai.common.Utility; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheEnum; +import com.twilio.oai.java.processor.enums.parameter.ParameterEnumProcessor; +import org.openapitools.codegen.CodegenParameter; + +import java.util.List; +import java.util.Map; + +import static com.twilio.oai.common.ApplicationConstants.DOT; +import static com.twilio.oai.common.ApplicationConstants.X_DATATYPE; +import static com.twilio.oai.common.ApplicationConstants.X_ENUM_TYPE; +import static com.twilio.oai.common.ApplicationConstants.X_VARIABLE_NAME; + +/* + application/x-www-form-urlencoded: + schema: + type: object + properties: + # PROPERTY_ARRAY + singleBodyArray: + type: array + items: + type: string + enum: [ new, sale, featured ] + description: An array of enum values in the request body + example: [ new, featured ] + */ +public class InlineBodyListEnumProcessor implements ParameterEnumProcessor { + private final EnumConstants.OpenApiEnumType type = EnumConstants.OpenApiEnumType.FORM_PARAM_LIST_INLINE; + @Override + public boolean shouldProcess(CodegenParameter codegenParameter) { + if (codegenParameter.getSchema() != null) return false; + if (codegenParameter.items != null && codegenParameter.items._enum != null && codegenParameter.isEnum) { + return true; + } + return false; + } + + @Override + public void process(CodegenParameter codegenParameter) { + if (!shouldProcess(codegenParameter)) return; + type(codegenParameter); + variableName(codegenParameter); + datatype(codegenParameter); + cacheEnumClass(codegenParameter); + } + + @Override + public EnumConstants.OpenApiEnumType getType() { + return type; + } + + private void type(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_ENUM_TYPE, EnumConstants.OpenApiEnumType.FORM_PARAM_INLINE); + } + private void variableName(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_VARIABLE_NAME, StringUtils.toCamelCase(codegenParameter.baseName)); + } + private void datatype(CodegenParameter codegenParameter) { + // codegenParameter.dataType = List + // enumExistingDatatype = String + String enumExistingDatatype = Utility.extractDatatypeFromContainer(codegenParameter.dataType); + String enumClassName = StringUtils.toPascalCase(codegenParameter.baseName); + String enumNonContainerDatatype = ResourceCacheContext.get().getResourceName() + DOT + enumClassName; + String resolvedDataType = Utility.replaceDatatypeInContainer(codegenParameter.dataType, enumNonContainerDatatype); + codegenParameter.vendorExtensions.put(X_DATATYPE, resolvedDataType); + + // Resolve BaseType for List as it is used in promoter as setter method. + codegenParameter.baseType = enumNonContainerDatatype; + } + + private void cacheEnumClass(CodegenParameter codegenParameter) { + String enumClassName = StringUtils.toPascalCase(codegenParameter.baseName); + List> enumValues = (List>) codegenParameter.allowableValues.get("enumVars"); + + MustacheEnum mustacheEnum = new MustacheEnum(enumClassName, enumValues); + ResourceCacheContext.get().addToEnumClasses(mustacheEnum); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/enums/parameter/body/ReusableBodyEnumProcessor.java b/src/main/java/com/twilio/oai/java/processor/enums/parameter/body/ReusableBodyEnumProcessor.java new file mode 100644 index 000000000..253d31db9 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/parameter/body/ReusableBodyEnumProcessor.java @@ -0,0 +1,73 @@ +package com.twilio.oai.java.processor.enums.parameter.body; + +import com.twilio.oai.common.EnumConstants; +import com.twilio.oai.common.StringUtils; +import com.twilio.oai.common.Utility; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheEnum; +import com.twilio.oai.java.processor.enums.parameter.ParameterEnumProcessor; +import org.openapitools.codegen.CodegenParameter; + +import java.util.List; +import java.util.Map; + +import static com.twilio.oai.common.ApplicationConstants.DOT; +import static com.twilio.oai.common.ApplicationConstants.X_DATATYPE; +import static com.twilio.oai.common.ApplicationConstants.X_ENUM_TYPE; +import static com.twilio.oai.common.ApplicationConstants.X_VARIABLE_NAME; + +/* + application/x-www-form-urlencoded: + schema: + type: object + properties: + # REUSABLE_SINGLE + singleBodyRef: + $ref: '#/components/schemas/singleReusable' + description: A reusable single-value enum in the request body + */ +public class ReusableBodyEnumProcessor implements ParameterEnumProcessor { + private final EnumConstants.OpenApiEnumType type = EnumConstants.OpenApiEnumType.FORM_PARAM_REF; + @Override + public boolean shouldProcess(CodegenParameter codegenParameter) { + if (codegenParameter.getSchema() != null) return false; + if (!codegenParameter.isEnum && codegenParameter.isEnumRef) { + return true; + } + return false; + } + + @Override + public void process(CodegenParameter codegenParameter) { + if (!shouldProcess(codegenParameter)) return; + type(codegenParameter); + variableName(codegenParameter); + datatype(codegenParameter); + cacheEnumClass(codegenParameter); + } + + @Override + public EnumConstants.OpenApiEnumType getType() { + return type; + } + + private void type(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_ENUM_TYPE, EnumConstants.OpenApiEnumType.FORM_PARAM_REF); + } + private void variableName(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_VARIABLE_NAME, StringUtils.toCamelCase(codegenParameter.baseName)); + } + private void datatype(CodegenParameter codegenParameter) { + String enumName = Utility.getEnumNameFromDefaultDatatype(codegenParameter.dataType); + codegenParameter.vendorExtensions.put(X_DATATYPE, Utility.appendResourceNameToEnum(enumName)); + } + + private void cacheEnumClass(CodegenParameter codegenParameter) { + // TODO: Best way to store = codegenParameter.allowableValues.get("enumVars") + String enumClassName = StringUtils.toPascalCase(Utility.getEnumNameFromDefaultDatatype(codegenParameter.dataType)); + List> enumValues = (List>) codegenParameter.allowableValues.get("enumVars"); + + MustacheEnum mustacheEnum = new MustacheEnum(enumClassName, enumValues); + ResourceCacheContext.get().addToEnumClasses(mustacheEnum); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/enums/parameter/body/ReusableBodyListEnumProcessor.java b/src/main/java/com/twilio/oai/java/processor/enums/parameter/body/ReusableBodyListEnumProcessor.java new file mode 100644 index 000000000..5c224e7e1 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/parameter/body/ReusableBodyListEnumProcessor.java @@ -0,0 +1,111 @@ +package com.twilio.oai.java.processor.enums.parameter.body; + +import com.twilio.oai.common.EnumConstants; +import com.twilio.oai.common.StringUtils; +import com.twilio.oai.common.Utility; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheEnum; +import com.twilio.oai.java.processor.enums.parameter.ParameterEnumProcessor; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenParameter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static com.twilio.oai.common.ApplicationConstants.DOT; +import static com.twilio.oai.common.ApplicationConstants.X_DATATYPE; +import static com.twilio.oai.common.ApplicationConstants.X_ENUM_TYPE; +import static com.twilio.oai.common.ApplicationConstants.X_VARIABLE_NAME; + +/* + application/x-www-form-urlencoded: + schema: + type: object + properties: + # REUSABLE_ARRAY + singleBodyRefArray: + type: array + items: + $ref: '#/components/schemas/singleReusable' + description: An array of reusable enum in the request body + example: [ electronics, clothing ] + */ +// renamed from FormParamListRefStrategy +public class ReusableBodyListEnumProcessor implements ParameterEnumProcessor { + private final EnumConstants.OpenApiEnumType type = EnumConstants.OpenApiEnumType.FORM_PARAM_LIST_REF; + @Override + public boolean shouldProcess(CodegenParameter codegenParameter) { + if (codegenParameter.getSchema() != null) return false; + if (codegenParameter.items != null && codegenParameter.items.isEnumRef && !codegenParameter.items.isEnum) { + return true; + } + return false; + } + + @Override + public void process(CodegenParameter codegenParameter) { + if (!shouldProcess(codegenParameter)) return; + type(codegenParameter); + variableName(codegenParameter); + datatype(codegenParameter); + cacheEnumClass(codegenParameter); + } + + @Override + public EnumConstants.OpenApiEnumType getType() { + return type; + } + + private void type(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_ENUM_TYPE, EnumConstants.OpenApiEnumType.FORM_PARAM_LIST_REF); + } + private void variableName(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_VARIABLE_NAME, StringUtils.toCamelCase(codegenParameter.baseName)); + } + private void datatype(CodegenParameter codegenParameter) { + // codegenParameter.dataType = List + // enumExistingDatatype = AccountEnumStatus + String enumExistingDatatype = Utility.extractDatatypeFromContainer(codegenParameter.dataType); + // enumClassName = Status + String enumClassName = Utility.getEnumNameFromDatatype(enumExistingDatatype); + // enumNonContainerDatatype = Account.Status + String enumNonContainerDatatype = Utility.appendResourceNameToEnum(enumClassName); + //ResourceCacheContext.get().getResourceName() + DOT + StringUtils.toPascalCase(enumClassName); + // resolvedDataType = List + String resolvedDataType = Utility.replaceDatatypeInContainer(codegenParameter.dataType, enumNonContainerDatatype); + codegenParameter.vendorExtensions.put(X_DATATYPE, resolvedDataType); + + // Resolve BaseType for List as it is used in promoter as setter method. + codegenParameter.baseType = enumNonContainerDatatype; + } + + private void cacheEnumClass(CodegenParameter codegenParameter) { + String baseDataType = Utility.extractDatatypeFromContainer(codegenParameter.dataType); + if (baseDataType == null) { + throw new RuntimeException("Not able to fetch enum baseType for List Enum with ref" + " DataType: " +codegenParameter.dataType); + } + String enumClassName = Utility.getEnumNameFromDatatype(baseDataType); + if (enumClassName == null) { + throw new RuntimeException("Not able to fetch enum class name from baseDataType for List Enum with ref" + + "baseType:"+ baseDataType + " DataType: " + codegenParameter.dataType); + } + + Map values = null; + List> enumValues = new ArrayList<>(); + + for (CodegenModel codegenModel: ResourceCacheContext.get().getAllModelsByDefaultGenerator()) { + if (baseDataType.equals(codegenModel.classname)) { + values = codegenModel.allowableValues; + enumValues = (List>) codegenModel.allowableValues.get("enumVars"); + break; + } + } + if (enumValues == null || enumValues.isEmpty()) { + System.out.println("Exception occurred:" + codegenParameter.baseName); + throw new RuntimeException("No enum values found for Enum" + " DataType: " +codegenParameter.dataType); + } + MustacheEnum mustacheEnum = new MustacheEnum(enumClassName, enumValues); + ResourceCacheContext.get().addToEnumClasses(mustacheEnum); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/enums/parameter/param/InlineListParamEnumProcessor.java b/src/main/java/com/twilio/oai/java/processor/enums/parameter/param/InlineListParamEnumProcessor.java new file mode 100644 index 000000000..e9209677e --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/parameter/param/InlineListParamEnumProcessor.java @@ -0,0 +1,86 @@ +package com.twilio.oai.java.processor.enums.parameter.param; + +import com.twilio.oai.common.EnumConstants.OpenApiEnumType; +import com.twilio.oai.common.StringUtils; +import com.twilio.oai.common.Utility; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheEnum; +import com.twilio.oai.java.processor.enums.parameter.ParameterEnumProcessor; +import org.openapitools.codegen.CodegenParameter; + +import java.util.List; +import java.util.Map; + +import static com.twilio.oai.common.ApplicationConstants.DOT; +import static com.twilio.oai.common.ApplicationConstants.X_DATATYPE; +import static com.twilio.oai.common.ApplicationConstants.X_ENUM_TYPE; +import static com.twilio.oai.common.ApplicationConstants.X_VARIABLE_NAME; + +/* + Example: + - name: arrayParam + in: query + description: Order items using an array of enums + required: false + schema: + type: array + items: + type: string + enum: + - asc + - desc + example: [asc] + */ +public class InlineListParamEnumProcessor implements ParameterEnumProcessor { + + private final OpenApiEnumType type = OpenApiEnumType.PARAMETER_LIST_INLINE; + + @Override + public boolean shouldProcess(CodegenParameter codegenParameter) { + if (codegenParameter.getSchema() == null) return false; + if (codegenParameter.getSchema()._enum == null && + codegenParameter.getSchema().items != null && codegenParameter.getSchema().items._enum != null) { + return true; + } + return false; + } + + @Override + public void process(final CodegenParameter codegenParameter) { + if (!shouldProcess(codegenParameter)) return; + type(codegenParameter); + variableName(codegenParameter); + datatype(codegenParameter); + cacheEnumClass(codegenParameter); + } + + @Override + public OpenApiEnumType getType() { + return type; + } + + private void type(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_ENUM_TYPE, OpenApiEnumType.PARAMETER_LIST_INLINE); + } + private void variableName(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_VARIABLE_NAME, StringUtils.toCamelCase(codegenParameter.baseName)); + } + private void datatype(CodegenParameter codegenParameter) { + String enumClassName = StringUtils.toPascalCase(codegenParameter.baseName); + String enumNonContainerDatatype = ResourceCacheContext.get().getResourceName() + DOT + StringUtils.toPascalCase(enumClassName); + String resolvedDataType = Utility.replaceDatatypeInContainer(codegenParameter.dataType, enumNonContainerDatatype); + codegenParameter.vendorExtensions.put(X_DATATYPE, resolvedDataType); + + // Resolve BaseType for List as it is used in promoter as setter method. + codegenParameter.baseType = enumNonContainerDatatype; + // enumNonContainerDatatype = Account.Status + + } + + private void cacheEnumClass(CodegenParameter codegenParameter) { + List> enumValues = (List>) codegenParameter.allowableValues.get("enumVars"); + + MustacheEnum mustacheEnum = new MustacheEnum( StringUtils.toPascalCase(codegenParameter.baseName), enumValues); + ResourceCacheContext.get().addToEnumClasses(mustacheEnum); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/enums/parameter/param/InlineParamEnumProcessor.java b/src/main/java/com/twilio/oai/java/processor/enums/parameter/param/InlineParamEnumProcessor.java new file mode 100644 index 000000000..46b516ecd --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/parameter/param/InlineParamEnumProcessor.java @@ -0,0 +1,73 @@ +package com.twilio.oai.java.processor.enums.parameter.param; + +import com.twilio.oai.common.EnumConstants.OpenApiEnumType; +import com.twilio.oai.common.StringUtils; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheEnum; +import com.twilio.oai.java.processor.enums.parameter.ParameterEnumProcessor; +import org.openapitools.codegen.CodegenParameter; + +import java.util.List; +import java.util.Map; + +import static com.twilio.oai.common.ApplicationConstants.DOT; +import static com.twilio.oai.common.ApplicationConstants.X_DATATYPE; +import static com.twilio.oai.common.ApplicationConstants.X_ENUM_TYPE; +import static com.twilio.oai.common.ApplicationConstants.X_VARIABLE_NAME; + +/* + - name: singleParam + in: query + description: A single enum value as a query parameter + required: false + schema: + type: string + enum: + - asc + - desc + example: asc + */ +public class InlineParamEnumProcessor implements ParameterEnumProcessor { + + private final OpenApiEnumType type = OpenApiEnumType.PARAMETER_INLINE; + + @Override + public void process(final CodegenParameter codegenParameter) { + if (!shouldProcess(codegenParameter)) return; + type(codegenParameter); + variableName(codegenParameter); + datatype(codegenParameter); + cacheEnumClass(codegenParameter); + } + + @Override + public OpenApiEnumType getType() { + return type; + } + + @Override + public boolean shouldProcess(CodegenParameter codegenParameter) { + if (codegenParameter.getSchema() == null) return false; + if (codegenParameter.getSchema()._enum != null && codegenParameter.isEnum) { + return true; + } + return false; + } + + private void type(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_ENUM_TYPE, type); + } + private void variableName(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_VARIABLE_NAME, StringUtils.toCamelCase(codegenParameter.baseName)); + } + private void datatype(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_DATATYPE, + ResourceCacheContext.get().getResourceName() + DOT + StringUtils.toPascalCase(codegenParameter.baseName)); + } + + private void cacheEnumClass(CodegenParameter codegenParameter) { + List> enumValues = (List>) codegenParameter.allowableValues.get("enumVars"); + MustacheEnum mustacheEnum = new MustacheEnum(StringUtils.toPascalCase(codegenParameter.baseName), enumValues); + ResourceCacheContext.get().addToEnumClasses(mustacheEnum); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/enums/parameter/param/ReusableListParamEnumProcessor.java b/src/main/java/com/twilio/oai/java/processor/enums/parameter/param/ReusableListParamEnumProcessor.java new file mode 100644 index 000000000..a0970d29d --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/parameter/param/ReusableListParamEnumProcessor.java @@ -0,0 +1,85 @@ +package com.twilio.oai.java.processor.enums.parameter.param; + +import com.twilio.oai.common.EnumConstants.OpenApiEnumType; +import com.twilio.oai.common.StringUtils; +import com.twilio.oai.common.Utility; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheEnum; +import com.twilio.oai.java.processor.enums.parameter.ParameterEnumProcessor; +import org.openapitools.codegen.CodegenParameter; + +import java.util.List; +import java.util.Map; + +import static com.twilio.oai.common.ApplicationConstants.DOT; +import static com.twilio.oai.common.ApplicationConstants.X_DATATYPE; +import static com.twilio.oai.common.ApplicationConstants.X_ENUM_TYPE; +import static com.twilio.oai.common.ApplicationConstants.X_VARIABLE_NAME; + +/* + - name: arrayParamRef + in: query + required: false + description: An array parameter referencing a reusable schema + schema: + type: array + items: + $ref: '#/components/schemas/singleReusable' + */ +public class ReusableListParamEnumProcessor implements ParameterEnumProcessor { + + private final OpenApiEnumType type = OpenApiEnumType.PARAMETER_LIST_REF; + + @Override + public void process(final CodegenParameter codegenParameter) { + if (!shouldProcess(codegenParameter)) return; + type(codegenParameter); + variableName(codegenParameter); + datatype(codegenParameter); + cacheEnumClass(codegenParameter); + } + + @Override + public OpenApiEnumType getType() { + return type; + } + + @Override + public boolean shouldProcess(CodegenParameter codegenParameter) { + if (codegenParameter.getSchema() == null) return false; + if (codegenParameter.getSchema().items != null && codegenParameter.getSchema().items.getRef() != null + && codegenParameter.getSchema().items.isEnumRef) { + return true; + } + return false; + } + + private void type(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_ENUM_TYPE, OpenApiEnumType.PARAMETER_LIST_REF); + } + private void variableName(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_VARIABLE_NAME, StringUtils.toCamelCase(codegenParameter.baseName)); + } + private void datatype(CodegenParameter codegenParameter) { + // #/components/schemas/singleReusable or #/components/schemas/content_enum_single_reusable + // enumRefResolved = singleReusable + String enumRefResolved = Utility.getEnumNameFromRef(codegenParameter.getSchema().items.getRef()); + // enumNonContainerDatatype = Content.SingleReusable + String enumNonContainerDatatype = Utility.appendResourceNameToEnum(enumRefResolved); + //ResourceCacheContext.get().getResourceName() + DOT + StringUtils.toPascalCase(enumRefResolved); + // resolvedDataType = List + String resolvedDataType = Utility.replaceDatatypeInContainer(codegenParameter.dataType, enumNonContainerDatatype); + codegenParameter.vendorExtensions.put(X_DATATYPE, resolvedDataType); + + // Resolve BaseType for List as it is used in promoter as setter method. + codegenParameter.baseType = enumNonContainerDatatype; + } + + private void cacheEnumClass(CodegenParameter codegenParameter) { + List> enumValues = (List>) codegenParameter.getSchema().items.allowableValues.get("enumVars"); + + MustacheEnum mustacheEnum = new MustacheEnum(StringUtils.toPascalCase( + Utility.getEnumNameFromRef(codegenParameter.getSchema().items.getRef())), enumValues); + ResourceCacheContext.get().addToEnumClasses(mustacheEnum); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/enums/parameter/param/ReusableParamEnumProcessor.java b/src/main/java/com/twilio/oai/java/processor/enums/parameter/param/ReusableParamEnumProcessor.java new file mode 100644 index 000000000..e95d85a27 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/parameter/param/ReusableParamEnumProcessor.java @@ -0,0 +1,67 @@ +package com.twilio.oai.java.processor.enums.parameter.param; + +import com.twilio.oai.common.EnumConstants.OpenApiEnumType; +import com.twilio.oai.common.StringUtils; +import com.twilio.oai.common.Utility; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheEnum; +import com.twilio.oai.java.processor.enums.parameter.ParameterEnumProcessor; +import org.openapitools.codegen.CodegenParameter; + +import java.util.List; +import java.util.Map; + +import static com.twilio.oai.common.ApplicationConstants.DOT; +import static com.twilio.oai.common.ApplicationConstants.X_DATATYPE; +import static com.twilio.oai.common.ApplicationConstants.X_ENUM_TYPE; +import static com.twilio.oai.common.ApplicationConstants.X_VARIABLE_NAME; + +/* + - name: singleParamRef + in: header + schema: + $ref: '#/components/schemas/singleReusable' + */ +public class ReusableParamEnumProcessor implements ParameterEnumProcessor { + private final OpenApiEnumType type = OpenApiEnumType.PARAMETER_REF; + @Override + public void process(final CodegenParameter codegenParameter) { + if (!shouldProcess(codegenParameter)) return; + type(codegenParameter); + variableName(codegenParameter); + datatype(codegenParameter); + cacheEnumClass(codegenParameter); + } + + @Override + public OpenApiEnumType getType() { + return type; + } + + @Override + public boolean shouldProcess(CodegenParameter codegenParameter) { + if (codegenParameter.getSchema() == null) return false; + if (codegenParameter.getSchema().getRef() != null && codegenParameter.isEnumRef) { + return true; + } + return false; + } + + private void type(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_ENUM_TYPE, OpenApiEnumType.PARAMETER_REF); + } + private void variableName(CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_VARIABLE_NAME, StringUtils.toCamelCase(codegenParameter.baseName)); + } + private void datatype(CodegenParameter codegenParameter) { + String enumRefResolved = Utility.getEnumNameFromRef(codegenParameter.getSchema().getRef()); + codegenParameter.vendorExtensions.put(X_DATATYPE, Utility.appendResourceNameToEnum(enumRefResolved)); + } + + private void cacheEnumClass(CodegenParameter codegenParameter) { + List> enumValues = (List>) codegenParameter.allowableValues.get("enumVars"); + MustacheEnum mustacheEnum = new MustacheEnum(StringUtils.toPascalCase( + Utility.getEnumNameFromRef(codegenParameter.getSchema().getRef())), enumValues); + ResourceCacheContext.get().addToEnumClasses(mustacheEnum); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/enums/property/InlineListPropEnumProcessor.java b/src/main/java/com/twilio/oai/java/processor/enums/property/InlineListPropEnumProcessor.java new file mode 100644 index 000000000..10aaa5ca3 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/property/InlineListPropEnumProcessor.java @@ -0,0 +1,64 @@ +package com.twilio.oai.java.processor.enums.property; + +import com.twilio.oai.common.EnumConstants.OpenApiEnumType; +import com.twilio.oai.common.StringUtils; +import com.twilio.oai.common.Utility; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheEnum; +import org.openapitools.codegen.CodegenProperty; + +import java.util.List; +import java.util.Map; + +import static com.twilio.oai.common.ApplicationConstants.DOT; +import static com.twilio.oai.common.ApplicationConstants.X_DATATYPE; +import static com.twilio.oai.common.ApplicationConstants.X_ENUM_TYPE; +import static com.twilio.oai.common.ApplicationConstants.X_VARIABLE_NAME; + +public class InlineListPropEnumProcessor implements PropertyEnumProcessor { + private final OpenApiEnumType type = OpenApiEnumType.PROPERTY_LIST; + + @Override + public void process(final CodegenProperty codegenProperty) { + if (!shouldProcess(codegenProperty)) return; + type(codegenProperty); + variableName(codegenProperty); + datatype(codegenProperty); + cacheEnumClass(codegenProperty); + } + + public boolean shouldProcess(CodegenProperty codegenProperty) { + if (codegenProperty.isEnum && !codegenProperty.isEnumRef && codegenProperty.items != null && codegenProperty.items.get_enum() != null) { + return true; + } + return false; + } + + @Override + public OpenApiEnumType getType() { + // Return the type of enum this strategy identifies + return type; + } + + private void type(CodegenProperty codegenProperty) { + codegenProperty.vendorExtensions.put(X_ENUM_TYPE, type); + } + private void variableName(CodegenProperty codegenProperty) { + codegenProperty.vendorExtensions.put(X_VARIABLE_NAME, StringUtils.toCamelCase(codegenProperty.baseName)); + } + private void datatype(CodegenProperty codegenProperty) { + String enumClassName = StringUtils.toPascalCase(codegenProperty.baseName); + String enumNonContainerDatatype = ResourceCacheContext.get().getResourceName() + DOT + StringUtils.toPascalCase(enumClassName); + String resolvedDataType = Utility.replaceDatatypeInContainer(codegenProperty.dataType, enumNonContainerDatatype); + codegenProperty.vendorExtensions.put(X_DATATYPE, resolvedDataType); + + // Resolve BaseType for List as it is used in promoter as setter method. + codegenProperty.baseType = enumNonContainerDatatype; + } + + private void cacheEnumClass(CodegenProperty codegenProperty) { + List> enumValues = (List>) codegenProperty.allowableValues.get("enumVars"); + MustacheEnum mustacheEnum = new MustacheEnum(StringUtils.toPascalCase(codegenProperty.baseName), enumValues); + ResourceCacheContext.get().addToEnumClasses(mustacheEnum); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/enums/property/InlinePropEnumProcessor.java b/src/main/java/com/twilio/oai/java/processor/enums/property/InlinePropEnumProcessor.java new file mode 100644 index 000000000..b75568774 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/property/InlinePropEnumProcessor.java @@ -0,0 +1,72 @@ +package com.twilio.oai.java.processor.enums.property; + +import com.twilio.oai.StringHelper; +import com.twilio.oai.common.EnumConstants.OpenApiEnumType; +import com.twilio.oai.common.StringUtils; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheEnum; +import org.openapitools.codegen.CodegenProperty; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.twilio.oai.common.ApplicationConstants.DOT; +import static com.twilio.oai.common.ApplicationConstants.X_DATATYPE; +import static com.twilio.oai.common.ApplicationConstants.X_ENUM_TYPE; +import static com.twilio.oai.common.ApplicationConstants.X_VARIABLE_NAME; + +/* +codegenProperty._enum = true +codegenProperty.isEnum = true +codegenProperty.isEnumRef = true + */ +public class InlinePropEnumProcessor implements PropertyEnumProcessor { + private final OpenApiEnumType type = OpenApiEnumType.PROPERTY_INLINE; + @Override + public void process(final CodegenProperty codegenProperty) { + if (!shouldProcess(codegenProperty)) return; + type(codegenProperty); + variableName(codegenProperty); + datatype(codegenProperty); + cacheEnumClass(codegenProperty); + } + + @Override + public OpenApiEnumType getType() { + return type; + } + + @Override + public boolean shouldProcess(CodegenProperty codegenProperty) { + if (codegenProperty.isEnum && !codegenProperty.isEnumRef && codegenProperty.get_enum() != null) { + return true; + } + return false; + } + + private void type(CodegenProperty codegenProperty) { + codegenProperty.vendorExtensions.put(X_ENUM_TYPE, type); + } + private void variableName(CodegenProperty codegenProperty) { + codegenProperty.vendorExtensions.put(X_VARIABLE_NAME, StringUtils.toCamelCase(codegenProperty.baseName)); + } + private void datatype(CodegenProperty codegenProperty) { + codegenProperty.vendorExtensions.put(X_DATATYPE, + ResourceCacheContext.get().getResourceName() + DOT + StringUtils.toPascalCase(codegenProperty.baseName)); + } + + private void cacheEnumClass(CodegenProperty codegenProperty) { + List> enumValues = new ArrayList<>(); + + for (String s : (List) codegenProperty.allowableValues.get("values")) { + HashMap valueMap = new HashMap<>(); + valueMap.put("name", StringHelper.toSnakeCase(s).toUpperCase()); + valueMap.put("value", "\"" + s + "\""); // adding extra quote as this is how enumVars are stored + enumValues.add(valueMap); + } + MustacheEnum mustacheEnum = new MustacheEnum(StringUtils.toPascalCase(codegenProperty.baseName), enumValues); + ResourceCacheContext.get().addToEnumClasses(mustacheEnum); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/enums/property/PropertyEnumProcessor.java b/src/main/java/com/twilio/oai/java/processor/enums/property/PropertyEnumProcessor.java new file mode 100644 index 000000000..3fb850182 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/property/PropertyEnumProcessor.java @@ -0,0 +1,7 @@ +package com.twilio.oai.java.processor.enums.property; + +import com.twilio.oai.java.processor.enums.EnumProcessor; +import org.openapitools.codegen.CodegenProperty; + +public interface PropertyEnumProcessor extends EnumProcessor { +} diff --git a/src/main/java/com/twilio/oai/java/processor/enums/property/ReusableListPropEnumProcessor.java b/src/main/java/com/twilio/oai/java/processor/enums/property/ReusableListPropEnumProcessor.java new file mode 100644 index 000000000..c95bfaf7a --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/property/ReusableListPropEnumProcessor.java @@ -0,0 +1,71 @@ +package com.twilio.oai.java.processor.enums.property; + +import com.twilio.oai.common.EnumConstants.OpenApiEnumType; +import com.twilio.oai.common.StringUtils; +import com.twilio.oai.common.Utility; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheEnum; +import org.openapitools.codegen.CodegenProperty; + +import java.util.List; +import java.util.Map; + +import static com.twilio.oai.common.ApplicationConstants.DOT; +import static com.twilio.oai.common.ApplicationConstants.X_DATATYPE; +import static com.twilio.oai.common.ApplicationConstants.X_ENUM_TYPE; +import static com.twilio.oai.common.ApplicationConstants.X_VARIABLE_NAME; + +public class ReusableListPropEnumProcessor implements PropertyEnumProcessor { + private final OpenApiEnumType type = OpenApiEnumType.PROPERTY_INLINE; + @Override + public void process(final CodegenProperty codegenProperty) { + if (!shouldProcess(codegenProperty)) return; + type(codegenProperty); + variableName(codegenProperty); + datatype(codegenProperty); + cacheEnumClass(codegenProperty); + } + + @Override + public OpenApiEnumType getType() { + return type; + } + + @Override + public boolean shouldProcess(CodegenProperty codegenProperty) { + if (codegenProperty.items != null && codegenProperty.items.isEnumRef && !codegenProperty.items.isEnum) { + return true; + } + return false; + } + + private void type(CodegenProperty codegenProperty) { + codegenProperty.vendorExtensions.put(X_ENUM_TYPE, type); + } + private void variableName(CodegenProperty codegenProperty) { + codegenProperty.vendorExtensions.put(X_VARIABLE_NAME, StringUtils.toCamelCase(codegenProperty.baseName)); + } + private void datatype(CodegenProperty codegenProperty) { + String enumExistingDatatype = Utility.extractDatatypeFromContainer(codegenProperty.dataType); + // enumClassName = Status + String enumClassName = Utility.getEnumNameFromDatatype(enumExistingDatatype); + // enumNonContainerDatatype = Account.Status + String enumNonContainerDatatype = Utility.appendResourceNameToEnum(enumClassName); + // ResourceCacheContext.get().getResourceName() + DOT + StringUtils.toPascalCase(enumClassName); + // resolvedDataType = List + String resolvedDataType = Utility.replaceDatatypeInContainer(codegenProperty.dataType, enumNonContainerDatatype); + codegenProperty.vendorExtensions.put(X_DATATYPE, resolvedDataType); + + // Resolve BaseType for List as it is used in promoter as setter method. + codegenProperty.baseType = enumNonContainerDatatype; + } + + private void cacheEnumClass(CodegenProperty codegenProperty) { + String enumExistingDatatype = Utility.extractDatatypeFromContainer(codegenProperty.dataType); + String enumClassName = Utility.getEnumNameFromDatatype(enumExistingDatatype); + List> enumValues = (List>) codegenProperty.items.allowableValues.get("enumVars"); + + MustacheEnum mustacheEnum = new MustacheEnum(enumClassName, enumValues); + ResourceCacheContext.get().addToEnumClasses(mustacheEnum); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/enums/property/ReusablePropEnumProcessor.java b/src/main/java/com/twilio/oai/java/processor/enums/property/ReusablePropEnumProcessor.java new file mode 100644 index 000000000..21765adb7 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/enums/property/ReusablePropEnumProcessor.java @@ -0,0 +1,68 @@ +package com.twilio.oai.java.processor.enums.property; + +import com.twilio.oai.StringHelper; +import com.twilio.oai.common.EnumConstants.OpenApiEnumType; +import com.twilio.oai.common.StringUtils; +import com.twilio.oai.common.Utility; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheEnum; +import org.openapitools.codegen.CodegenProperty; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.twilio.oai.common.ApplicationConstants.DOT; +import static com.twilio.oai.common.ApplicationConstants.X_DATATYPE; +import static com.twilio.oai.common.ApplicationConstants.X_ENUM_TYPE; +import static com.twilio.oai.common.ApplicationConstants.X_VARIABLE_NAME; +public class ReusablePropEnumProcessor implements PropertyEnumProcessor { + private final OpenApiEnumType type = OpenApiEnumType.PROPERTY_REF; + @Override + public void process(final CodegenProperty codegenProperty) { + if (!shouldProcess(codegenProperty)) return; + type(codegenProperty); + variableName(codegenProperty); + datatype(codegenProperty); + cacheEnumClass(codegenProperty); + } + + @Override + public OpenApiEnumType getType() { + return type; + } + + @Override + public boolean shouldProcess(CodegenProperty codegenProperty) { + if (!codegenProperty.isEnum && codegenProperty.isEnumRef && codegenProperty.getRef() != null) { + return true; + } + return false; + } + + private void type(CodegenProperty codegenProperty) { + codegenProperty.vendorExtensions.put(X_ENUM_TYPE, type); + } + private void variableName(CodegenProperty codegenProperty) { + codegenProperty.vendorExtensions.put(X_VARIABLE_NAME, StringUtils.toCamelCase(codegenProperty.baseName)); + } + private void datatype(CodegenProperty codegenProperty) { + String enumName = Utility.getEnumNameFromDefaultDatatype(codegenProperty.getRef()); + codegenProperty.vendorExtensions.put(X_DATATYPE, Utility.appendResourceNameToEnum(enumName)); + } + + private void cacheEnumClass(CodegenProperty codegenProperty) { + System.out.println(codegenProperty.baseName); + String enumClassName = Utility.getEnumNameFromRef(codegenProperty.getRef()); + List> enumValues = new ArrayList<>(); + for (String s : (List) codegenProperty.allowableValues.get("values")) { + HashMap valueMap = new HashMap<>(); + valueMap.put("name", StringHelper.toSnakeCase(s).toUpperCase()); + valueMap.put("value", "\"" + s + "\""); // adding extra quote as this is how enumVars are stored + enumValues.add(valueMap); + } + MustacheEnum mustacheEnum = new MustacheEnum(StringUtils.toPascalCase(enumClassName), enumValues); + ResourceCacheContext.get().addToEnumClasses(mustacheEnum); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/model/ListModelStrategy.java b/src/main/java/com/twilio/oai/java/processor/model/ListModelStrategy.java new file mode 100644 index 000000000..6819b4578 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/model/ListModelStrategy.java @@ -0,0 +1,58 @@ +package com.twilio.oai.java.processor.model; + +import com.twilio.oai.common.EnumConstants.ModelType; +import com.twilio.oai.common.StringUtils; +import com.twilio.oai.common.Utility; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheModel; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenProperty; + +import static com.twilio.oai.common.ApplicationConstants.DOT; +import static com.twilio.oai.common.ApplicationConstants.X_DATATYPE; +import static com.twilio.oai.common.ApplicationConstants.X_MODEL_TYPE; +import static com.twilio.oai.common.ApplicationConstants.X_VARIABLE_NAME; + +public class ListModelStrategy implements ModelProcessor { + ModelType type = ModelType.LIST; + @Override + public void process(CodegenProperty codegenProperty, CodegenModel codegenModel) { + if (!codegenProperty.isContainer) return; + type(codegenProperty); + variableName(codegenProperty); + dataType(codegenProperty); + cacheModelClass(codegenProperty, codegenModel); + + } + + @Override + public boolean shouldProcess(CodegenProperty codegenProperty, CodegenModel codegenModel) { + if (codegenProperty.isContainer) return true; + return false; + } + + public ModelType getType() { + return type; + } + + + private void type(final CodegenProperty codegenProperty) { + codegenProperty.vendorExtensions.put(X_MODEL_TYPE, type); + } + + private void variableName(CodegenProperty codegenProperty) { + codegenProperty.vendorExtensions.put(X_VARIABLE_NAME, StringUtils.toCamelCase(codegenProperty.baseName)); + } + // basetype + private void dataType(CodegenProperty codegenProperty) { + //TODO: Need to identify whether the property is defined using ref or directly defined property + String datatypeInsideContainer = Utility.extractDatatypeFromContainer(codegenProperty.dataType); + String updatedDataType = Utility.replaceDatatypeInContainer(codegenProperty.dataType, ResourceCacheContext.get().getResourceName() + DOT + datatypeInsideContainer); + codegenProperty.vendorExtensions.put(X_DATATYPE, updatedDataType); + } + + private void cacheModelClass(CodegenProperty codegenProperty, CodegenModel codegenModel) { + MustacheModel mustacheModel = new MustacheModel(codegenProperty, codegenModel); + ResourceCacheContext.get().addToModelClasses(mustacheModel); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/model/ModelProcessor.java b/src/main/java/com/twilio/oai/java/processor/model/ModelProcessor.java new file mode 100644 index 000000000..1d912ad4a --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/model/ModelProcessor.java @@ -0,0 +1,9 @@ +package com.twilio.oai.java.processor.model; + +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenProperty; + +public interface ModelProcessor { + boolean shouldProcess(CodegenProperty codegenProperty, CodegenModel codegenModel); + void process(CodegenProperty codegenProperty, CodegenModel codegenModel); +} diff --git a/src/main/java/com/twilio/oai/java/processor/model/ModelProcessorFactory.java b/src/main/java/com/twilio/oai/java/processor/model/ModelProcessorFactory.java new file mode 100644 index 000000000..79e33cc56 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/model/ModelProcessorFactory.java @@ -0,0 +1,40 @@ +package com.twilio.oai.java.processor.model; + +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenProperty; + +import java.util.List; + +public class ModelProcessorFactory { + + private static ModelProcessorFactory instance; + private final List modelProcessors; + public static synchronized ModelProcessorFactory getInstance() { + if (instance == null) { + synchronized (ModelProcessorFactory.class) { + if (instance == null) { + instance = new ModelProcessorFactory(); + } + } + } + return instance; + } + + private ModelProcessorFactory() { + modelProcessors = List.of( + new SingleModelStrategy(), + new ListModelStrategy() + ); + } + + public void applyProcessor(CodegenProperty codegenProperty, CodegenModel codegenModel) { + + // Process + for (ModelProcessor modelProcessor : modelProcessors) { + if (modelProcessor.shouldProcess(codegenProperty, codegenModel)) { + modelProcessor.process(codegenProperty, codegenModel); + return; + } + } + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/model/SingleModelStrategy.java b/src/main/java/com/twilio/oai/java/processor/model/SingleModelStrategy.java new file mode 100644 index 000000000..f64526599 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/model/SingleModelStrategy.java @@ -0,0 +1,57 @@ +package com.twilio.oai.java.processor.model; + + +import com.twilio.oai.common.StringUtils; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheModel; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenProperty; + +import static com.twilio.oai.common.ApplicationConstants.DOT; +import static com.twilio.oai.common.ApplicationConstants.X_DATATYPE; +import static com.twilio.oai.common.ApplicationConstants.X_MODEL_TYPE; +import static com.twilio.oai.common.ApplicationConstants.X_VARIABLE_NAME; +import static com.twilio.oai.common.EnumConstants.ModelType; +public class SingleModelStrategy implements ModelProcessor { + ModelType type = ModelType.SINGLE; + + @Override + public boolean shouldProcess(CodegenProperty codegenProperty, CodegenModel codegenModel) { + if (!codegenProperty.isContainer) return true; + return false; + } + + @Override + public void process(CodegenProperty codegenProperty, CodegenModel codegenModel) { + if (codegenProperty.isContainer) return; + type(codegenProperty); + variableName(codegenProperty); + dataType(codegenProperty); + cacheModelClass(codegenProperty, codegenModel); + } + + public ModelType getType() { + return type; + } + + private void type(final CodegenProperty codegenProperty) { + codegenProperty.vendorExtensions.put(X_MODEL_TYPE, type); + } + + private void variableName(CodegenProperty codegenProperty) { + // This will be used in CRUDF(creator, reader etc) classes. + codegenProperty.vendorExtensions.put(X_VARIABLE_NAME, StringUtils.toCamelCase(codegenProperty.baseName)); + } + // basetype + private void dataType(CodegenProperty codegenProperty) { + //TODO: Need to identify whether the property is defined using ref or directly defined property + codegenProperty.vendorExtensions.put(X_DATATYPE, ResourceCacheContext.get().getResourceName() + DOT + codegenProperty.dataType); + } + + private void cacheModelClass(CodegenProperty codegenProperty, CodegenModel codegenModel) { + MustacheModel mustacheModel = new MustacheModel(codegenProperty, codegenModel); + ResourceCacheContext.get().addToModelClasses(mustacheModel); + } + + +} diff --git a/src/main/java/com/twilio/oai/java/processor/model/parameter/ModelProcessor.java b/src/main/java/com/twilio/oai/java/processor/model/parameter/ModelProcessor.java new file mode 100644 index 000000000..b0ab5cbac --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/model/parameter/ModelProcessor.java @@ -0,0 +1,9 @@ +package com.twilio.oai.java.processor.model.parameter; + +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenParameter; + +public interface ModelProcessor { + boolean shouldProcess(CodegenParameter codegenParameter, CodegenModel codegenModel); + void process(CodegenParameter codegenParameter, CodegenModel codegenModel); +} diff --git a/src/main/java/com/twilio/oai/java/processor/model/parameter/ParamModelProcessorManager.java b/src/main/java/com/twilio/oai/java/processor/model/parameter/ParamModelProcessorManager.java new file mode 100644 index 000000000..071477e04 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/model/parameter/ParamModelProcessorManager.java @@ -0,0 +1,40 @@ +package com.twilio.oai.java.processor.model.parameter; + + +import com.twilio.oai.java.processor.model.ModelProcessorFactory; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenParameter; + +import java.util.List; + +public class ParamModelProcessorManager { + private static ParamModelProcessorManager instance; + private final List modelProcessors; + public static synchronized ParamModelProcessorManager getInstance() { + if (instance == null) { + synchronized (ModelProcessorFactory.class) { + if (instance == null) { + instance = new ParamModelProcessorManager(); + } + } + } + return instance; + } + + private ParamModelProcessorManager() { + modelProcessors = List.of( + new SingleModelStrategy() + ); + } + + public void applyProcessor(CodegenParameter codegenParameter, CodegenModel codegenModel) { + + // Process + for (ModelProcessor modelProcessor : modelProcessors) { + if (modelProcessor.shouldProcess(codegenParameter, codegenModel)) { + modelProcessor.process(codegenParameter, codegenModel); + return; + } + } + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/model/parameter/SingleModelStrategy.java b/src/main/java/com/twilio/oai/java/processor/model/parameter/SingleModelStrategy.java new file mode 100644 index 000000000..3f5aa0737 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/model/parameter/SingleModelStrategy.java @@ -0,0 +1,56 @@ +package com.twilio.oai.java.processor.model.parameter; + +import com.twilio.oai.common.EnumConstants; +import com.twilio.oai.common.StringUtils; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.nestedmodels.MustacheModel; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenParameter; + +import static com.twilio.oai.common.ApplicationConstants.DOT; +import static com.twilio.oai.common.ApplicationConstants.X_MODEL_TYPE; +import static com.twilio.oai.common.ApplicationConstants.X_VARIABLE_NAME; + +public class SingleModelStrategy implements ModelProcessor { + EnumConstants.ModelType type = EnumConstants.ModelType.SINGLE; + + @Override + public boolean shouldProcess(CodegenParameter codegenParameter, CodegenModel codegenModel) { + if (!codegenParameter.isContainer) return true; + return false; + } + + @Override + public void process(CodegenParameter codegenParameter, CodegenModel codegenModel) { + if (codegenParameter.isContainer) return; + type(codegenParameter); + variableName(codegenParameter); + dataType(codegenParameter); + cacheModelClass(codegenParameter, codegenModel); + } + + public EnumConstants.ModelType getType() { + return type; + } + + private void type(final CodegenParameter codegenParameter) { + codegenParameter.vendorExtensions.put(X_MODEL_TYPE, type); + } + + private void variableName(CodegenParameter codegenParameter) { + // This will be used in CRUDF(creator, reader etc) classes. + codegenParameter.vendorExtensions.put(X_VARIABLE_NAME, StringUtils.toCamelCase(codegenParameter.baseName)); + } + // basetype + private void dataType(CodegenParameter codegenParameter) { + //TODO: Need to identify whether the property is defined using ref or directly defined property + //codegenParameter.vendorExtensions.put(X_DATATYPE, ResourceCacheContext.get().getResourceName() + DOT + codegenParameter.dataType); + codegenParameter.dataType = ResourceCacheContext.get().getResourceName() + DOT + codegenParameter.dataType; + } + + private void cacheModelClass(CodegenParameter codegenParameter, CodegenModel codegenModel) { + MustacheModel mustacheModel = new MustacheModel(codegenParameter, codegenModel); + ResourceCacheContext.get().addToModelClasses(mustacheModel); + } + +} diff --git a/src/main/java/com/twilio/oai/java/processor/parameter/ParameterProcessor.java b/src/main/java/com/twilio/oai/java/processor/parameter/ParameterProcessor.java new file mode 100644 index 000000000..9072f6649 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/parameter/ParameterProcessor.java @@ -0,0 +1,51 @@ +package com.twilio.oai.java.processor.parameter; + +import com.twilio.oai.java.processor.enums.EnumProcessorFactory; +import org.apache.commons.lang3.StringUtils; +import org.openapitools.codegen.CodegenOperation; + +/* + * This class includes processing of path, query, header and required parameters. + */ +public class ParameterProcessor { + + public static ParameterProcessor instance; + EnumProcessorFactory enumProcessorFactory; + private ParameterProcessor () { + this.enumProcessorFactory = EnumProcessorFactory.getInstance(); + } + + public static synchronized ParameterProcessor getInstance() { + if (instance == null) { + instance = new ParameterProcessor(); + } + return instance; + } + + public void process(final CodegenOperation codegenOperation) { + codegenOperation.pathParams.forEach(param -> { + String capitalized = StringUtils.capitalize(param.paramName); + param.paramName = "path" + capitalized; + }); + + codegenOperation.allParams.stream().filter(param -> param.isPathParam).forEach(param -> { + String capitalized = StringUtils.capitalize(param.paramName); + param.paramName = "path" + capitalized; + }); + + codegenOperation.requiredParams.stream().filter(param -> param.isPathParam).forEach(param -> { + String capitalized = StringUtils.capitalize(param.paramName); + param.paramName = "path" + capitalized; + }); + + codegenOperation.queryParams.forEach(param -> enumProcessorFactory.applyProcessor(param)); + codegenOperation.pathParams.forEach(param -> enumProcessorFactory.applyProcessor(param)); + codegenOperation.headerParams.forEach(param -> enumProcessorFactory.applyProcessor(param)); + codegenOperation.requiredParams.forEach(param -> enumProcessorFactory.applyProcessor(param)); + + // Required for setter methods and promotion method generation + codegenOperation.allParams.forEach(param -> enumProcessorFactory.applyProcessor(param)); + + //codegenOperation.allParams.forEach(param -> enumProcessorFactory.applyProcessor(param)); + } +} \ No newline at end of file diff --git a/src/main/java/com/twilio/oai/java/processor/requestbody/JsonRequestProcessor.java b/src/main/java/com/twilio/oai/java/processor/requestbody/JsonRequestProcessor.java new file mode 100644 index 000000000..5015d58a0 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/requestbody/JsonRequestProcessor.java @@ -0,0 +1,107 @@ +package com.twilio.oai.java.processor.requestbody; + +import com.twilio.oai.LoggerUtil; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenParameter; +import org.openapitools.codegen.CodegenProperty; + +import java.util.List; + +import static com.twilio.oai.common.ApplicationConstants.X_REQUEST_CONTENT_TYPE; +import static com.twilio.oai.java.constants.MustacheConstants.X_REQUEST_LANGUAGE_CONTENT_TYPE_CONSTANT; + +public class JsonRequestProcessor implements RequestBodyProcessor { + final RecursiveModelProcessor recursiveModelProcessor = new RecursiveModelProcessor(); + public JsonRequestProcessor() { + // Constructor can be used for initialization if needed + } + + @Override + public boolean shouldProcess(final CodegenOperation codegenOperation) { + // TODO + if (codegenOperation.bodyParams != null && !codegenOperation.bodyParams.isEmpty()) return true; + return false; + } + + /* + Note: + In json request body parameter could appear as list of codegenProperty or codegenParameter + */ + @Override + public void process(CodegenOperation codegenOperation) { + codegenOperation.vendorExtensions.put(X_REQUEST_CONTENT_TYPE, getContentType()); + codegenOperation.vendorExtensions.put(X_REQUEST_CONTENT_TYPE, getContentType()); + codegenOperation.vendorExtensions.put(X_REQUEST_LANGUAGE_CONTENT_TYPE_CONSTANT, "JSON"); + if (!codegenOperation.getHasBodyParam()) return; + List bodyParams = codegenOperation.bodyParams; + if (bodyParams.size() > 1) { + LoggerUtil.logSevere(this.getClass().getName(), "Multiple request bodies found " + codegenOperation.operationId); + } + +// if (codegenOperation.bodyParams != null && !codegenOperation.bodyParams.isEmpty() && codegenOperation.bodyParams.get(0).isOneOf) { +// processOneOf(codegenOperation); +// return; +// } + + if (bodyParams.get(0).vars != null && !bodyParams.get(0).vars.isEmpty()) { + processProperty(codegenOperation); + } else { + processOneOf(codegenOperation); + } + } + + public void processOneOf(CodegenOperation codegenOperation) { + System.out.println(codegenOperation.bodyParams); + CodegenParameter codegenParameter = codegenOperation.bodyParams.get(0); + if (codegenParameter.getContent() != null && codegenParameter.getContent().get("application/json") != null) { + CodegenProperty codegenProperty = codegenParameter.getContent().get("application/json").getSchema(); + if (codegenProperty != null) { + recursiveModelProcessor.process(codegenProperty); + } + } + } + + @Override + public String getContentType() { + return "application/json"; + } + + + /* + If you see in below example, there is no property defined. + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Cat' + + Cat: + allOf: + - type: object + properties: + account_sid: + type: string + - oneOf: + - $ref: '#/components/schemas/One' + - $ref: '#/components/schemas/Two' + */ + // Process list: codegenOperation.bodyParams + private void processParameter(CodegenOperation codegenOperation) { + if (codegenOperation.bodyParams.isEmpty()) return; + // Request Body has oneOf and its instance variables will be present as CodegenParameter + codegenOperation.bodyParams.stream().forEach(codegenParameter -> recursiveModelProcessor.process(codegenParameter)); + // Used in constructor generation. + codegenOperation.requiredParams.stream().forEach(codegenParameter -> recursiveModelProcessor.process(codegenParameter)); + + + + } + + // List of instance variable can be processed by list: codegenOperation.bodyParam.vars + private void processProperty(CodegenOperation codegenOperation) { + if (codegenOperation.bodyParam != null && codegenOperation.bodyParam.vars.isEmpty()) return; + codegenOperation.bodyParams.stream().forEach(codegenParameter -> recursiveModelProcessor.process(codegenParameter)); + //codegenOperation.bodyParam.vars.stream().forEach(property -> recursiveModelProcessor.processModelRecursively(property)); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/requestbody/RecursiveModelProcessor.java b/src/main/java/com/twilio/oai/java/processor/requestbody/RecursiveModelProcessor.java new file mode 100644 index 000000000..f8b0fc989 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/requestbody/RecursiveModelProcessor.java @@ -0,0 +1,110 @@ +package com.twilio.oai.java.processor.requestbody; + +import com.twilio.oai.common.Utility; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.format.Deserializer; +import com.twilio.oai.java.processor.enums.EnumProcessorFactory; +import com.twilio.oai.java.processor.model.ModelProcessorFactory; +import com.twilio.oai.java.processor.model.parameter.ParamModelProcessorManager; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenParameter; +import org.openapitools.codegen.CodegenProperty; + +public class RecursiveModelProcessor { + EnumProcessorFactory enumProcessorFactory = EnumProcessorFactory.getInstance(); + ModelProcessorFactory modelProcessorFactory = ModelProcessorFactory.getInstance(); + ParamModelProcessorManager paramModelProcessorManager = ParamModelProcessorManager.getInstance(); + + public void processBody(CodegenOperation codegenOperation) { + // codegenOperation.bodyParam.vars.get(3).ref: #/components/schemas/types + + codegenOperation.bodyParam.vars.forEach(property -> processModelRecursively(property)); + + } + + public void process(CodegenProperty codegenProperty) { + processModelRecursively(codegenProperty); + } + + public void process(CodegenParameter codegenParameter) { + CodegenModel codegenModel = ResourceCacheContext.get().getAllModelsByDefaultGenerator().stream() + .filter(model -> model.classname.equalsIgnoreCase(codegenParameter.dataType)) + .findFirst() + .orElse(null); + if (codegenModel == null) return; + + paramModelProcessorManager.applyProcessor(codegenParameter, codegenModel); + + if (codegenModel.vars != null && !codegenModel.vars.isEmpty()) { + for (CodegenProperty modelProperty : codegenModel.vars) { + processModelRecursively(modelProperty); + } + } + } + + // Only in case of oneOf or allOf + public void processModelRecursively(CodegenParameter codegenParameter, CodegenModel codegenModel) { + + + paramModelProcessorManager.applyProcessor(codegenParameter, codegenModel); + + if (codegenModel.vars != null && !codegenModel.vars.isEmpty()) { + for (CodegenProperty modelProperty : codegenModel.vars) { + processModelRecursively(modelProperty); + } + } + } + + public void processResponse(final CodegenOperation codegenOperation) { + // Make sure to filter pagination models. + return ; + } + + + // DFS based recursive logic + public void processModelRecursively(final CodegenProperty codegenProperty) { + CodegenModel codegenModel = Utility.getModelFromOpenApiType(codegenProperty); + /* + This code block has access to all the codegenProperty for a nested model. + Add your logic to process the property. + ------------------ Start ------------------ + */ + + if (isEnum(codegenProperty)) { + // Logic 1: Enum Logic + processEnum(codegenProperty); + return; + } + if (codegenModel == null) { + // For non ref models, CodegenModel will be present. Non model nor enum. + // Logic 3: Normal variable logic + Deserializer.addDeserializer(codegenProperty); + + return; + } + // Logic 2: nested model logic + modelProcessorFactory.applyProcessor(codegenProperty, codegenModel); + + /* + ------------------ End ------------------ + */ + + + + // A Model has been identified, look for child models + if (codegenModel.vars != null && !codegenModel.vars.isEmpty()) { + for (CodegenProperty modelProperty : codegenModel.vars) { + processModelRecursively(modelProperty); + } + } + } + + private boolean isEnum(CodegenProperty codegenProperty) { + return enumProcessorFactory.isEnum(codegenProperty); + } + + private void processEnum(CodegenProperty codegenProperty) { + enumProcessorFactory.applyProcessor(codegenProperty); + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/requestbody/RequestBodyProcessor.java b/src/main/java/com/twilio/oai/java/processor/requestbody/RequestBodyProcessor.java new file mode 100644 index 000000000..9f8377821 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/requestbody/RequestBodyProcessor.java @@ -0,0 +1,9 @@ +package com.twilio.oai.java.processor.requestbody; + +import org.openapitools.codegen.CodegenOperation; + +public interface RequestBodyProcessor { + void process(CodegenOperation codegenOperation); + String getContentType(); + boolean shouldProcess(CodegenOperation codegenOperation); +} diff --git a/src/main/java/com/twilio/oai/java/processor/requestbody/RequestBodyProcessorFactory.java b/src/main/java/com/twilio/oai/java/processor/requestbody/RequestBodyProcessorFactory.java new file mode 100644 index 000000000..7bc940919 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/requestbody/RequestBodyProcessorFactory.java @@ -0,0 +1,37 @@ +package com.twilio.oai.java.processor.requestbody; + +import org.openapitools.codegen.CodegenOperation; + +import java.util.List; + +public class RequestBodyProcessorFactory { + private static RequestBodyProcessorFactory instance; + private final List requestBodyProcessors; + + private RequestBodyProcessorFactory() { + this.requestBodyProcessors = List.of( + new UrlEncodedProcessor(), + new JsonRequestProcessor() + ); + } + + public static synchronized RequestBodyProcessorFactory getInstance() { + if (instance == null) { + synchronized (RequestBodyProcessorFactory.class) { + if (instance == null) { + instance = new RequestBodyProcessorFactory(); + } + } + } + return instance; + } + + public void process(final CodegenOperation codegenOperation) { + for (RequestBodyProcessor requestBodyProcessor : requestBodyProcessors) { + if (requestBodyProcessor.shouldProcess(codegenOperation)) { + requestBodyProcessor.process(codegenOperation); + return; // Exit after the first processor that applies + } + } + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/requestbody/UrlEncodedProcessor.java b/src/main/java/com/twilio/oai/java/processor/requestbody/UrlEncodedProcessor.java new file mode 100644 index 000000000..3498ab0cb --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/requestbody/UrlEncodedProcessor.java @@ -0,0 +1,31 @@ +package com.twilio.oai.java.processor.requestbody; + +import com.twilio.oai.java.processor.enums.EnumProcessorFactory; +import org.openapitools.codegen.CodegenOperation; + +import static com.twilio.oai.common.ApplicationConstants.X_REQUEST_CONTENT_TYPE; +import static com.twilio.oai.java.constants.MustacheConstants.X_REQUEST_LANGUAGE_CONTENT_TYPE_CONSTANT; + +public class UrlEncodedProcessor implements RequestBodyProcessor { + final EnumProcessorFactory enumFactory = EnumProcessorFactory.getInstance(); + @Override + public void process(CodegenOperation codegenOperation) { + codegenOperation.vendorExtensions.put(X_REQUEST_CONTENT_TYPE, getContentType()); + codegenOperation.vendorExtensions.put(X_REQUEST_LANGUAGE_CONTENT_TYPE_CONSTANT, "FORM_URLENCODED"); + codegenOperation.formParams.forEach(parameter -> { + enumFactory.applyProcessor(parameter); + //Promoter.addPromoter(parameter); + }); + } + + @Override + public String getContentType() { + return "application/x-www-form-urlencoded"; + } + + @Override + public boolean shouldProcess(final CodegenOperation codegenOperation) { + if (codegenOperation.formParams != null && !codegenOperation.formParams.isEmpty()) return true; + return false; + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/responsebody/JsonResponseProcessor.java b/src/main/java/com/twilio/oai/java/processor/responsebody/JsonResponseProcessor.java new file mode 100644 index 000000000..9ab982846 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/responsebody/JsonResponseProcessor.java @@ -0,0 +1,103 @@ +package com.twilio.oai.java.processor.responsebody; + +import com.twilio.oai.common.Utility; +import com.twilio.oai.java.cache.ResourceCacheContext; +import com.twilio.oai.java.format.Deserializer; +import com.twilio.oai.java.processor.enums.EnumProcessorFactory; +import com.twilio.oai.java.processor.requestbody.RecursiveModelProcessor; +import org.openapitools.codegen.CodegenMediaType; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenProperty; +import org.openapitools.codegen.CodegenResponse; + +import java.util.Map; + +public class JsonResponseProcessor implements ResponseProcessor { + EnumProcessorFactory enumProcessorFactory = EnumProcessorFactory.getInstance(); + RecursiveModelProcessor recursiveModelProcessor = new RecursiveModelProcessor(); + @Override + public void process(final CodegenOperation codegenOperation) { + System.out.println(codegenOperation.operationId); + + // delete operation does not have response body + if (codegenOperation.operationId.toLowerCase().startsWith("delete")) return; + + CodegenModel codegenModel = getModel(codegenOperation); + if (codegenModel == null) return; + CodegenModel responseModel = codegenModel; + + if (codegenOperation.operationId.toLowerCase().startsWith("list")) { + responseModel = getModelFromListOperation(codegenModel); + if (responseModel == null) return; + } + + responseModel.vars.forEach(codegenProperty -> { + enumProcessorFactory.applyProcessor(codegenProperty); + Deserializer.addDeserializer(codegenProperty); + }); + responseModel.vars.stream().forEach(property -> recursiveModelProcessor.process(property)); + + // Adding responseModel vars to cache + responseModel.vars.forEach(ResourceCacheContext.get().getResponse()::add); + } + + //model.vars.get(0).items.ref to get actual output + private CodegenModel getModelFromListOperation(CodegenModel codegenModel) { + System.out.println(codegenModel); + for (CodegenProperty codegenProperty: codegenModel.vars) { + // We expect list operation to have pagination. + if (codegenProperty.isContainer) { + String ref = codegenProperty.items.getRef(); + CodegenModel responseModel = Utility.getModelFromRef(ref); + return responseModel; + } + } + return null; + } + + public boolean shouldProcess(final CodegenOperation codegenOperation) { + System.out.println(codegenOperation.operationId); + if (codegenOperation.produces != null && !codegenOperation.produces.isEmpty()) { + for (Map contentType : codegenOperation.produces) { + if (getContentType().equals(contentType.get("mediaType")) || "application/scim+json".equals(contentType.get("mediaType"))) { + return true; + } + } + } + return false; + } + + @Override + public String getContentType() { + return "application/json"; + } + + // if $ref, model name: codegenOperation.responses.get(0).content.get("application/json").schema.getRef() + // output: #/components/schemas/api.v2010.account.message + private CodegenModel getModel(final CodegenOperation codegenOperation) { + if (codegenOperation.responses != null && !codegenOperation.responses.isEmpty()) { + for (CodegenResponse codegenResponse: codegenOperation.responses) { + if (codegenResponse.is2xx || codegenResponse.is3xx) { + if (codegenResponse == null || codegenResponse.getContent() == null) return null; + CodegenMediaType codegenMediaType = codegenResponse.getContent().get(getContentType()); + if (codegenMediaType == null) { + codegenMediaType = codegenResponse.getContent().get("application/scim+json"); + if (codegenMediaType == null) return null; + } + + if (codegenMediaType.getSchema().isContainer) { + // It covers special case in which response is list + // TODO: Handle in future. + } + String ref = codegenMediaType.getSchema().getRef(); + if (ref == null) return null; + CodegenModel model = Utility.getModelFromRef(ref); + return model; + + } + } + } + return null; + } +} diff --git a/src/main/java/com/twilio/oai/java/processor/responsebody/ResponseProcessor.java b/src/main/java/com/twilio/oai/java/processor/responsebody/ResponseProcessor.java new file mode 100644 index 000000000..32422a7a6 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/responsebody/ResponseProcessor.java @@ -0,0 +1,9 @@ +package com.twilio.oai.java.processor.responsebody; + +import org.openapitools.codegen.CodegenOperation; + +public interface ResponseProcessor { + void process(CodegenOperation codegenOperation); + String getContentType(); + boolean shouldProcess(CodegenOperation codegenOperation); +} diff --git a/src/main/java/com/twilio/oai/java/processor/responsebody/ResponseProcessorFactory.java b/src/main/java/com/twilio/oai/java/processor/responsebody/ResponseProcessorFactory.java new file mode 100644 index 000000000..d67553649 --- /dev/null +++ b/src/main/java/com/twilio/oai/java/processor/responsebody/ResponseProcessorFactory.java @@ -0,0 +1,26 @@ +package com.twilio.oai.java.processor.responsebody; + +import org.openapitools.codegen.CodegenOperation; + +import java.util.ArrayList; +import java.util.List; + +public class ResponseProcessorFactory { + private final List processors = new ArrayList<>(); + private static final ResponseProcessorFactory INSTANCE = new ResponseProcessorFactory(); + + private ResponseProcessorFactory() { + processors.add(new JsonResponseProcessor()); + } + + public static ResponseProcessorFactory getInstance() { + return INSTANCE; + } + public void process(final CodegenOperation codegenOperation) { + for (ResponseProcessor responseProcessor : processors) { + if (responseProcessor.shouldProcess(codegenOperation)) { + responseProcessor.process(codegenOperation); + } + } + } +} diff --git a/src/main/java/com/twilio/oai/resolver/java/JavaParameterResolver.java b/src/main/java/com/twilio/oai/resolver/java/JavaParameterResolver.java index a384b2c1b..eb7c88e3a 100644 --- a/src/main/java/com/twilio/oai/resolver/java/JavaParameterResolver.java +++ b/src/main/java/com/twilio/oai/resolver/java/JavaParameterResolver.java @@ -66,7 +66,7 @@ public void resolveProperties(CodegenParameter parameter, ApiResourceBuilder api parameter.allowableValues = null; }); parameter.paramName = StringHelper.toFirstLetterLower(parameter.paramName); - if (apiResourceBuilder.getToggleMap().getOrDefault(EnumConstants.Generator.TWILIO_JAVA.getValue(), Boolean.FALSE) ) { + if (apiResourceBuilder.getToggleMap().getOrDefault(EnumConstants.Generator.TWILIO_JAVA_LEGACY.getValue(), Boolean.FALSE) ) { resolveIngressModel(parameter, apiResourceBuilder); } } diff --git a/src/main/java/com/twilio/oai/resolver/java/JavaPropertyResolver.java b/src/main/java/com/twilio/oai/resolver/java/JavaPropertyResolver.java index 09fe2a11c..8f86c1b45 100644 --- a/src/main/java/com/twilio/oai/resolver/java/JavaPropertyResolver.java +++ b/src/main/java/com/twilio/oai/resolver/java/JavaPropertyResolver.java @@ -45,7 +45,7 @@ public void resolveProperties(CodegenProperty property, ApiResourceBuilder apiR (key, value) -> property.getVendorExtensions().merge(key, value, (oldValue, newValue) -> newValue) ); - if (apiResourceBuilder.getToggleMap().getOrDefault(EnumConstants.Generator.TWILIO_JAVA.getValue(), Boolean.FALSE) ) { + if (apiResourceBuilder.getToggleMap().getOrDefault(EnumConstants.Generator.TWILIO_JAVA_LEGACY.getValue(), Boolean.FALSE) ) { resolveIngressModel(property, apiResourceBuilder); } } diff --git a/src/main/java/com/twilio/oai/resolver/node/NodePropertyResolver.java b/src/main/java/com/twilio/oai/resolver/node/NodePropertyResolver.java index c613f383a..c52369518 100644 --- a/src/main/java/com/twilio/oai/resolver/node/NodePropertyResolver.java +++ b/src/main/java/com/twilio/oai/resolver/node/NodePropertyResolver.java @@ -41,7 +41,7 @@ public void resolveProperties(CodegenProperty property, ApiResourceBuilder apiR (key, value) -> property.getVendorExtensions().merge(key, value, (oldValue, newValue) -> newValue) ); - if (apiResourceBuilder.getToggleMap().getOrDefault(EnumConstants.Generator.TWILIO_JAVA.getValue(), Boolean.FALSE) ) { + if (apiResourceBuilder.getToggleMap().getOrDefault(EnumConstants.Generator.TWILIO_JAVA_LEGACY.getValue(), Boolean.FALSE) ) { resolveIngressModel(property, apiResourceBuilder); } } diff --git a/src/main/java/com/twilio/oai/templating/TwilioHandlebarsEngineAdapter.java b/src/main/java/com/twilio/oai/templating/TwilioHandlebarsEngineAdapter.java index 8badacd90..ee6441103 100644 --- a/src/main/java/com/twilio/oai/templating/TwilioHandlebarsEngineAdapter.java +++ b/src/main/java/com/twilio/oai/templating/TwilioHandlebarsEngineAdapter.java @@ -41,8 +41,8 @@ public TemplateSource sourceAt(final String location) { .newBuilder(bundle) .resolver(MapValueResolver.INSTANCE, JavaBeanValueResolver.INSTANCE, - FieldValueResolver.INSTANCE, - MethodValueResolver.INSTANCE) + MethodValueResolver.INSTANCE, + FieldValueResolver.INSTANCE) .build(); final Handlebars handlebars = new Handlebars(loader); diff --git a/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig index e022a1df2..096960d4a 100644 --- a/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig +++ b/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig @@ -1,8 +1,9 @@ com.twilio.oai.TwilioCsharpGenerator com.twilio.oai.TwilioGoGenerator com.twilio.oai.TwilioJavaGenerator +com.twilio.oai.TwilioJavaGeneratorModern com.twilio.oai.TwilioNodeGenerator com.twilio.oai.TwilioPhpGenerator -com.twilio.oai.TwilioPythonGenerator com.twilio.oai.TwilioRubyGenerator com.twilio.oai.TwilioTerraformGenerator +com.twilio.oai.TwilioPythonGenerator diff --git a/src/main/resources/config/toggles.json b/src/main/resources/config/toggles.json index a2aed71bf..012819918 100644 --- a/src/main/resources/config/toggles.json +++ b/src/main/resources/config/toggles.json @@ -1,6 +1,6 @@ { "json_ingress": { - "twilio-java": true, + "twilio-java-legacy": true, "twilio-node": true, "twilio-python": true, "twilio-ruby": true, diff --git a/src/main/resources/twilio-csharp/options/CreateOptions.mustache b/src/main/resources/twilio-csharp/options/CreateOptions.mustache index eaf5745be..953df3bb4 100644 --- a/src/main/resources/twilio-csharp/options/CreateOptions.mustache +++ b/src/main/resources/twilio-csharp/options/CreateOptions.mustache @@ -19,11 +19,11 @@ } {{/vendorExtensions.x-required-param-exists}} - {{^vendorExtensions.x-is-json}} + {{^bodyParams.0}} {{>options/GetParams}} - {{/vendorExtensions.x-is-json}} - {{#vendorExtensions.x-is-json}} + {{/bodyParams.0}} + {{#bodyParams.0}} {{>options/GetBody}} - {{/vendorExtensions.x-is-json}} + {{/bodyParams.0}} {{>options/HeaderParams}} - } \ No newline at end of file + } diff --git a/src/main/resources/twilio-csharp/options/DeleteOptions.mustache b/src/main/resources/twilio-csharp/options/DeleteOptions.mustache index 81a89826d..22e07f4d3 100644 --- a/src/main/resources/twilio-csharp/options/DeleteOptions.mustache +++ b/src/main/resources/twilio-csharp/options/DeleteOptions.mustache @@ -19,12 +19,7 @@ } {{/vendorExtensions.x-required-param-exists}} - {{^vendorExtensions.x-is-json}} {{>options/GetParams}} - {{/vendorExtensions.x-is-json}} - {{#vendorExtensions.x-is-json}} - {{>options/GetBody}} - {{/vendorExtensions.x-is-json}} {{>options/HeaderParams}} } diff --git a/src/main/resources/twilio-csharp/options/FetchOptions.mustache b/src/main/resources/twilio-csharp/options/FetchOptions.mustache index 3f37646c3..7b9034ef4 100644 --- a/src/main/resources/twilio-csharp/options/FetchOptions.mustache +++ b/src/main/resources/twilio-csharp/options/FetchOptions.mustache @@ -19,12 +19,7 @@ } {{/vendorExtensions.x-required-param-exists}} - {{^vendorExtensions.x-is-json}} {{>options/GetParams}} - {{/vendorExtensions.x-is-json}} - {{#vendorExtensions.x-is-json}} - {{>options/GetBody}} - {{/vendorExtensions.x-is-json}} {{>options/HeaderParams}} } diff --git a/src/main/resources/twilio-csharp/options/GetBody.mustache b/src/main/resources/twilio-csharp/options/GetBody.mustache index 070e3b328..6b00d461e 100644 --- a/src/main/resources/twilio-csharp/options/GetBody.mustache +++ b/src/main/resources/twilio-csharp/options/GetBody.mustache @@ -4,7 +4,6 @@ { string body = ""; - {{#vendorExtensions.x-getparams}} {{^isArray}} {{^vendorExtensions.x-parameter-map}} if ({{paramName}} != null) @@ -13,6 +12,5 @@ } {{/vendorExtensions.x-parameter-map}} {{/isArray}} - {{/vendorExtensions.x-getparams}} return body; - } \ No newline at end of file + } diff --git a/src/main/resources/twilio-csharp/options/ReadOptions.mustache b/src/main/resources/twilio-csharp/options/ReadOptions.mustache index e77a9f95e..06f74cf8b 100644 --- a/src/main/resources/twilio-csharp/options/ReadOptions.mustache +++ b/src/main/resources/twilio-csharp/options/ReadOptions.mustache @@ -19,11 +19,6 @@ } {{/vendorExtensions.x-required-param-exists}} - {{^vendorExtensions.x-is-json}} {{>options/GetParams}} - {{/vendorExtensions.x-is-json}} - {{#vendorExtensions.x-is-json}} - {{>options/GetBody}} - {{/vendorExtensions.x-is-json}} {{>options/HeaderParams}} } diff --git a/src/main/resources/twilio-csharp/options/UpdateOptions.mustache b/src/main/resources/twilio-csharp/options/UpdateOptions.mustache index 237d43f5e..a2060d929 100644 --- a/src/main/resources/twilio-csharp/options/UpdateOptions.mustache +++ b/src/main/resources/twilio-csharp/options/UpdateOptions.mustache @@ -19,12 +19,12 @@ } {{/vendorExtensions.x-required-param-exists}} - {{^vendorExtensions.x-is-json}} + {{^bodyParams.0}} {{>options/GetParams}} - {{/vendorExtensions.x-is-json}} - {{#vendorExtensions.x-is-json}} + {{/bodyParams.0}} + {{#bodyParams.0}} {{>options/GetBody}} - {{/vendorExtensions.x-is-json}} + {{/bodyParams.0}} {{>options/HeaderParams}} } diff --git a/src/main/resources/twilio-csharp/resource/CreateResource.mustache b/src/main/resources/twilio-csharp/resource/CreateResource.mustache index 7348e8e04..4b6fb8618 100644 --- a/src/main/resources/twilio-csharp/resource/CreateResource.mustache +++ b/src/main/resources/twilio-csharp/resource/CreateResource.mustache @@ -6,13 +6,13 @@ {{vendorExtensions.x-http-method}}, Rest.Domain.{{domainPackage}}, path, - {{^vendorExtensions.x-is-json}} + {{^bodyParams.0}} contentType: EnumConstants.ContentTypeEnum.FORM_URLENCODED, - postParams: options.GetParams(),{{/vendorExtensions.x-is-json}} - {{#vendorExtensions.x-is-json}} + postParams: options.GetParams(),{{/bodyParams.0}} + {{#bodyParams.0}} contentType: EnumConstants.ContentTypeEnum.JSON, body: options.GetBody(), - {{/vendorExtensions.x-is-json}} + {{/bodyParams.0}} headerParams: {{^vendorExtensions.hasOptionalHeaderParams}}null{{/vendorExtensions.hasOptionalHeaderParams}}{{#vendorExtensions.hasOptionalHeaderParams}}options.GetHeaderParams(){{/vendorExtensions.hasOptionalHeaderParams}} ); } @@ -61,4 +61,4 @@ var options = new Create{{apiName}}Options({{#requiredParams}}{{#lambda.camelcase}}{{paramName}}{{/lambda.camelcase}}{{^-last}}, {{/-last}}{{/requiredParams}}){ {{#vendorExtensions.x-request-body-param}}{{^required}} {{paramName}} = {{#lambda.camelcase}}{{paramName}}{{/lambda.camelcase}}{{^-last}},{{/-last}}{{/required}}{{/vendorExtensions.x-request-body-param}} }; return await CreateAsync(options, client); } - #endif \ No newline at end of file + #endif diff --git a/src/main/resources/twilio-csharp/resource/UpdateResource.mustache b/src/main/resources/twilio-csharp/resource/UpdateResource.mustache index 036ef5935..1584db2c0 100644 --- a/src/main/resources/twilio-csharp/resource/UpdateResource.mustache +++ b/src/main/resources/twilio-csharp/resource/UpdateResource.mustache @@ -6,13 +6,13 @@ {{vendorExtensions.x-http-method}}, Rest.Domain.{{domainPackage}}, path, - {{^vendorExtensions.x-is-json}} + {{^bodyParams.0}} contentType: EnumConstants.ContentTypeEnum.FORM_URLENCODED, - postParams: options.GetParams(),{{/vendorExtensions.x-is-json}} - {{#vendorExtensions.x-is-json}} + postParams: options.GetParams(),{{/bodyParams.0}} + {{#bodyParams.0}} contentType: EnumConstants.ContentTypeEnum.JSON, body: options.GetBody(), - {{/vendorExtensions.x-is-json}} + {{/bodyParams.0}} headerParams: {{^vendorExtensions.x-header-param-exists}}null{{/vendorExtensions.x-header-param-exists}}{{#vendorExtensions.x-header-param-exists}}options.GetHeaderParams(){{/vendorExtensions.x-header-param-exists}} ); } @@ -62,4 +62,4 @@ var options = new Update{{apiName}}Options({{#requiredParams}}{{#lambda.camelcase}}{{paramName}}{{/lambda.camelcase}}{{^-last}}, {{/-last}}{{/requiredParams}}){ {{#vendorExtensions.x-request-body-param}}{{^required}}{{paramName}} = {{#lambda.camelcase}}{{paramName}}{{/lambda.camelcase}}{{^-last}}, {{/-last}}{{/required}}{{/vendorExtensions.x-request-body-param}} }; return await UpdateAsync(options, client); } - #endif \ No newline at end of file + #endif diff --git a/src/main/resources/twilio-java-legacy/api.mustache b/src/main/resources/twilio-java-legacy/api.mustache new file mode 100644 index 000000000..deaa723ed --- /dev/null +++ b/src/main/resources/twilio-java-legacy/api.mustache @@ -0,0 +1,167 @@ +{{>licenseInfo}} +{{#resources}} +package com.twilio.rest.{{domainPackage}}.{{apiVersion}}{{namespaceSubPart}}; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.twilio.base{{authMethodPackage}}.Resource; +import com.twilio.converter.Converter; +import java.util.Currency; +import com.twilio.converter.DateConverter; +import com.twilio.converter.Promoter; +import com.twilio.converter.PrefixedCollapsibleMap; +import com.twilio.converter.CurrencyDeserializer; +import com.twilio.exception.ApiConnectionException; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import com.twilio.exception.ApiException; +import com.twilio.exception.RestException; +import com.twilio.http.HttpMethod; +import com.twilio.http.Request; +import com.twilio.http.Response; +import com.twilio.http.TwilioRestClient; +import com.twilio.rest.Domains; + +import lombok.ToString; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.time.ZonedDateTime; + +{{^fullJavaUtil}} +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +{{/fullJavaUtil}} + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import java.util.Map; +import java.time.LocalDate; +import java.math.BigDecimal; +import com.twilio.type.PhoneNumberCapabilities; +import com.twilio.type.FeedbackIssue; +import com.twilio.type.IceServer; +import com.twilio.type.InboundCallPrice; +import com.twilio.type.OutboundPrefixPriceWithOrigin; +import com.twilio.type.OutboundPrefixPrice; +import com.twilio.type.OutboundCallPriceWithOrigin; +import com.twilio.type.PhoneNumberPrice; +import com.twilio.type.InboundSmsPrice; +import com.twilio.type.OutboundSmsPrice; +import com.twilio.type.OutboundCallPrice; +import com.twilio.type.RecordingRule; +import com.twilio.type.SubscribeRule; + +@JsonIgnoreProperties(ignoreUnknown = true) +@ToString +public class {{apiName}} extends Resource { + private static final long serialVersionUID = {{serialVersionUID}}L; + + {{>models}} + {{#apiOperations}} + {{#vendorExtensions.x-is-create-operation}} + {{#vendorExtensions.x-signature-list}} + public static {{apiName}}Creator creator({{#.}}final {{{dataType}}} {{{paramName}}}{{^-last}}, {{/-last}}{{/.}}){ + return new {{apiName}}Creator({{#.}}{{{paramName}}}{{^-last}}, {{/-last}}{{/.}}); + } + {{/vendorExtensions.x-signature-list}} + + {{/vendorExtensions.x-is-create-operation}} + {{#vendorExtensions.x-is-fetch-operation}} + {{#vendorExtensions.x-signature-list}} + public static {{apiName}}Fetcher fetcher({{#.}}final {{{dataType}}} {{{paramName}}}{{^-last}}, {{/-last}}{{/.}}){ + return new {{apiName}}Fetcher({{#.}}{{{paramName}}}{{^-last}}, {{/-last}}{{/.}}); + } + {{/vendorExtensions.x-signature-list}} + + {{/vendorExtensions.x-is-fetch-operation}} + {{#vendorExtensions.x-is-delete-operation}} + {{#vendorExtensions.x-signature-list}} + public static {{apiName}}Deleter deleter({{#.}}final {{{dataType}}} {{{paramName}}}{{^-last}}, {{/-last}}{{/.}}){ + return new {{apiName}}Deleter({{#.}}{{{paramName}}}{{^-last}}, {{/-last}}{{/.}}); + } + {{/vendorExtensions.x-signature-list}} + + {{/vendorExtensions.x-is-delete-operation}} + {{#vendorExtensions.x-is-read-operation}} + {{#vendorExtensions.x-signature-list}} + public static {{apiName}}Reader reader({{#.}}final {{{dataType}}} {{{paramName}}}{{^-last}}, {{/-last}}{{/.}}){ + return new {{apiName}}Reader({{#.}}{{{paramName}}}{{^-last}}, {{/-last}}{{/.}}); + } + {{/vendorExtensions.x-signature-list}} + + {{/vendorExtensions.x-is-read-operation}} + {{#vendorExtensions.x-is-update-operation}} + {{#vendorExtensions.x-signature-list}} + public static {{apiName}}Updater updater({{#.}}final {{{dataType}}} {{{paramName}}}{{^-last}}, {{/-last}}{{/.}}){ + return new {{apiName}}Updater({{#.}}{{{paramName}}}{{^-last}}, {{/-last}}{{/.}}); + } + {{/vendorExtensions.x-signature-list}} + + {{/vendorExtensions.x-is-update-operation}} + {{/apiOperations}} + /** + * Converts a JSON String into a {{apiName}} object using the provided ObjectMapper. + * + * @param json Raw JSON String + * @param objectMapper Jackson ObjectMapper + * @return {{apiName}} object represented by the provided JSON + */ + public static {{apiName}} fromJson(final String json, final ObjectMapper objectMapper) { + // Convert all checked exceptions to Runtime + try { + return objectMapper.readValue(json, {{apiName}}.class); + } catch (final JsonMappingException | JsonParseException e) { + throw new ApiException(e.getMessage(), e); + } catch (final IOException e) { + throw new ApiConnectionException(e.getMessage(), e); + } + } + + /** + * Converts a JSON InputStream into a {{apiName}} object using the provided + * ObjectMapper. + * + * @param json Raw JSON InputStream + * @param objectMapper Jackson ObjectMapper + * @return {{apiName}} object represented by the provided JSON + */ + public static {{apiName}} fromJson(final InputStream json, final ObjectMapper objectMapper) { + // Convert all checked exceptions to Runtime + try { + return objectMapper.readValue(json, {{apiName}}.class); + } catch (final JsonMappingException | JsonParseException e) { + throw new ApiException(e.getMessage(), e); + } catch (final IOException e) { + throw new ApiConnectionException(e.getMessage(), e); + } + } + {{#hasNestedRequestBody}} + public static String toJson(Object object, ObjectMapper mapper) { + try { + return mapper.writeValueAsString(object); + } catch (final JsonMappingException e) { + throw new ApiException(e.getMessage(), e); + } catch (JsonProcessingException e) { + throw new ApiException(e.getMessage(), e); + } catch (final IOException e) { + throw new ApiConnectionException(e.getMessage(), e); + } + }{{/hasNestedRequestBody}} +{{>responseModel}} +{{>enums}} +} +{{/resources}} + diff --git a/src/main/resources/twilio-java-legacy/api_doc.mustache b/src/main/resources/twilio-java-legacy/api_doc.mustache new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/resources/twilio-java-legacy/api_test.mustache b/src/main/resources/twilio-java-legacy/api_test.mustache new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/resources/twilio-java-legacy/creator.mustache b/src/main/resources/twilio-java-legacy/creator.mustache new file mode 100644 index 000000000..1c19dac2e --- /dev/null +++ b/src/main/resources/twilio-java-legacy/creator.mustache @@ -0,0 +1,136 @@ +{{>licenseInfo}} +{{#resources}} +package com.twilio.rest.{{domainPackage}}.{{apiVersion}}{{namespaceSubPart}}; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.twilio.constant.EnumConstants; +import com.twilio.converter.Promoter; +import com.twilio.exception.ApiConnectionException; +import com.twilio.converter.PrefixedCollapsibleMap; +import com.twilio.converter.Converter; +import com.twilio.exception.ApiException; +import com.twilio.exception.RestException; +import com.twilio.http.HttpMethod; +import com.twilio.http.Response; +import com.twilio.rest.Domains; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; +import java.time.LocalDate; +import com.twilio.converter.Converter; +import java.time.ZonedDateTime; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.net.URI; +import java.time.format.DateTimeFormatter; +import com.twilio.converter.DateConverter; + +{{^fullJavaUtil}} +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +{{/fullJavaUtil}} + +import lombok.ToString; + +import java.net.URI; + +{{#apiOperations}} +{{#vendorExtensions.x-is-create-operation}} +import com.twilio.base{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.Creator; +import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request; +import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient; + +public class {{apiName}}Creator extends Creator<{{apiName}}>{ +{{#allParams}} + private {{{dataType}}} {{paramName}}; +{{/allParams}} + +{{#vendorExtensions.x-signature-list}} + public {{apiName}}Creator({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}) { + {{#.}} + this.{{paramName}} = {{paramName}}; + {{/.}} + } +{{/vendorExtensions.x-signature-list}} + +{{#vendorExtensions.x-non-path-params}} + public {{apiName}}Creator set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ + this.{{paramName}} = {{paramName}}; + return this; + } +{{#isArray}} + public {{apiName}}Creator set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); + } +{{/isArray}} +{{#vendorExtensions.x-promotions}} +{{#entrySet}} + + public {{apiName}}Creator set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{#lambda.titlecase}}{{key}}{{/lambda.titlecase}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{value}}); + } +{{/entrySet}} +{{/vendorExtensions.x-promotions}} +{{/vendorExtensions.x-non-path-params}} + + @Override + public {{apiName}} create(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client){ +{{>generate_uri}} + {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( + {{vendorExtensions.x-http-method}}, + Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), + path + ); + {{#queryParams.0}} + addQueryParams(request); + {{/queryParams.0}} + {{^vendorExtensions.x-is-json}} + request.setContentType(EnumConstants.ContentType.FORM_URLENCODED); + {{/vendorExtensions.x-is-json}} + {{#vendorExtensions.x-is-json}} + request.setContentType(EnumConstants.ContentType.JSON); + {{/vendorExtensions.x-is-json}} + {{#formParams.0}} + addPostParams(request); + {{/formParams.0}} + {{#bodyParams.0}} + addPostParams(request, client); + {{/bodyParams.0}} + {{#headerParams.0}} + addHeaderParams(request); + {{/headerParams.0}} + Response response = client.request(request); + if (response == null) { + throw new ApiConnectionException("{{apiName}} creation failed: Unable to connect to server"); + } else if (!{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestException restException = RestException.fromJson(response.getStream(), client.getObjectMapper()); + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + } + + return {{apiName}}.fromJson(response.getStream(), client.getObjectMapper()); + } +{{#vendorExtensions.x-has-form-params}} +{{>postParams}} +{{/vendorExtensions.x-has-form-params}} +{{#vendorExtensions.x-has-body-params}} +{{>postParams_body}} +{{/vendorExtensions.x-has-body-params}} +{{#vendorExtensions.x-has-header-params}} +{{>headerParams}} +{{/vendorExtensions.x-has-header-params}} +{{#vendorExtensions.x-has-query-params}} + private void addQueryParams(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request) { +{{>queryParams}} } +{{/vendorExtensions.x-has-query-params}} +} +{{/vendorExtensions.x-is-create-operation}} +{{/apiOperations}} +{{/resources}} diff --git a/src/main/resources/twilio-java/dateParams.mustache b/src/main/resources/twilio-java-legacy/dateParams.mustache similarity index 100% rename from src/main/resources/twilio-java/dateParams.mustache rename to src/main/resources/twilio-java-legacy/dateParams.mustache diff --git a/src/main/resources/twilio-java/dateTimeGroupParams.mustache b/src/main/resources/twilio-java-legacy/dateTimeGroupParams.mustache similarity index 100% rename from src/main/resources/twilio-java/dateTimeGroupParams.mustache rename to src/main/resources/twilio-java-legacy/dateTimeGroupParams.mustache diff --git a/src/main/resources/twilio-java-legacy/deleter.mustache b/src/main/resources/twilio-java-legacy/deleter.mustache new file mode 100644 index 000000000..082c5df14 --- /dev/null +++ b/src/main/resources/twilio-java-legacy/deleter.mustache @@ -0,0 +1,129 @@ +{{>licenseInfo}} +{{#resources}} +package com.twilio.rest.{{domainPackage}}.{{apiVersion}}{{namespaceSubPart}}; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.twilio.converter.Promoter; +import com.twilio.constant.EnumConstants; +import com.twilio.exception.ApiConnectionException; +import com.twilio.converter.PrefixedCollapsibleMap; +import com.twilio.exception.ApiException; +import com.twilio.converter.Converter; +import com.twilio.exception.RestException; +import com.twilio.http.HttpMethod; +import com.twilio.http.Response; +import com.twilio.rest.Domains; +import java.time.LocalDate; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.net.URI; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import com.twilio.converter.DateConverter; + +{{^fullJavaUtil}} +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +{{/fullJavaUtil}} + +import lombok.ToString; + +{{#apiOperations}} +{{#vendorExtensions.x-is-delete-operation}} +import com.twilio.base{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.Deleter; +import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request; +import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient; + +public class {{apiName}}Deleter extends Deleter<{{apiName}}> { +{{#allParams}} + private {{{dataType}}} {{paramName}}; +{{/allParams}} + +{{#vendorExtensions.x-signature-list}} + public {{apiName}}Deleter({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}){ + {{#.}} + this.{{paramName}} = {{paramName}}; + {{/.}} + } +{{/vendorExtensions.x-signature-list}} + +{{#vendorExtensions.x-non-path-params}} + public {{apiName}}Deleter set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ + this.{{paramName}} = {{paramName}}; + return this; + } +{{#isArray}} + public {{apiName}}Deleter set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); + } +{{/isArray}} +{{#vendorExtensions.x-promotions}} +{{#entrySet}} + + public {{apiName}}Deleter set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{#lambda.titlecase}}{{key}}{{/lambda.titlecase}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{value}}); + } +{{/entrySet}} +{{/vendorExtensions.x-promotions}} +{{/vendorExtensions.x-non-path-params}} + + @Override + public boolean delete(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client) { +{{>generate_uri}} + {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( + {{vendorExtensions.x-http-method}}, + Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), + path + ); + {{#queryParams.0}} + addQueryParams(request); + {{/queryParams.0}} + {{^vendorExtensions.x-is-json}} + request.setContentType(EnumConstants.ContentType.FORM_URLENCODED); + {{/vendorExtensions.x-is-json}} + {{#vendorExtensions.x-is-json}} + request.setContentType(EnumConstants.ContentType.JSON); + {{/vendorExtensions.x-is-json}} + {{#formParams.0}} + addPostParams(request); + {{/formParams.0}} + {{#bodyParams.0}} + addPostParams(request, client); + {{/bodyParams.0}} + {{#headerParams.0}} + addHeaderParams(request); + {{/headerParams.0}} + Response response = client.request(request); + + if (response == null) { + throw new ApiConnectionException("{{apiName}} delete failed: Unable to connect to server"); + } else if (!{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestException restException = RestException.fromJson(response.getStream(), client.getObjectMapper()); + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + } + return response.getStatusCode() == 204; + } +{{#vendorExtensions.x-has-form-params}} +{{>postParams}} +{{/vendorExtensions.x-has-form-params}} +{{#vendorExtensions.x-has-body-params}} +{{>postParams_body}} +{{/vendorExtensions.x-has-body-params}} +{{#vendorExtensions.x-has-header-params}} +{{>headerParams}} +{{/vendorExtensions.x-has-header-params}} +{{#vendorExtensions.x-has-query-params}} + private void addQueryParams(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request) { +{{>queryParams}} } +{{/vendorExtensions.x-has-query-params}} +} +{{/vendorExtensions.x-is-delete-operation}} +{{/apiOperations}} +{{/resources}} diff --git a/src/main/resources/twilio-java-legacy/enums.mustache b/src/main/resources/twilio-java-legacy/enums.mustache new file mode 100644 index 000000000..43c17f9fa --- /dev/null +++ b/src/main/resources/twilio-java-legacy/enums.mustache @@ -0,0 +1,24 @@ +{{#enums}} + public enum {{#lambda.titlecase}}{{{enumName}}}{{/lambda.titlecase}} { + {{#allowableValues}} + {{#values}} + {{#lambda.uppercase}}{{#lambda.replacehyphen}}{{{.}}}{{/lambda.replacehyphen}}({{/lambda.uppercase}}"{{{.}}}"){{^-last}},{{/-last}}{{#-last}};{{/-last}} + {{/values}} + {{/allowableValues}} + + private final String value; + + private {{#lambda.titlecase}}{{{enumName}}}{{/lambda.titlecase}}(final String value) { + this.value = value; + } + + public String toString() { + return value; + } + + @JsonCreator + public static {{#lambda.titlecase}}{{{enumName}}}{{/lambda.titlecase}} forValue(final String value) { + return Promoter.enumFromString(value, {{#lambda.titlecase}}{{{enumName}}}{{/lambda.titlecase}}.values()); + } + } +{{/enums}} \ No newline at end of file diff --git a/src/main/resources/twilio-java-legacy/fetcher.mustache b/src/main/resources/twilio-java-legacy/fetcher.mustache new file mode 100644 index 000000000..34be9003b --- /dev/null +++ b/src/main/resources/twilio-java-legacy/fetcher.mustache @@ -0,0 +1,131 @@ +{{>licenseInfo}} +{{#resources}} +package com.twilio.rest.{{domainPackage}}.{{apiVersion}}{{namespaceSubPart}}; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.twilio.constant.EnumConstants; +import com.twilio.converter.Promoter; +import com.twilio.exception.ApiConnectionException; +import com.twilio.converter.PrefixedCollapsibleMap; +import com.twilio.converter.Converter; +import com.twilio.exception.ApiException; +import com.twilio.exception.RestException; +import com.twilio.http.HttpMethod; +import com.twilio.http.Response; +import com.twilio.rest.Domains; + +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.net.URI; +import java.time.ZonedDateTime; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import com.twilio.converter.DateConverter; + +{{^fullJavaUtil}} +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +{{/fullJavaUtil}} + +import lombok.ToString; + +{{#apiOperations}} +{{#vendorExtensions.x-is-fetch-operation}} +import com.twilio.base{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.Fetcher; +import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request; +import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient; + +public class {{apiName}}Fetcher extends Fetcher<{{apiName}}> { +{{#allParams}} + private {{{dataType}}} {{paramName}}; +{{/allParams}} + +{{#vendorExtensions.x-signature-list}} + public {{apiName}}Fetcher({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}){ + {{#.}} + this.{{paramName}} = {{paramName}}; + {{/.}} + } +{{/vendorExtensions.x-signature-list}} + +{{#vendorExtensions.x-non-path-params}} + public {{apiName}}Fetcher set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ + this.{{paramName}} = {{paramName}}; + return this; + } +{{#isArray}} + public {{apiName}}Fetcher set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); + } +{{/isArray}} +{{#vendorExtensions.x-promotions}} +{{#entrySet}} + + public {{apiName}}Fetcher set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{#lambda.titlecase}}{{key}}{{/lambda.titlecase}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{value}}); + } +{{/entrySet}} +{{/vendorExtensions.x-promotions}} +{{/vendorExtensions.x-non-path-params}} + + @Override + public {{apiName}} fetch(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client) { +{{>generate_uri}} + {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( + {{vendorExtensions.x-http-method}}, + Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), + path + ); + {{#queryParams.0}} + addQueryParams(request); + {{/queryParams.0}} + {{^vendorExtensions.x-is-json}} + request.setContentType(EnumConstants.ContentType.FORM_URLENCODED); + {{/vendorExtensions.x-is-json}} + {{#vendorExtensions.x-is-json}} + request.setContentType(EnumConstants.ContentType.JSON); + {{/vendorExtensions.x-is-json}} + {{#formParams.0}} + addPostParams(request); + {{/formParams.0}} + {{#bodyParams.0}} + addPostParams(request, client); + {{/bodyParams.0}} + {{#headerParams.0}} + addHeaderParams(request); + {{/headerParams.0}} + Response response = client.request(request); + + if (response == null) { + throw new ApiConnectionException("{{apiName}} fetch failed: Unable to connect to server"); + } else if (!{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestException restException = RestException.fromJson(response.getStream(), client.getObjectMapper()); + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + } + + return {{apiName}}.fromJson(response.getStream(), client.getObjectMapper()); + } +{{#vendorExtensions.x-has-form-params}} +{{>postParams}} +{{/vendorExtensions.x-has-form-params}} +{{#vendorExtensions.x-has-body-params}} +{{>postParams_body}} +{{/vendorExtensions.x-has-body-params}} +{{#vendorExtensions.x-has-header-params}} +{{>headerParams}} +{{/vendorExtensions.x-has-header-params}} +{{#vendorExtensions.x-has-query-params}} + private void addQueryParams(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request) { +{{>queryParams}} } +{{/vendorExtensions.x-has-query-params}} +} +{{/vendorExtensions.x-is-fetch-operation}} +{{/apiOperations}} +{{/resources}} diff --git a/src/main/resources/twilio-java/generate_uri.mustache b/src/main/resources/twilio-java-legacy/generate_uri.mustache similarity index 100% rename from src/main/resources/twilio-java/generate_uri.mustache rename to src/main/resources/twilio-java-legacy/generate_uri.mustache diff --git a/src/main/resources/twilio-java/headerParams.mustache b/src/main/resources/twilio-java-legacy/headerParams.mustache similarity index 100% rename from src/main/resources/twilio-java/headerParams.mustache rename to src/main/resources/twilio-java-legacy/headerParams.mustache diff --git a/src/main/resources/twilio-java-legacy/licenseInfo.mustache b/src/main/resources/twilio-java-legacy/licenseInfo.mustache new file mode 100644 index 000000000..62ae6193c --- /dev/null +++ b/src/main/resources/twilio-java-legacy/licenseInfo.mustache @@ -0,0 +1,13 @@ +/* + * This code was generated by + * ___ _ _ _ _ _ _ ____ ____ ____ _ ____ ____ _ _ ____ ____ ____ ___ __ __ + * | | | | | | | | | __ | | |__| | __ | __ |___ |\ | |___ |__/ |__| | | | |__/ + * | |_|_| | |___ | |__| |__| | | | |__] |___ | \| |___ | \ | | | |__| | \ + * + * {{{appName}}} + * {{{appDescription}}} + * + * NOTE: This class is auto generated by OpenAPI Generator. + * https://openapi-generator.tech + * Do not edit the class manually. + */ diff --git a/src/main/resources/twilio-java-legacy/models.mustache b/src/main/resources/twilio-java-legacy/models.mustache new file mode 100644 index 000000000..a95788f86 --- /dev/null +++ b/src/main/resources/twilio-java-legacy/models.mustache @@ -0,0 +1,41 @@ + + {{#resources.nestedModels}} + @ToString + static public class {{classname}} { + {{#vars}} + @JsonInclude(JsonInclude.Include.NON_EMPTY) + @JsonProperty("{{{baseName}}}") + {{#vendorExtensions.x-ref-enum}} + @Getter @Setter private {{{datatypeWithEnum}}} {{name}}; + {{/vendorExtensions.x-ref-enum}} + {{^vendorExtensions.x-ref-enum}} + @Getter @Setter private {{{dataType}}} {{name}}; + {{/vendorExtensions.x-ref-enum}} + {{^isMap}} + {{^isFreeFormObject}} + {{^isAnyType}} + {{#vendorExtensions.x-serialize}} + public String get{{#lambda.titlecase}}{{name}}{{/lambda.titlecase}}() { + return {{vendorExtensions.x-serialize}}; + }{{/vendorExtensions.x-serialize}} + {{/isAnyType}} + {{/isFreeFormObject}} + {{/isMap}} + {{/vars}} + {{#vendorExtensions.x-constructor-required}} + {{#vendorExtensions.x-model-parameters}} + public {{classname}}({{#.}}final {{{dataType}}} {{name}}{{^-last}}, {{/-last}}{{/.}} ) { + {{#.}} + this.{{name}} = {{name}}; + {{/.}} + } + {{/vendorExtensions.x-model-parameters}} + {{/vendorExtensions.x-constructor-required}} + + {{^vendorExtensions.x-response}} + public static {{classname}} fromJson(String jsonString, ObjectMapper mapper) throws IOException { + return mapper.readValue(jsonString, {{classname}}.class); + } + {{/vendorExtensions.x-response}} + } + {{/resources.nestedModels}} diff --git a/src/main/resources/twilio-java/packageName.mustache b/src/main/resources/twilio-java-legacy/packageName.mustache similarity index 100% rename from src/main/resources/twilio-java/packageName.mustache rename to src/main/resources/twilio-java-legacy/packageName.mustache diff --git a/src/main/resources/twilio-java/postParams.mustache b/src/main/resources/twilio-java-legacy/postParams.mustache similarity index 100% rename from src/main/resources/twilio-java/postParams.mustache rename to src/main/resources/twilio-java-legacy/postParams.mustache diff --git a/src/main/resources/twilio-java/postParams_body.mustache b/src/main/resources/twilio-java-legacy/postParams_body.mustache similarity index 100% rename from src/main/resources/twilio-java/postParams_body.mustache rename to src/main/resources/twilio-java-legacy/postParams_body.mustache diff --git a/src/main/resources/twilio-java/prefixedCollapsibleMapQParams.mustache b/src/main/resources/twilio-java-legacy/prefixedCollapsibleMapQParams.mustache similarity index 100% rename from src/main/resources/twilio-java/prefixedCollapsibleMapQParams.mustache rename to src/main/resources/twilio-java-legacy/prefixedCollapsibleMapQParams.mustache diff --git a/src/main/resources/twilio-java/queryParams.mustache b/src/main/resources/twilio-java-legacy/queryParams.mustache similarity index 100% rename from src/main/resources/twilio-java/queryParams.mustache rename to src/main/resources/twilio-java-legacy/queryParams.mustache diff --git a/src/main/resources/twilio-java-legacy/reader.mustache b/src/main/resources/twilio-java-legacy/reader.mustache new file mode 100644 index 000000000..0297987bd --- /dev/null +++ b/src/main/resources/twilio-java-legacy/reader.mustache @@ -0,0 +1,186 @@ +{{>licenseInfo}} +{{#resources}} +package com.twilio.rest.{{domainPackage}}.{{apiVersion}}{{namespaceSubPart}}; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.twilio.constant.EnumConstants; +import com.twilio.converter.Promoter; +import com.twilio.exception.ApiConnectionException; +import com.twilio.converter.PrefixedCollapsibleMap; +import com.twilio.converter.Converter; +import com.twilio.exception.ApiException; +import com.twilio.exception.RestException; +import com.twilio.http.HttpMethod; +import com.twilio.http.Response; +import com.twilio.rest.Domains; +import java.time.LocalDate; +import java.time.ZonedDateTime; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.net.URI; +import java.time.format.DateTimeFormatter; +import com.twilio.converter.DateConverter; + +{{^fullJavaUtil}} +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +{{/fullJavaUtil}} + +import lombok.ToString; + +{{#apiOperations}} +{{#vendorExtensions.x-is-read-operation}} +import com.twilio.base{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.Page; +import com.twilio.base{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.Reader; +import com.twilio.base{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.ResourceSet; +import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request; +import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient; + +public class {{apiName}}Reader extends Reader<{{apiName}}> { +{{#allParams}} + private {{{dataType}}} {{paramName}}; +{{/allParams}} + +{{#vendorExtensions.x-signature-list}} + public {{apiName}}Reader({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}){ + {{#.}} + this.{{paramName}} = {{paramName}}; + {{/.}} + } +{{/vendorExtensions.x-signature-list}} + +{{#vendorExtensions.x-non-path-params}} + public {{apiName}}Reader set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ + this.{{paramName}} = {{paramName}}; + return this; + } +{{#isArray}} + public {{apiName}}Reader set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); + } +{{/isArray}} +{{#vendorExtensions.x-promotions}} +{{#entrySet}} + + public {{apiName}}Reader set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{#lambda.titlecase}}{{key}}{{/lambda.titlecase}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{value}}); + } +{{/entrySet}} +{{/vendorExtensions.x-promotions}} +{{/vendorExtensions.x-non-path-params}} + + @Override + public ResourceSet<{{apiName}}> read(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client) { + return new ResourceSet<>(this, client, firstPage(client)); + } + + public Page<{{apiName}}> firstPage(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client) { + String path = "{{{path}}}"; + {{#allParams}} + {{#vendorExtensions.x-is-account-sid}} + this.{{paramName}} = this.{{paramName}} == null ? client.getAccountSid() : this.{{paramName}}; + path = path.replace("{"+"{{baseName}}"+"}", this.{{paramName}}.toString()); + {{/vendorExtensions.x-is-account-sid}} + {{/allParams}} + {{#requiredParams}} + path = path.replace("{"+"{{baseName}}"+"}", this.{{paramName}}.toString()); + {{/requiredParams}} + + {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( + {{vendorExtensions.x-http-method}}, + Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), + path + ); + + {{#queryParams.0}} + addQueryParams(request); + {{/queryParams.0}} + {{^vendorExtensions.x-is-json}} + request.setContentType(EnumConstants.ContentType.FORM_URLENCODED); + {{/vendorExtensions.x-is-json}} + {{#vendorExtensions.x-is-json}} + request.setContentType(EnumConstants.ContentType.JSON); + {{/vendorExtensions.x-is-json}} + {{#formParams.0}} + addPostParams(request); + {{/formParams.0}} + {{#bodyParams.0}} + addPostParams(request, client); + {{/bodyParams.0}} + {{#headerParams.0}} + addHeaderParams(request); + {{/headerParams.0}} + return pageForRequest(client, request); + } + + private Page<{{apiName}}> pageForRequest(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client, final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request) { + Response response = client.request(request); + + if (response == null) { + throw new ApiConnectionException("{{apiName}} read failed: Unable to connect to server"); + } else if (!{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestException restException = RestException.fromJson(response.getStream(), client.getObjectMapper()); + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + } + + return Page.fromJson( + "{{recordKey}}", + response.getContent(), + {{apiName}}.class, + client.getObjectMapper() + ); + } + + @Override + public Page<{{apiName}}> previousPage(final Page<{{apiName}}> page, final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client) { + {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( + {{vendorExtensions.x-http-method}}, + page.getPreviousPageUrl(Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString()) + ); + return pageForRequest(client, request); + } + + + @Override + public Page<{{apiName}}> nextPage(final Page<{{apiName}}> page, final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client) { + {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( + {{vendorExtensions.x-http-method}}, + page.getNextPageUrl(Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString()) + ); + return pageForRequest(client, request); + } + + @Override + public Page<{{apiName}}> getPage(final String targetUrl, final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client) { + {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( + HttpMethod.GET, + targetUrl + ); + + return pageForRequest(client, request); + } +{{#vendorExtensions.x-has-form-params}} +{{>postParams}} +{{/vendorExtensions.x-has-form-params}} +{{#vendorExtensions.x-has-header-params}} +{{>headerParams}} +{{/vendorExtensions.x-has-header-params}} +{{#vendorExtensions.x-has-query-params}} + private void addQueryParams(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request) { +{{>queryParams}} + if(getPageSize() != null) { + request.addQueryParam("PageSize", Integer.toString(getPageSize())); + } + } +{{/vendorExtensions.x-has-query-params}} +} +{{/vendorExtensions.x-is-read-operation}} +{{/apiOperations}} +{{/resources}} diff --git a/src/main/resources/twilio-java/responseModel.mustache b/src/main/resources/twilio-java-legacy/responseModel.mustache similarity index 100% rename from src/main/resources/twilio-java/responseModel.mustache rename to src/main/resources/twilio-java-legacy/responseModel.mustache diff --git a/src/main/resources/twilio-java-legacy/updater.mustache b/src/main/resources/twilio-java-legacy/updater.mustache new file mode 100644 index 000000000..d14fd7661 --- /dev/null +++ b/src/main/resources/twilio-java-legacy/updater.mustache @@ -0,0 +1,132 @@ +{{>licenseInfo}} +{{#resources}} +package com.twilio.rest.{{domainPackage}}.{{apiVersion}}{{namespaceSubPart}}; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.twilio.constant.EnumConstants; +import com.twilio.converter.Promoter; +import com.twilio.exception.ApiConnectionException; +import com.twilio.converter.PrefixedCollapsibleMap; +import com.twilio.converter.Converter; +import com.twilio.exception.ApiException; +import com.twilio.exception.RestException; +import com.twilio.http.HttpMethod; +import com.twilio.http.Response; +import com.twilio.rest.Domains; +import java.time.format.DateTimeFormatter; +import com.twilio.converter.DateConverter; + +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.net.URI; +import java.time.ZonedDateTime; +import java.time.LocalDate; + +{{^fullJavaUtil}} +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +{{/fullJavaUtil}} + +import lombok.ToString; + +{{#apiOperations}} +{{#vendorExtensions.x-is-update-operation}} +import com.twilio.base{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.Updater; +import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request; +import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient; + + +public class {{apiName}}Updater extends Updater<{{apiName}}>{ +{{#allParams}} + private {{{dataType}}} {{paramName}}; +{{/allParams}} + +{{#vendorExtensions.x-signature-list}} + public {{apiName}}Updater({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}){ + {{#.}} + this.{{paramName}} = {{paramName}}; + {{/.}} + } +{{/vendorExtensions.x-signature-list}} + +{{#vendorExtensions.x-non-path-params}} + public {{apiName}}Updater set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ + this.{{paramName}} = {{paramName}}; + return this; + } +{{#isArray}} + public {{apiName}}Updater set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); + } +{{/isArray}} +{{#vendorExtensions.x-promotions}} +{{#entrySet}} + + public {{apiName}}Updater set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{#lambda.titlecase}}{{key}}{{/lambda.titlecase}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{value}}); + } +{{/entrySet}} +{{/vendorExtensions.x-promotions}} +{{/vendorExtensions.x-non-path-params}} + + @Override + public {{apiName}} update(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client){ +{{>generate_uri}} + {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( + {{vendorExtensions.x-http-method}}, + Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), + path + ); + {{#queryParams.0}} + addQueryParams(request); + {{/queryParams.0}} + {{^vendorExtensions.x-is-json}} + request.setContentType(EnumConstants.ContentType.FORM_URLENCODED); + {{/vendorExtensions.x-is-json}} + {{#vendorExtensions.x-is-json}} + request.setContentType(EnumConstants.ContentType.JSON); + {{/vendorExtensions.x-is-json}} + {{#formParams.0}} + addPostParams(request); + {{/formParams.0}} + {{#bodyParams.0}} + addPostParams(request, client); + {{/bodyParams.0}} + {{#headerParams.0}} + addHeaderParams(request); + {{/headerParams.0}} + Response response = client.request(request); + if (response == null) { + throw new ApiConnectionException("{{apiName}} update failed: Unable to connect to server"); + } else if (!{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestException restException = RestException.fromJson(response.getStream(), client.getObjectMapper()); + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + } + + return {{apiName}}.fromJson(response.getStream(), client.getObjectMapper()); + } + +{{#vendorExtensions.x-has-form-params}} +{{>postParams}} +{{/vendorExtensions.x-has-form-params}} +{{#vendorExtensions.x-has-body-params}} +{{>postParams_body}} +{{/vendorExtensions.x-has-body-params}} +{{#vendorExtensions.x-has-header-params}} +{{>headerParams}} +{{/vendorExtensions.x-has-header-params}} +{{#vendorExtensions.x-has-query-params}} + private void addQueryParams(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request) { +{{>queryParams}} } +{{/vendorExtensions.x-has-query-params}} +} +{{/vendorExtensions.x-is-update-operation}} +{{/apiOperations}} +{{/resources}} diff --git a/src/main/resources/twilio-java/Readme.md b/src/main/resources/twilio-java/Readme.md new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/resources/twilio-java/allConstructors.mustache b/src/main/resources/twilio-java/allConstructors.mustache new file mode 100644 index 000000000..26fc4e4bb --- /dev/null +++ b/src/main/resources/twilio-java/allConstructors.mustache @@ -0,0 +1,64 @@ + +{{#operations}} +{{#vendorExtensions.x-create-operation}} +{{#vendorExtensions.x-signature-list}} + + public static {{resourceName}}Creator creator({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}) { + return new {{resourceName}}Creator( + {{#.}} {{paramName}}{{^-last}}, {{/-last}}{{/.}} + ); + } + +{{/vendorExtensions.x-signature-list}} +{{/vendorExtensions.x-create-operation}} + + +{{#vendorExtensions.x-delete-operation}} +{{#vendorExtensions.x-signature-list}} + + public static {{resourceName}}Deleter deleter({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}) { + return new {{resourceName}}Deleter( + {{#.}} {{paramName}}{{^-last}}, {{/-last}}{{/.}} + ); + } + +{{/vendorExtensions.x-signature-list}} +{{/vendorExtensions.x-delete-operation}} + +{{#vendorExtensions.x-fetch-operation}} +{{#vendorExtensions.x-signature-list}} + + public static {{resourceName}}Fetcher fetcher({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}) { + return new {{resourceName}}Fetcher( + {{#.}} {{paramName}}{{^-last}}, {{/-last}}{{/.}} + ); + } + +{{/vendorExtensions.x-signature-list}} +{{/vendorExtensions.x-fetch-operation}} + +{{#vendorExtensions.x-list-operation}} +{{#vendorExtensions.x-signature-list}} + + public static {{resourceName}}Reader reader({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}) { + return new {{resourceName}}Reader( + {{#.}} {{paramName}}{{^-last}}, {{/-last}}{{/.}} + ); + } + +{{/vendorExtensions.x-signature-list}} +{{/vendorExtensions.x-list-operation}} + +{{#vendorExtensions.x-update-operation}} +{{#vendorExtensions.x-signature-list}} + + public static {{resourceName}}Updater updater({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}) { + return new {{resourceName}}Updater( + {{#.}} {{paramName}}{{^-last}}, {{/-last}}{{/.}} + ); + } + +{{/vendorExtensions.x-signature-list}} +{{/vendorExtensions.x-update-operation}} + +{{/operations}} diff --git a/src/main/resources/twilio-java/api.mustache b/src/main/resources/twilio-java/api.mustache index deaa723ed..f38a63e80 100644 --- a/src/main/resources/twilio-java/api.mustache +++ b/src/main/resources/twilio-java/api.mustache @@ -2,166 +2,20 @@ {{#resources}} package com.twilio.rest.{{domainPackage}}.{{apiVersion}}{{namespaceSubPart}}; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.twilio.base{{authMethodPackage}}.Resource; -import com.twilio.converter.Converter; -import java.util.Currency; -import com.twilio.converter.DateConverter; -import com.twilio.converter.Promoter; -import com.twilio.converter.PrefixedCollapsibleMap; -import com.twilio.converter.CurrencyDeserializer; -import com.twilio.exception.ApiConnectionException; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; - -import com.twilio.exception.ApiException; -import com.twilio.exception.RestException; -import com.twilio.http.HttpMethod; -import com.twilio.http.Request; -import com.twilio.http.Response; -import com.twilio.http.TwilioRestClient; -import com.twilio.rest.Domains; - -import lombok.ToString; - +{{>common/imports}} +import com.twilio.base.Resource; import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.time.ZonedDateTime; - -{{^fullJavaUtil}} -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -{{/fullJavaUtil}} - -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; - -import java.util.Map; -import java.time.LocalDate; -import java.math.BigDecimal; -import com.twilio.type.PhoneNumberCapabilities; -import com.twilio.type.FeedbackIssue; -import com.twilio.type.IceServer; -import com.twilio.type.InboundCallPrice; -import com.twilio.type.OutboundPrefixPriceWithOrigin; -import com.twilio.type.OutboundPrefixPrice; -import com.twilio.type.OutboundCallPriceWithOrigin; -import com.twilio.type.PhoneNumberPrice; -import com.twilio.type.InboundSmsPrice; -import com.twilio.type.OutboundSmsPrice; -import com.twilio.type.OutboundCallPrice; -import com.twilio.type.RecordingRule; -import com.twilio.type.SubscribeRule; +import com.fasterxml.jackson.core.JsonParseException; @JsonIgnoreProperties(ignoreUnknown = true) @ToString -public class {{apiName}} extends Resource { - private static final long serialVersionUID = {{serialVersionUID}}L; - - {{>models}} - {{#apiOperations}} - {{#vendorExtensions.x-is-create-operation}} - {{#vendorExtensions.x-signature-list}} - public static {{apiName}}Creator creator({{#.}}final {{{dataType}}} {{{paramName}}}{{^-last}}, {{/-last}}{{/.}}){ - return new {{apiName}}Creator({{#.}}{{{paramName}}}{{^-last}}, {{/-last}}{{/.}}); - } - {{/vendorExtensions.x-signature-list}} - - {{/vendorExtensions.x-is-create-operation}} - {{#vendorExtensions.x-is-fetch-operation}} - {{#vendorExtensions.x-signature-list}} - public static {{apiName}}Fetcher fetcher({{#.}}final {{{dataType}}} {{{paramName}}}{{^-last}}, {{/-last}}{{/.}}){ - return new {{apiName}}Fetcher({{#.}}{{{paramName}}}{{^-last}}, {{/-last}}{{/.}}); - } - {{/vendorExtensions.x-signature-list}} - - {{/vendorExtensions.x-is-fetch-operation}} - {{#vendorExtensions.x-is-delete-operation}} - {{#vendorExtensions.x-signature-list}} - public static {{apiName}}Deleter deleter({{#.}}final {{{dataType}}} {{{paramName}}}{{^-last}}, {{/-last}}{{/.}}){ - return new {{apiName}}Deleter({{#.}}{{{paramName}}}{{^-last}}, {{/-last}}{{/.}}); - } - {{/vendorExtensions.x-signature-list}} - - {{/vendorExtensions.x-is-delete-operation}} - {{#vendorExtensions.x-is-read-operation}} - {{#vendorExtensions.x-signature-list}} - public static {{apiName}}Reader reader({{#.}}final {{{dataType}}} {{{paramName}}}{{^-last}}, {{/-last}}{{/.}}){ - return new {{apiName}}Reader({{#.}}{{{paramName}}}{{^-last}}, {{/-last}}{{/.}}); - } - {{/vendorExtensions.x-signature-list}} - - {{/vendorExtensions.x-is-read-operation}} - {{#vendorExtensions.x-is-update-operation}} - {{#vendorExtensions.x-signature-list}} - public static {{apiName}}Updater updater({{#.}}final {{{dataType}}} {{{paramName}}}{{^-last}}, {{/-last}}{{/.}}){ - return new {{apiName}}Updater({{#.}}{{{paramName}}}{{^-last}}, {{/-last}}{{/.}}); - } - {{/vendorExtensions.x-signature-list}} - - {{/vendorExtensions.x-is-update-operation}} - {{/apiOperations}} - /** - * Converts a JSON String into a {{apiName}} object using the provided ObjectMapper. - * - * @param json Raw JSON String - * @param objectMapper Jackson ObjectMapper - * @return {{apiName}} object represented by the provided JSON - */ - public static {{apiName}} fromJson(final String json, final ObjectMapper objectMapper) { - // Convert all checked exceptions to Runtime - try { - return objectMapper.readValue(json, {{apiName}}.class); - } catch (final JsonMappingException | JsonParseException e) { - throw new ApiException(e.getMessage(), e); - } catch (final IOException e) { - throw new ApiConnectionException(e.getMessage(), e); - } - } +public class {{resourceName}} extends Resource { - /** - * Converts a JSON InputStream into a {{apiName}} object using the provided - * ObjectMapper. - * - * @param json Raw JSON InputStream - * @param objectMapper Jackson ObjectMapper - * @return {{apiName}} object represented by the provided JSON - */ - public static {{apiName}} fromJson(final InputStream json, final ObjectMapper objectMapper) { - // Convert all checked exceptions to Runtime - try { - return objectMapper.readValue(json, {{apiName}}.class); - } catch (final JsonMappingException | JsonParseException e) { - throw new ApiException(e.getMessage(), e); - } catch (final IOException e) { - throw new ApiConnectionException(e.getMessage(), e); - } - } - {{#hasNestedRequestBody}} - public static String toJson(Object object, ObjectMapper mapper) { - try { - return mapper.writeValueAsString(object); - } catch (final JsonMappingException e) { - throw new ApiException(e.getMessage(), e); - } catch (JsonProcessingException e) { - throw new ApiException(e.getMessage(), e); - } catch (final IOException e) { - throw new ApiConnectionException(e.getMessage(), e); - } - }{{/hasNestedRequestBody}} -{{>responseModel}} +{{>allConstructors}} {{>enums}} +{{>models}} +{{>staticMethods}} +{{>response}} } {{/resources}} diff --git a/src/main/resources/twilio-java/common/addHeaderParams.mustache b/src/main/resources/twilio-java/common/addHeaderParams.mustache new file mode 100644 index 000000000..50105e54d --- /dev/null +++ b/src/main/resources/twilio-java/common/addHeaderParams.mustache @@ -0,0 +1,22 @@ +private void addHeaderParams(final Request request) { +{{#headerParams}} + +{{! -- case1 Normal Parameter (Non Array, Non equality parameter)}} +{{^isArray}} +{{^vendorExtensions.x-inequality-main}} + if ({{paramName}} != null) { + Serializer.toString(request, "{{{baseName}}}", {{paramName}}, ParameterType.HEADER); + } +{{/vendorExtensions.x-inequality-main}} +{{/isArray}} +{{! -- Case2: Array Parameter }} +{{#isArray}} + if ({{paramName}} != null) { + for ({{baseType}} param: {{paramName}}) { + Serializer.toString(request, "{{{baseName}}}", param, ParameterType.HEADER); + } + } +{{/isArray}} + +{{/headerParams}} +} \ No newline at end of file diff --git a/src/main/resources/twilio-java/common/addPostParams.mustache b/src/main/resources/twilio-java/common/addPostParams.mustache new file mode 100644 index 000000000..cbd1705b6 --- /dev/null +++ b/src/main/resources/twilio-java/common/addPostParams.mustache @@ -0,0 +1,23 @@ +private void addPostParams(final Request request) { +{{#formParams}} + + {{! -- case1 Normal Parameter (Non Array, Non equality parameter)}} +{{^isArray}} +{{^vendorExtensions.x-inequality-main}} + if ({{paramName}} != null) { + Serializer.toString(request, "{{{baseName}}}", {{paramName}}, ParameterType.URLENCODED); + } +{{/vendorExtensions.x-inequality-main}} +{{/isArray}} + +{{! -- Case2: Array Parameter }} +{{#isArray}} + if ({{paramName}} != null) { + for ({{baseType}} param: {{paramName}}) { + Serializer.toString(request, "{{{baseName}}}", param, ParameterType.URLENCODED); + } + } +{{/isArray}} + +{{/formParams}} +} \ No newline at end of file diff --git a/src/main/resources/twilio-java/common/addPostParamsJson.mustache b/src/main/resources/twilio-java/common/addPostParamsJson.mustache new file mode 100644 index 000000000..d87b90b7c --- /dev/null +++ b/src/main/resources/twilio-java/common/addPostParamsJson.mustache @@ -0,0 +1,8 @@ +private void addPostParams(final Request request, TwilioRestClient client) { + ObjectMapper objectMapper = client.getObjectMapper(); + {{#bodyParams}} + if ({{paramName}} != null) { + request.setBody({{resourceName}}.toJson({{paramName}}, objectMapper)); + } + {{/bodyParams}} +} \ No newline at end of file diff --git a/src/main/resources/twilio-java/common/addQueryParams.mustache b/src/main/resources/twilio-java/common/addQueryParams.mustache new file mode 100644 index 000000000..857f55571 --- /dev/null +++ b/src/main/resources/twilio-java/common/addQueryParams.mustache @@ -0,0 +1,36 @@ +private void addQueryParams(final Request request) { +{{! -- 4 cases: Normal parameter, Eqality parameter(Message), Ineqality Parameter(MessageBefore, MessageAfter)}, List Parameter }} +{{#queryParams}} +{{^vendorExtensions.x-has-before-or-after}}{{! -- These serialize in equality field}} + +{{! -- case1 Normal Parameter (Non Array, Non equality parameter)}} +{{^isArray}} +{{^vendorExtensions.x-inequality-main}} + if ({{paramName}} != null) { + Serializer.toString(request, "{{{baseName}}}", {{paramName}}, ParameterType.QUERY); + } +{{/vendorExtensions.x-inequality-main}} +{{/isArray}} + +{{! -- Case2: Inequality Parameter, Non Array }} +{{! -- Case3: Add before and after with inequality parameter }} +{{^isArray}} +{{#vendorExtensions.x-inequality-main}} + if ({{paramName}} != null) { + Serializer.toString(request, "{{{baseName}}}", {{paramName}}, {{paramName}}Before, {{paramName}}After); + } +{{/vendorExtensions.x-inequality-main}} +{{/isArray}} + +{{! -- Case4: Array Parameter }} +{{#isArray}} + if ({{paramName}} != null) { + for ({{baseType}} param: {{paramName}}) { + Serializer.toString(request, "{{{baseName}}}", param, ParameterType.QUERY); + } + } +{{/isArray}} + +{{/vendorExtensions.x-has-before-or-after}} +{{/queryParams}} +} \ No newline at end of file diff --git a/src/main/resources/twilio-java/common/constructors.mustache b/src/main/resources/twilio-java/common/constructors.mustache new file mode 100644 index 000000000..3aa4a722c --- /dev/null +++ b/src/main/resources/twilio-java/common/constructors.mustache @@ -0,0 +1,7 @@ +{{#vendorExtensions.x-signature-list}} + public {{resourceName}}{{vendorExtensions.x-common-action-type}}({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}) { + {{#.}} + this.{{paramName}} = {{paramName}}; + {{/.}} + } +{{/vendorExtensions.x-signature-list}} \ No newline at end of file diff --git a/src/main/resources/twilio-java/common/generateUri.mustache b/src/main/resources/twilio-java/common/generateUri.mustache new file mode 100644 index 000000000..3ebe8b578 --- /dev/null +++ b/src/main/resources/twilio-java/common/generateUri.mustache @@ -0,0 +1,17 @@ + +{{#vendorExtensions.parentUrl}} + String path = "{{{vendorExtensions.parentUrl}}}"; +{{/vendorExtensions.parentUrl}} +{{^vendorExtensions.parentUrl}} + String path = "{{{path}}}"; +{{/vendorExtensions.parentUrl}} + +{{#pathParams}} + {{#vendorExtensions.x-is-account-sid}} + this.{{paramName}} = this.{{paramName}} == null ? client.getAccountSid() : this.{{paramName}}; + path = path.replace("{"+"{{baseName}}"+"}", this.{{paramName}}.toString()); + {{/vendorExtensions.x-is-account-sid}} + {{^vendorExtensions.x-is-account-sid}} + path = path.replace("{"+"{{baseName}}"+"}", this.{{paramName}}.toString()); + {{/vendorExtensions.x-is-account-sid}} +{{/pathParams}} diff --git a/src/main/resources/twilio-java/common/imports.mustache b/src/main/resources/twilio-java/common/imports.mustache new file mode 100644 index 000000000..2dce9d03f --- /dev/null +++ b/src/main/resources/twilio-java/common/imports.mustache @@ -0,0 +1,60 @@ +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import com.twilio.auth_strategy.NoAuthStrategy; +import com.twilio.base.Creator; +import com.twilio.base.Deleter; +import com.twilio.base.Fetcher; +import com.twilio.base.Reader; +import com.twilio.base.Updater; +import com.twilio.constant.EnumConstants; +import com.twilio.constant.EnumConstants.ParameterType; +import com.twilio.converter.Promoter; +import com.twilio.converter.Serializer; +import com.twilio.exception.ApiConnectionException; +import com.twilio.exception.ApiException; +import com.twilio.exception.RestException; +import com.twilio.http.HttpMethod; +import com.twilio.http.Request; +import com.twilio.http.Response; +import com.twilio.http.TwilioRestClient; +import com.twilio.rest.Domains; +import com.twilio.type.FeedbackIssue; +import com.twilio.type.IceServer; +import com.twilio.type.InboundCallPrice; +import com.twilio.type.InboundSmsPrice; +import com.twilio.type.OutboundCallPrice; +import com.twilio.type.OutboundCallPriceWithOrigin; +import com.twilio.type.OutboundPrefixPrice; +import com.twilio.type.OutboundPrefixPriceWithOrigin; +import com.twilio.type.OutboundSmsPrice; +import com.twilio.type.PhoneNumberCapabilities; +import com.twilio.type.PhoneNumberPrice; +import com.twilio.type.RecordingRule; +import com.twilio.type.SubscribeRule; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + + +import java.io.InputStream; +import java.math.BigDecimal; +import java.net.URI; +import java.time.LocalDate; +import java.time.ZonedDateTime; +import java.util.Currency; +import java.util.List; +import java.util.Map; +import com.twilio.type.*; +import java.util.Objects; +import com.twilio.base.Resource; +import java.io.IOException; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.fasterxml.jackson.core.JsonProcessingException; \ No newline at end of file diff --git a/src/main/resources/twilio-java/common/instanceVariables.mustache b/src/main/resources/twilio-java/common/instanceVariables.mustache new file mode 100644 index 000000000..6040b44dd --- /dev/null +++ b/src/main/resources/twilio-java/common/instanceVariables.mustache @@ -0,0 +1,15 @@ +{{#pathParams}} + private {{{dataType}}} {{paramName}}; +{{/pathParams}} +{{#queryParams}} + private {{{dataType}}} {{paramName}}; +{{/queryParams}} +{{#headerParams}} + private {{{dataType}}} {{paramName}}; +{{/headerParams}} +{{#formParams}} + private {{{dataType}}} {{paramName}}; +{{/formParams}} +{{#bodyParams}} + private {{{dataType}}} {{paramName}}; +{{/bodyParams}} \ No newline at end of file diff --git a/src/main/resources/twilio-java/common/operationMethod.mustache b/src/main/resources/twilio-java/common/operationMethod.mustache new file mode 100644 index 000000000..c518e5cba --- /dev/null +++ b/src/main/resources/twilio-java/common/operationMethod.mustache @@ -0,0 +1,51 @@ +{{! +resourceName: Api Name as identified by Directory Structure service +x-common-action-method: used to define operation method and can have values: create, read, update, delete, fetch + Example: https://github.com/twilio/twilio-java/blob/9c2ba4dbc185c5576e67fbeb82ec6f4899093e79/src/main/java/com/twilio/rest/api/v2010/account/MessageCreator.java#L309 + +httpMethod: http method associated in the current operation. +domainName: example api, video, chat, etc. These can be found in Domains.java in twilio-java +vendorExtensions.x-content-type: content type of the request, example: application/json, application/x-www-form-urlencoded +}} + @Override + public {{resourceName}} {{vendorExtensions.x-common-action-method}}(final TwilioRestClient client) { + {{>common/generateUri}} + + Request request = new Request( + HttpMethod.{{httpMethod}}, + Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), + path + ); + {{#vendorExtensions.x-request-content-type}} + request.setContentType(EnumConstants.ContentType.{{vendorExtensions.x-request-content-type}}); + {{/vendorExtensions.x-request-content-type}} + {{#queryParams.0}} + addQueryParams(request); + {{/queryParams.0}} + {{#headerParams.0}} + addHeaderParams(request); + {{/headerParams.0}} + {{#formParams.0}} + addPostParams(request); + {{/formParams.0}} + {{#bodyParams.0}} + addPostParams(request, client); + {{/bodyParams.0}} + + Response response = client.request(request); + + if (response == null) { + throw new ApiConnectionException("{{resourceName}} creation failed: Unable to connect to server"); + } else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestException restException = RestException.fromJson( + response.getStream(), + client.getObjectMapper() + ); + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + } + + return {{resourceName}}.fromJson(response.getStream(), client.getObjectMapper()); + } \ No newline at end of file diff --git a/src/main/resources/twilio-java/common/setters.mustache b/src/main/resources/twilio-java/common/setters.mustache new file mode 100644 index 000000000..b52f1e769 --- /dev/null +++ b/src/main/resources/twilio-java/common/setters.mustache @@ -0,0 +1,20 @@ +{{#vendorExtensions.x-setter-methods}} + +public {{resourceName}}{{vendorExtensions.x-common-action-type}} set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ + this.{{paramName}} = {{paramName}}; + return this; +} + +{{! Optional setter-- Ideally this shouldn't exists, keeping it for backward compatibility }} +{{#isArray}} +public {{resourceName}}{{vendorExtensions.x-common-action-type}} set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); +} +{{/isArray}} +{{! Optional setter, vendorExtensions.x-promotion stores promotion method}} +{{#vendorExtensions.x-promotion}} +public {{resourceName}}{{vendorExtensions.x-common-action-type}} set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final String {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{vendorExtensions.x-promotion}}); +} +{{/vendorExtensions.x-promotion}} +{{/vendorExtensions.x-setter-methods}} \ No newline at end of file diff --git a/src/main/resources/twilio-java/creator.mustache b/src/main/resources/twilio-java/creator.mustache index 1c19dac2e..521f180c0 100644 --- a/src/main/resources/twilio-java/creator.mustache +++ b/src/main/resources/twilio-java/creator.mustache @@ -2,135 +2,29 @@ {{#resources}} package com.twilio.rest.{{domainPackage}}.{{apiVersion}}{{namespaceSubPart}}; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.twilio.constant.EnumConstants; -import com.twilio.converter.Promoter; -import com.twilio.exception.ApiConnectionException; -import com.twilio.converter.PrefixedCollapsibleMap; -import com.twilio.converter.Converter; -import com.twilio.exception.ApiException; -import com.twilio.exception.RestException; -import com.twilio.http.HttpMethod; -import com.twilio.http.Response; -import com.twilio.rest.Domains; -import java.math.BigDecimal; -import java.util.List; -import java.util.Map; -import java.time.LocalDate; -import com.twilio.converter.Converter; -import java.time.ZonedDateTime; -import java.io.IOException; -import java.io.InputStream; -import java.math.BigDecimal; -import java.net.URI; -import java.time.format.DateTimeFormatter; -import com.twilio.converter.DateConverter; - -{{^fullJavaUtil}} -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; -{{/fullJavaUtil}} - -import lombok.ToString; - -import java.net.URI; - -{{#apiOperations}} -{{#vendorExtensions.x-is-create-operation}} -import com.twilio.base{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.Creator; -import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request; -import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient; - -public class {{apiName}}Creator extends Creator<{{apiName}}>{ -{{#allParams}} - private {{{dataType}}} {{paramName}}; -{{/allParams}} - -{{#vendorExtensions.x-signature-list}} - public {{apiName}}Creator({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}) { - {{#.}} - this.{{paramName}} = {{paramName}}; - {{/.}} - } -{{/vendorExtensions.x-signature-list}} - -{{#vendorExtensions.x-non-path-params}} - public {{apiName}}Creator set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ - this.{{paramName}} = {{paramName}}; - return this; - } -{{#isArray}} - public {{apiName}}Creator set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ - return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); - } -{{/isArray}} -{{#vendorExtensions.x-promotions}} -{{#entrySet}} - - public {{apiName}}Creator set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{#lambda.titlecase}}{{key}}{{/lambda.titlecase}} {{paramName}}){ - return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{value}}); - } -{{/entrySet}} -{{/vendorExtensions.x-promotions}} -{{/vendorExtensions.x-non-path-params}} - - @Override - public {{apiName}} create(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client){ -{{>generate_uri}} - {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( - {{vendorExtensions.x-http-method}}, - Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), - path - ); - {{#queryParams.0}} - addQueryParams(request); - {{/queryParams.0}} - {{^vendorExtensions.x-is-json}} - request.setContentType(EnumConstants.ContentType.FORM_URLENCODED); - {{/vendorExtensions.x-is-json}} - {{#vendorExtensions.x-is-json}} - request.setContentType(EnumConstants.ContentType.JSON); - {{/vendorExtensions.x-is-json}} - {{#formParams.0}} - addPostParams(request); - {{/formParams.0}} - {{#bodyParams.0}} - addPostParams(request, client); - {{/bodyParams.0}} - {{#headerParams.0}} - addHeaderParams(request); - {{/headerParams.0}} - Response response = client.request(request); - if (response == null) { - throw new ApiConnectionException("{{apiName}} creation failed: Unable to connect to server"); - } else if (!{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient.SUCCESS.test(response.getStatusCode())) { - RestException restException = RestException.fromJson(response.getStream(), client.getObjectMapper()); - if (restException == null) { - throw new ApiException("Server Error, no content", response.getStatusCode()); - } - throw new ApiException(restException); - } - - return {{apiName}}.fromJson(response.getStream(), client.getObjectMapper()); - } -{{#vendorExtensions.x-has-form-params}} -{{>postParams}} -{{/vendorExtensions.x-has-form-params}} -{{#vendorExtensions.x-has-body-params}} -{{>postParams_body}} -{{/vendorExtensions.x-has-body-params}} -{{#vendorExtensions.x-has-header-params}} -{{>headerParams}} -{{/vendorExtensions.x-has-header-params}} -{{#vendorExtensions.x-has-query-params}} - private void addQueryParams(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request) { -{{>queryParams}} } -{{/vendorExtensions.x-has-query-params}} +{{>common/imports}} + +{{#operations}} +{{#vendorExtensions.x-create-operation}} +public class {{resourceName}}Creator extends Creator<{{resourceName}}> { + +{{>common/instanceVariables}} +{{>common/constructors}} +{{>creator/setters}} +{{>creator/operationMethod}} +{{#queryParams.0}} + {{>common/addQueryParams}} +{{/queryParams.0}} +{{#formParams.0}} + {{>common/addPostParams}} +{{/formParams.0}} +{{#headerParams.0}} + {{>common/addHeaderParams}} +{{/headerParams.0}} +{{#bodyParams.0}} + {{>common/addPostParamsJson}} +{{/bodyParams.0}} } -{{/vendorExtensions.x-is-create-operation}} -{{/apiOperations}} -{{/resources}} +{{/vendorExtensions.x-create-operation}} +{{/operations}} +{{/resources}} \ No newline at end of file diff --git a/src/main/resources/twilio-java/creator/operationMethod.mustache b/src/main/resources/twilio-java/creator/operationMethod.mustache new file mode 100644 index 000000000..32496cede --- /dev/null +++ b/src/main/resources/twilio-java/creator/operationMethod.mustache @@ -0,0 +1,54 @@ +{{! +resourceName: Api Name as identified by Directory Structure service +x-common-action-method: used to define operation method and can have values: create, read, update, delete, fetch + Example: https://github.com/twilio/twilio-java/blob/9c2ba4dbc185c5576e67fbeb82ec6f4899093e79/src/main/java/com/twilio/rest/api/v2010/account/MessageCreator.java#L309 + +httpMethod: http method associated in the current operation. +domainName: example api, video, chat, etc. These can be found in Domains.java in twilio-java +vendorExtensions.x-content-type: content type of the request, example: application/json, application/x-www-form-urlencoded +}} + @Override + public {{resourceName}} {{vendorExtensions.x-common-action-method}}(final TwilioRestClient client) { + {{>common/generateUri}} + + Request request = new Request( + HttpMethod.{{httpMethod}}, + Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), + path + ); + {{#vendorExtensions.x-request-content-type}} + request.setContentType(EnumConstants.ContentType.{{vendorExtensions.x-request-content-type}}); + {{/vendorExtensions.x-request-content-type}} + {{#vendorExtensions.x-no-auth}} + request.setAuth(NoAuthStrategy.getInstance()); + {{/vendorExtensions.x-no-auth}} + {{#queryParams.0}} + addQueryParams(request); + {{/queryParams.0}} + {{#headerParams.0}} + addHeaderParams(request); + {{/headerParams.0}} + {{#formParams.0}} + addPostParams(request); + {{/formParams.0}} + {{#bodyParams.0}} + addPostParams(request, client); + {{/bodyParams.0}} + + Response response = client.request(request); + + if (response == null) { + throw new ApiConnectionException("{{resourceName}} creation failed: Unable to connect to server"); + } else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestException restException = RestException.fromJson( + response.getStream(), + client.getObjectMapper() + ); + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + } + + return {{resourceName}}.fromJson(response.getStream(), client.getObjectMapper()); + } \ No newline at end of file diff --git a/src/main/resources/twilio-java/creator/setters.mustache b/src/main/resources/twilio-java/creator/setters.mustache new file mode 100644 index 000000000..841e0e79d --- /dev/null +++ b/src/main/resources/twilio-java/creator/setters.mustache @@ -0,0 +1,20 @@ +{{#vendorExtensions.x-setter-methods}} + +public {{resourceName}}Creator set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ + this.{{paramName}} = {{paramName}}; + return this; +} + +{{! Optional setter-- Ideally this shouldn't exists, keeping it for backward compatibility }} +{{#isArray}} +public {{resourceName}}Creator set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); +} +{{/isArray}} +{{! Optional setter, vendorExtensions.x-promotion stores promotion method}} +{{#vendorExtensions.x-promotion}} +public {{resourceName}}Creator set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final String {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{vendorExtensions.x-promotion}}); +} +{{/vendorExtensions.x-promotion}} +{{/vendorExtensions.x-setter-methods}} \ No newline at end of file diff --git a/src/main/resources/twilio-java/deleter.mustache b/src/main/resources/twilio-java/deleter.mustache index 082c5df14..e4cdeb330 100644 --- a/src/main/resources/twilio-java/deleter.mustache +++ b/src/main/resources/twilio-java/deleter.mustache @@ -1,129 +1,23 @@ {{>licenseInfo}} {{#resources}} package com.twilio.rest.{{domainPackage}}.{{apiVersion}}{{namespaceSubPart}}; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.twilio.converter.Promoter; -import com.twilio.constant.EnumConstants; -import com.twilio.exception.ApiConnectionException; -import com.twilio.converter.PrefixedCollapsibleMap; -import com.twilio.exception.ApiException; -import com.twilio.converter.Converter; -import com.twilio.exception.RestException; -import com.twilio.http.HttpMethod; -import com.twilio.http.Response; -import com.twilio.rest.Domains; -import java.time.LocalDate; -import java.io.IOException; -import java.io.InputStream; -import java.math.BigDecimal; -import java.net.URI; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import com.twilio.converter.DateConverter; - -{{^fullJavaUtil}} -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -{{/fullJavaUtil}} - -import lombok.ToString; - -{{#apiOperations}} -{{#vendorExtensions.x-is-delete-operation}} -import com.twilio.base{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.Deleter; -import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request; -import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient; - -public class {{apiName}}Deleter extends Deleter<{{apiName}}> { -{{#allParams}} - private {{{dataType}}} {{paramName}}; -{{/allParams}} - -{{#vendorExtensions.x-signature-list}} - public {{apiName}}Deleter({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}){ - {{#.}} - this.{{paramName}} = {{paramName}}; - {{/.}} - } -{{/vendorExtensions.x-signature-list}} - -{{#vendorExtensions.x-non-path-params}} - public {{apiName}}Deleter set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ - this.{{paramName}} = {{paramName}}; - return this; - } -{{#isArray}} - public {{apiName}}Deleter set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ - return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); - } -{{/isArray}} -{{#vendorExtensions.x-promotions}} -{{#entrySet}} - - public {{apiName}}Deleter set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{#lambda.titlecase}}{{key}}{{/lambda.titlecase}} {{paramName}}){ - return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{value}}); - } -{{/entrySet}} -{{/vendorExtensions.x-promotions}} -{{/vendorExtensions.x-non-path-params}} - - @Override - public boolean delete(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client) { -{{>generate_uri}} - {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( - {{vendorExtensions.x-http-method}}, - Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), - path - ); - {{#queryParams.0}} - addQueryParams(request); - {{/queryParams.0}} - {{^vendorExtensions.x-is-json}} - request.setContentType(EnumConstants.ContentType.FORM_URLENCODED); - {{/vendorExtensions.x-is-json}} - {{#vendorExtensions.x-is-json}} - request.setContentType(EnumConstants.ContentType.JSON); - {{/vendorExtensions.x-is-json}} - {{#formParams.0}} - addPostParams(request); - {{/formParams.0}} - {{#bodyParams.0}} - addPostParams(request, client); - {{/bodyParams.0}} - {{#headerParams.0}} - addHeaderParams(request); - {{/headerParams.0}} - Response response = client.request(request); - - if (response == null) { - throw new ApiConnectionException("{{apiName}} delete failed: Unable to connect to server"); - } else if (!{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient.SUCCESS.test(response.getStatusCode())) { - RestException restException = RestException.fromJson(response.getStream(), client.getObjectMapper()); - if (restException == null) { - throw new ApiException("Server Error, no content", response.getStatusCode()); +{{>common/imports}} + + {{#operations}} + {{#vendorExtensions.x-delete-operation}} + public class {{resourceName}}Deleter extends Deleter<{{resourceName}}> { + + {{>common/instanceVariables}} + {{>common/constructors}} + {{>deleter/setters}} + {{>deleter/operationMethod}} + {{#queryParams.0}} + {{>common/addQueryParams}} + {{/queryParams.0}} + {{#headerParams.0}} + {{>common/addHeaderParams}} + {{/headerParams.0}} } - throw new ApiException(restException); - } - return response.getStatusCode() == 204; - } -{{#vendorExtensions.x-has-form-params}} -{{>postParams}} -{{/vendorExtensions.x-has-form-params}} -{{#vendorExtensions.x-has-body-params}} -{{>postParams_body}} -{{/vendorExtensions.x-has-body-params}} -{{#vendorExtensions.x-has-header-params}} -{{>headerParams}} -{{/vendorExtensions.x-has-header-params}} -{{#vendorExtensions.x-has-query-params}} - private void addQueryParams(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request) { -{{>queryParams}} } -{{/vendorExtensions.x-has-query-params}} -} -{{/vendorExtensions.x-is-delete-operation}} -{{/apiOperations}} -{{/resources}} + {{/vendorExtensions.x-delete-operation}} + {{/operations}} +{{/resources}} \ No newline at end of file diff --git a/src/main/resources/twilio-java/deleter/operationMethod.mustache b/src/main/resources/twilio-java/deleter/operationMethod.mustache new file mode 100644 index 000000000..ba98e2ba1 --- /dev/null +++ b/src/main/resources/twilio-java/deleter/operationMethod.mustache @@ -0,0 +1,47 @@ +{{! +resourceName: Api Name as identified by Directory Structure service +x-common-action-method: used to define operation method and can have values: create, read, update, delete, fetch + Example: https://github.com/twilio/twilio-java/blob/9c2ba4dbc185c5576e67fbeb82ec6f4899093e79/src/main/java/com/twilio/rest/api/v2010/account/MessageCreator.java#L309 + +httpMethod: http method associated in the current operation. +domainName: example api, video, chat, etc. These can be found in Domains.java in twilio-java +vendorExtensions.x-content-type: content type of the request, example: application/json, application/x-www-form-urlencoded +}} + @Override + public boolean delete(final TwilioRestClient client) { + {{>common/generateUri}} + + Request request = new Request( + HttpMethod.{{httpMethod}}, + Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), + path + ); + {{#vendorExtensions.x-request-content-type}} + request.setContentType(EnumConstants.ContentType.{{vendorExtensions.x-request-content-type}}); + {{/vendorExtensions.x-request-content-type}} + {{#vendorExtensions.x-no-auth}} + request.setAuth(NoAuthStrategy.getInstance()); + {{/vendorExtensions.x-no-auth}} + {{#queryParams.0}} + addQueryParams(request); + {{/queryParams.0}} + {{#headerParams.0}} + addHeaderParams(request); + {{/headerParams.0}} + + Response response = client.request(request); + + if (response == null) { + throw new ApiConnectionException("{{resourceName}} delete failed: Unable to connect to server"); + } else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestException restException = RestException.fromJson( + response.getStream(), + client.getObjectMapper() + ); + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + } + return response.getStatusCode() == 204; + } \ No newline at end of file diff --git a/src/main/resources/twilio-java/deleter/setters.mustache b/src/main/resources/twilio-java/deleter/setters.mustache new file mode 100644 index 000000000..a40899655 --- /dev/null +++ b/src/main/resources/twilio-java/deleter/setters.mustache @@ -0,0 +1,20 @@ +{{#vendorExtensions.x-setter-methods}} + +public {{resourceName}}Deleter set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ + this.{{paramName}} = {{paramName}}; + return this; +} + +{{! Optional setter-- Ideally this shouldn't exists, keeping it for backward compatibility }} +{{#isArray}} +public {{resourceName}}Deleter set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); +} +{{/isArray}} +{{! Optional setter, vendorExtensions.x-promotion stores promotion method}} +{{#vendorExtensions.x-promotion}} +public {{resourceName}}Deleter set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final String {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{vendorExtensions.x-promotion}}); +} +{{/vendorExtensions.x-promotion}} +{{/vendorExtensions.x-setter-methods}} \ No newline at end of file diff --git a/src/main/resources/twilio-java/enums.mustache b/src/main/resources/twilio-java/enums.mustache index 43c17f9fa..6e13ae918 100644 --- a/src/main/resources/twilio-java/enums.mustache +++ b/src/main/resources/twilio-java/enums.mustache @@ -1,24 +1,22 @@ -{{#enums}} - public enum {{#lambda.titlecase}}{{{enumName}}}{{/lambda.titlecase}} { - {{#allowableValues}} - {{#values}} - {{#lambda.uppercase}}{{#lambda.replacehyphen}}{{{.}}}{{/lambda.replacehyphen}}({{/lambda.uppercase}}"{{{.}}}"){{^-last}},{{/-last}}{{#-last}};{{/-last}} - {{/values}} - {{/allowableValues}} +{{#mustacheEnums}} +public enum {{className}} { +{{#enumValues}} + {{name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}} +{{/enumValues}} - private final String value; + private final String value; - private {{#lambda.titlecase}}{{{enumName}}}{{/lambda.titlecase}}(final String value) { + private {{className}}(final String value) { this.value = value; - } + } - public String toString() { - return value; - } + public String toString() { + return value; + } - @JsonCreator - public static {{#lambda.titlecase}}{{{enumName}}}{{/lambda.titlecase}} forValue(final String value) { - return Promoter.enumFromString(value, {{#lambda.titlecase}}{{{enumName}}}{{/lambda.titlecase}}.values()); - } + @JsonCreator + public static {{className}} forValue(final String value) { + return Promoter.enumFromString(value, {{className}}.values()); } -{{/enums}} \ No newline at end of file +} +{{/mustacheEnums}} \ No newline at end of file diff --git a/src/main/resources/twilio-java/equalsAndHashcode.mustache b/src/main/resources/twilio-java/equalsAndHashcode.mustache new file mode 100644 index 000000000..88548827b --- /dev/null +++ b/src/main/resources/twilio-java/equalsAndHashcode.mustache @@ -0,0 +1,26 @@ +@Override +public boolean equals(final Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + {{resourceName}} other = ({{resourceName}}) o; + return ( + {{#response}} + Objects.equals({{name}}, other.{{name}}){{^-last}} && {{/-last}} + {{/response}} + ); +} + +@Override +public int hashCode() { + return Objects.hash( + {{#response}} + {{name}}{{^-last}}, {{/-last}} + {{/response}} + ); +} diff --git a/src/main/resources/twilio-java/fetcher.mustache b/src/main/resources/twilio-java/fetcher.mustache index 34be9003b..1c0280c97 100644 --- a/src/main/resources/twilio-java/fetcher.mustache +++ b/src/main/resources/twilio-java/fetcher.mustache @@ -1,131 +1,23 @@ {{>licenseInfo}} {{#resources}} package com.twilio.rest.{{domainPackage}}.{{apiVersion}}{{namespaceSubPart}}; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.twilio.constant.EnumConstants; -import com.twilio.converter.Promoter; -import com.twilio.exception.ApiConnectionException; -import com.twilio.converter.PrefixedCollapsibleMap; -import com.twilio.converter.Converter; -import com.twilio.exception.ApiException; -import com.twilio.exception.RestException; -import com.twilio.http.HttpMethod; -import com.twilio.http.Response; -import com.twilio.rest.Domains; - -import java.io.IOException; -import java.io.InputStream; -import java.math.BigDecimal; -import java.net.URI; -import java.time.ZonedDateTime; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import com.twilio.converter.DateConverter; - -{{^fullJavaUtil}} -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -{{/fullJavaUtil}} - -import lombok.ToString; - -{{#apiOperations}} -{{#vendorExtensions.x-is-fetch-operation}} -import com.twilio.base{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.Fetcher; -import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request; -import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient; - -public class {{apiName}}Fetcher extends Fetcher<{{apiName}}> { -{{#allParams}} - private {{{dataType}}} {{paramName}}; -{{/allParams}} - -{{#vendorExtensions.x-signature-list}} - public {{apiName}}Fetcher({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}){ - {{#.}} - this.{{paramName}} = {{paramName}}; - {{/.}} - } -{{/vendorExtensions.x-signature-list}} - -{{#vendorExtensions.x-non-path-params}} - public {{apiName}}Fetcher set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ - this.{{paramName}} = {{paramName}}; - return this; - } -{{#isArray}} - public {{apiName}}Fetcher set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ - return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); - } -{{/isArray}} -{{#vendorExtensions.x-promotions}} -{{#entrySet}} - - public {{apiName}}Fetcher set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{#lambda.titlecase}}{{key}}{{/lambda.titlecase}} {{paramName}}){ - return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{value}}); - } -{{/entrySet}} -{{/vendorExtensions.x-promotions}} -{{/vendorExtensions.x-non-path-params}} - - @Override - public {{apiName}} fetch(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client) { -{{>generate_uri}} - {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( - {{vendorExtensions.x-http-method}}, - Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), - path - ); - {{#queryParams.0}} - addQueryParams(request); - {{/queryParams.0}} - {{^vendorExtensions.x-is-json}} - request.setContentType(EnumConstants.ContentType.FORM_URLENCODED); - {{/vendorExtensions.x-is-json}} - {{#vendorExtensions.x-is-json}} - request.setContentType(EnumConstants.ContentType.JSON); - {{/vendorExtensions.x-is-json}} - {{#formParams.0}} - addPostParams(request); - {{/formParams.0}} - {{#bodyParams.0}} - addPostParams(request, client); - {{/bodyParams.0}} - {{#headerParams.0}} - addHeaderParams(request); - {{/headerParams.0}} - Response response = client.request(request); - - if (response == null) { - throw new ApiConnectionException("{{apiName}} fetch failed: Unable to connect to server"); - } else if (!{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient.SUCCESS.test(response.getStatusCode())) { - RestException restException = RestException.fromJson(response.getStream(), client.getObjectMapper()); - if (restException == null) { - throw new ApiException("Server Error, no content", response.getStatusCode()); - } - throw new ApiException(restException); - } - - return {{apiName}}.fromJson(response.getStream(), client.getObjectMapper()); +{{>common/imports}} + +{{#operations}} +{{#vendorExtensions.x-fetch-operation}} + public class {{resourceName}}Fetcher extends Fetcher<{{resourceName}}> { + + {{>common/instanceVariables}} + {{>common/constructors}} + {{>fetcher/setters}} + {{>fetcher/operationMethod}} + {{#queryParams.0}} + {{>common/addQueryParams}} + {{/queryParams.0}} + {{#headerParams.0}} + {{>common/addHeaderParams}} + {{/headerParams.0}} } -{{#vendorExtensions.x-has-form-params}} -{{>postParams}} -{{/vendorExtensions.x-has-form-params}} -{{#vendorExtensions.x-has-body-params}} -{{>postParams_body}} -{{/vendorExtensions.x-has-body-params}} -{{#vendorExtensions.x-has-header-params}} -{{>headerParams}} -{{/vendorExtensions.x-has-header-params}} -{{#vendorExtensions.x-has-query-params}} - private void addQueryParams(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request) { -{{>queryParams}} } -{{/vendorExtensions.x-has-query-params}} -} -{{/vendorExtensions.x-is-fetch-operation}} -{{/apiOperations}} -{{/resources}} +{{/vendorExtensions.x-fetch-operation}} +{{/operations}} +{{/resources}} \ No newline at end of file diff --git a/src/main/resources/twilio-java/fetcher/operationMethod.mustache b/src/main/resources/twilio-java/fetcher/operationMethod.mustache new file mode 100644 index 000000000..8ead0de7b --- /dev/null +++ b/src/main/resources/twilio-java/fetcher/operationMethod.mustache @@ -0,0 +1,47 @@ +{{! +resourceName: Api Name as identified by Directory Structure service +x-common-action-method: used to define operation method and can have values: create, read, update, delete, fetch + Example: https://github.com/twilio/twilio-java/blob/9c2ba4dbc185c5576e67fbeb82ec6f4899093e79/src/main/java/com/twilio/rest/api/v2010/account/MessageCreator.java#L309 + +httpMethod: http method associated in the current operation. +domainName: example api, video, chat, etc. These can be found in Domains.java in twilio-java +vendorExtensions.x-content-type: content type of the request, example: application/json, application/x-www-form-urlencoded +}} + @Override + public {{resourceName}} fetch(final TwilioRestClient client) { + {{>common/generateUri}} + + Request request = new Request( + HttpMethod.{{httpMethod}}, + Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), + path + ); + {{#vendorExtensions.x-request-content-type}} + request.setContentType(EnumConstants.ContentType.{{vendorExtensions.x-request-content-type}}); + {{/vendorExtensions.x-request-content-type}} + {{#vendorExtensions.x-no-auth}} + request.setAuth(NoAuthStrategy.getInstance()); + {{/vendorExtensions.x-no-auth}} + {{#queryParams.0}} + addQueryParams(request); + {{/queryParams.0}} + {{#headerParams.0}} + addHeaderParams(request); + {{/headerParams.0}} + + Response response = client.request(request); + + if (response == null) { + throw new ApiConnectionException("{{resourceName}} fetch failed: Unable to connect to server"); + } else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestException restException = RestException.fromJson( + response.getStream(), + client.getObjectMapper() + ); + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + } + return {{resourceName}}.fromJson(response.getStream(), client.getObjectMapper()); + } \ No newline at end of file diff --git a/src/main/resources/twilio-java/fetcher/setters.mustache b/src/main/resources/twilio-java/fetcher/setters.mustache new file mode 100644 index 000000000..f7134c7d3 --- /dev/null +++ b/src/main/resources/twilio-java/fetcher/setters.mustache @@ -0,0 +1,20 @@ +{{#vendorExtensions.x-setter-methods}} + +public {{resourceName}}Fetcher set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ + this.{{paramName}} = {{paramName}}; + return this; +} + +{{! Optional setter-- Ideally this shouldn't exists, keeping it for backward compatibility }} +{{#isArray}} +public {{resourceName}}Fetcher set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); +} +{{/isArray}} +{{! Optional setter, vendorExtensions.x-promotion stores promotion method}} +{{#vendorExtensions.x-promotion}} +public {{resourceName}}Fetcher set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final String {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{vendorExtensions.x-promotion}}); +} +{{/vendorExtensions.x-promotion}} +{{/vendorExtensions.x-setter-methods}} \ No newline at end of file diff --git a/src/main/resources/twilio-java/modelEqualsAndHashCode.mustache b/src/main/resources/twilio-java/modelEqualsAndHashCode.mustache new file mode 100644 index 000000000..7a8c4d8fa --- /dev/null +++ b/src/main/resources/twilio-java/modelEqualsAndHashCode.mustache @@ -0,0 +1,27 @@ + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + {{className}} other = ({{className}}) o; + return ( + {{#allProperties}} + Objects.equals({{name}}, other.{{name}}){{^-last}} && {{/-last}} + {{/allProperties}} + ); + } + + @Override + public int hashCode() { + return Objects.hash( + {{#allProperties}} + {{name}}{{^-last}}, {{/-last}} + {{/allProperties}} + ); + } diff --git a/src/main/resources/twilio-java/models.mustache b/src/main/resources/twilio-java/models.mustache index a95788f86..86470737b 100644 --- a/src/main/resources/twilio-java/models.mustache +++ b/src/main/resources/twilio-java/models.mustache @@ -1,41 +1,73 @@ +{{#mustacheModels}} - {{#resources.nestedModels}} - @ToString - static public class {{classname}} { - {{#vars}} + @JsonDeserialize(builder = {{className}}.Builder.class) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + @ToString +{{!@Builder}} + public static class {{className}} { + + {{#allProperties}} + {{#vendorExtensions.x-deserializer}} + @JsonDeserialize(using = {{vendorExtensions.x-deserializer}}.class) + {{/vendorExtensions.x-deserializer}} + @JsonInclude(JsonInclude.Include.NON_EMPTY) + @JsonProperty("{{{baseName}}}") + @Getter private final {{{dataType}}} {{name}}; + + {{/allProperties}} + + private {{className}}(Builder builder) { + {{#allProperties}} + this.{{name}} = builder.{{name}}; + {{/allProperties}} + } + public static Builder builder({{#mandatoryProperties}} final {{{dataType}}} {{name}}{{^-last}}, {{/-last}} {{/mandatoryProperties}}) { + return new Builder({{#mandatoryProperties}} {{name}}{{^-last}}, {{/-last}} {{/mandatoryProperties}}); + } + + public static {{className}} fromJson(String jsonString, ObjectMapper mapper) throws IOException { + return mapper.readValue(jsonString, {{className}}.class); + } + + @JsonPOJOBuilder(withPrefix = "") + public static class Builder { + {{#allProperties}} + {{#vendorExtensions.x-deserializer}} + @JsonDeserialize(using = {{vendorExtensions.x-deserializer}}.class) + {{/vendorExtensions.x-deserializer}} + @JsonProperty("{{{baseName}}}") + private {{{dataType}}} {{name}}; + + {{/allProperties}} + + {{#mandatoryProperties.0}} + @JsonCreator + public Builder({{#mandatoryProperties}} @JsonProperty("{{{baseName}}}") final {{{dataType}}} {{name}}{{^-last}}, {{/-last}} {{/mandatoryProperties}}) { + {{#mandatoryProperties}} + this.{{name}} = {{name}}; + {{/mandatoryProperties}} + } + {{/mandatoryProperties.0}} + + {{#optionalProperties}} + {{#vendorExtensions.x-deserializer}} + @JsonDeserialize(using = {{vendorExtensions.x-deserializer}}.class) + {{/vendorExtensions.x-deserializer}} @JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonProperty("{{{baseName}}}") - {{#vendorExtensions.x-ref-enum}} - @Getter @Setter private {{{datatypeWithEnum}}} {{name}}; - {{/vendorExtensions.x-ref-enum}} - {{^vendorExtensions.x-ref-enum}} - @Getter @Setter private {{{dataType}}} {{name}}; - {{/vendorExtensions.x-ref-enum}} - {{^isMap}} - {{^isFreeFormObject}} - {{^isAnyType}} - {{#vendorExtensions.x-serialize}} - public String get{{#lambda.titlecase}}{{name}}{{/lambda.titlecase}}() { - return {{vendorExtensions.x-serialize}}; - }{{/vendorExtensions.x-serialize}} - {{/isAnyType}} - {{/isFreeFormObject}} - {{/isMap}} - {{/vars}} - {{#vendorExtensions.x-constructor-required}} - {{#vendorExtensions.x-model-parameters}} - public {{classname}}({{#.}}final {{{dataType}}} {{name}}{{^-last}}, {{/-last}}{{/.}} ) { - {{#.}} + public Builder {{name}}({{{dataType}}} {{name}}) { this.{{name}} = {{name}}; - {{/.}} + return this; } - {{/vendorExtensions.x-model-parameters}} - {{/vendorExtensions.x-constructor-required}} + {{/optionalProperties}} - {{^vendorExtensions.x-response}} - public static {{classname}} fromJson(String jsonString, ObjectMapper mapper) throws IOException { - return mapper.readValue(jsonString, {{classname}}.class); - } - {{/vendorExtensions.x-response}} + public {{className}} build() { + return new {{className}}(this); } - {{/resources.nestedModels}} + } + {{>modelEqualsAndHashCode}} +{{! @JsonPOJOBuilder(withPrefix = "") +public static class Builder {}} + } + +{{/mustacheModels}} diff --git a/src/main/resources/twilio-java/reader.mustache b/src/main/resources/twilio-java/reader.mustache index 0297987bd..74ae0f226 100644 --- a/src/main/resources/twilio-java/reader.mustache +++ b/src/main/resources/twilio-java/reader.mustache @@ -1,186 +1,25 @@ {{>licenseInfo}} {{#resources}} package com.twilio.rest.{{domainPackage}}.{{apiVersion}}{{namespaceSubPart}}; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.twilio.constant.EnumConstants; -import com.twilio.converter.Promoter; -import com.twilio.exception.ApiConnectionException; -import com.twilio.converter.PrefixedCollapsibleMap; -import com.twilio.converter.Converter; -import com.twilio.exception.ApiException; -import com.twilio.exception.RestException; -import com.twilio.http.HttpMethod; -import com.twilio.http.Response; -import com.twilio.rest.Domains; -import java.time.LocalDate; -import java.time.ZonedDateTime; -import java.io.IOException; -import java.io.InputStream; -import java.math.BigDecimal; -import java.net.URI; -import java.time.format.DateTimeFormatter; -import com.twilio.converter.DateConverter; - -{{^fullJavaUtil}} -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -{{/fullJavaUtil}} - -import lombok.ToString; - -{{#apiOperations}} -{{#vendorExtensions.x-is-read-operation}} -import com.twilio.base{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.Page; -import com.twilio.base{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.Reader; -import com.twilio.base{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.ResourceSet; -import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request; -import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient; - -public class {{apiName}}Reader extends Reader<{{apiName}}> { -{{#allParams}} - private {{{dataType}}} {{paramName}}; -{{/allParams}} - -{{#vendorExtensions.x-signature-list}} - public {{apiName}}Reader({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}){ - {{#.}} - this.{{paramName}} = {{paramName}}; - {{/.}} - } -{{/vendorExtensions.x-signature-list}} - -{{#vendorExtensions.x-non-path-params}} - public {{apiName}}Reader set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ - this.{{paramName}} = {{paramName}}; - return this; - } -{{#isArray}} - public {{apiName}}Reader set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ - return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); - } -{{/isArray}} -{{#vendorExtensions.x-promotions}} -{{#entrySet}} - - public {{apiName}}Reader set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{#lambda.titlecase}}{{key}}{{/lambda.titlecase}} {{paramName}}){ - return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{value}}); - } -{{/entrySet}} -{{/vendorExtensions.x-promotions}} -{{/vendorExtensions.x-non-path-params}} - - @Override - public ResourceSet<{{apiName}}> read(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client) { - return new ResourceSet<>(this, client, firstPage(client)); - } - - public Page<{{apiName}}> firstPage(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client) { - String path = "{{{path}}}"; - {{#allParams}} - {{#vendorExtensions.x-is-account-sid}} - this.{{paramName}} = this.{{paramName}} == null ? client.getAccountSid() : this.{{paramName}}; - path = path.replace("{"+"{{baseName}}"+"}", this.{{paramName}}.toString()); - {{/vendorExtensions.x-is-account-sid}} - {{/allParams}} - {{#requiredParams}} - path = path.replace("{"+"{{baseName}}"+"}", this.{{paramName}}.toString()); - {{/requiredParams}} - - {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( - {{vendorExtensions.x-http-method}}, - Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), - path - ); - - {{#queryParams.0}} - addQueryParams(request); - {{/queryParams.0}} - {{^vendorExtensions.x-is-json}} - request.setContentType(EnumConstants.ContentType.FORM_URLENCODED); - {{/vendorExtensions.x-is-json}} - {{#vendorExtensions.x-is-json}} - request.setContentType(EnumConstants.ContentType.JSON); - {{/vendorExtensions.x-is-json}} - {{#formParams.0}} - addPostParams(request); - {{/formParams.0}} - {{#bodyParams.0}} - addPostParams(request, client); - {{/bodyParams.0}} - {{#headerParams.0}} - addHeaderParams(request); - {{/headerParams.0}} - return pageForRequest(client, request); - } - - private Page<{{apiName}}> pageForRequest(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client, final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request) { - Response response = client.request(request); - - if (response == null) { - throw new ApiConnectionException("{{apiName}} read failed: Unable to connect to server"); - } else if (!{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient.SUCCESS.test(response.getStatusCode())) { - RestException restException = RestException.fromJson(response.getStream(), client.getObjectMapper()); - if (restException == null) { - throw new ApiException("Server Error, no content", response.getStatusCode()); - } - throw new ApiException(restException); - } - - return Page.fromJson( - "{{recordKey}}", - response.getContent(), - {{apiName}}.class, - client.getObjectMapper() - ); - } - - @Override - public Page<{{apiName}}> previousPage(final Page<{{apiName}}> page, final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client) { - {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( - {{vendorExtensions.x-http-method}}, - page.getPreviousPageUrl(Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString()) - ); - return pageForRequest(client, request); - } - - - @Override - public Page<{{apiName}}> nextPage(final Page<{{apiName}}> page, final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client) { - {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( - {{vendorExtensions.x-http-method}}, - page.getNextPageUrl(Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString()) - ); - return pageForRequest(client, request); - } - - @Override - public Page<{{apiName}}> getPage(final String targetUrl, final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client) { - {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( - HttpMethod.GET, - targetUrl - ); - - return pageForRequest(client, request); - } -{{#vendorExtensions.x-has-form-params}} -{{>postParams}} -{{/vendorExtensions.x-has-form-params}} -{{#vendorExtensions.x-has-header-params}} -{{>headerParams}} -{{/vendorExtensions.x-has-header-params}} -{{#vendorExtensions.x-has-query-params}} - private void addQueryParams(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request) { -{{>queryParams}} - if(getPageSize() != null) { - request.addQueryParam("PageSize", Integer.toString(getPageSize())); - } - } -{{/vendorExtensions.x-has-query-params}} +{{>common/imports}} +import com.twilio.base.Page; +import com.twilio.base.ResourceSet; + +{{#operations}} +{{#vendorExtensions.x-list-operation}} +public class {{resourceName}}Reader extends Reader<{{resourceName}}> { + + {{>common/instanceVariables}} + {{>common/constructors}} + {{>reader/setters}} + {{>reader/operationMethod}} +{{#queryParams.0}} + {{>common/addQueryParams}} +{{/queryParams.0}} +{{#headerParams.0}} + {{>common/addHeaderParams}} +{{/headerParams.0}} } -{{/vendorExtensions.x-is-read-operation}} -{{/apiOperations}} -{{/resources}} +{{/vendorExtensions.x-list-operation}} +{{/operations}} +{{/resources}} \ No newline at end of file diff --git a/src/main/resources/twilio-java/reader/operationMethod.mustache b/src/main/resources/twilio-java/reader/operationMethod.mustache new file mode 100644 index 000000000..7dea9b5d8 --- /dev/null +++ b/src/main/resources/twilio-java/reader/operationMethod.mustache @@ -0,0 +1,70 @@ +{{! +resourceName: Api Name as identified by Directory Structure service +recordKey: +httpMethod: http method associated in the current operation. +domainName: example api, video, chat, etc. These can be found in Domains.java in twilio-java +}} + @Override + public ResourceSet<{{resourceName}}> read(final TwilioRestClient client) { + return new ResourceSet<>(this, client, firstPage(client)); + } + + public Page<{{resourceName}}> firstPage(final TwilioRestClient client) { + {{>common/generateUri}} + Request request = new Request( + HttpMethod.{{httpMethod}}, + Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), + path + ); + {{#vendorExtensions.x-no-auth}} + request.setAuth(NoAuthStrategy.getInstance()); + {{/vendorExtensions.x-no-auth}} + {{#queryParams.0}} + addQueryParams(request); + {{/queryParams.0}} + {{#headerParams.0}} + addHeaderParams(request); + {{/headerParams.0}} + + return pageForRequest(client, request); + } + + private Page<{{resourceName}}> pageForRequest(final TwilioRestClient client, final Request request) { + Response response = client.request(request); + if (response == null) { + throw new ApiConnectionException("{{resourceName}} read failed: Unable to connect to server"); + } else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestException restException = RestException.fromJson( + response.getStream(), + client.getObjectMapper()); + + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + } {{! end of else if }} + + return Page.fromJson( + "{{recordKey}}", + response.getContent(), + {{resourceName}}.class, + client.getObjectMapper()); + } + + @Override + public Page<{{resourceName}}> previousPage(final Page<{{resourceName}}> page, final TwilioRestClient client ) { + Request request = new Request(HttpMethod.GET, page.getPreviousPageUrl(Domains.API.toString())); + return pageForRequest(client, request); + } + + @Override + public Page<{{resourceName}}> nextPage(final Page<{{resourceName}}> page, final TwilioRestClient client) { + Request request = new Request(HttpMethod.GET, page.getNextPageUrl(Domains.API.toString())); + return pageForRequest(client, request); + } + + @Override + public Page<{{resourceName}}> getPage(final String targetUrl, final TwilioRestClient client) { + Request request = new Request(HttpMethod.GET, targetUrl); + return pageForRequest(client, request); + } \ No newline at end of file diff --git a/src/main/resources/twilio-java/reader/paginationMethods.mustache b/src/main/resources/twilio-java/reader/paginationMethods.mustache new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/resources/twilio-java/reader/setters.mustache b/src/main/resources/twilio-java/reader/setters.mustache new file mode 100644 index 000000000..749017bbd --- /dev/null +++ b/src/main/resources/twilio-java/reader/setters.mustache @@ -0,0 +1,20 @@ +{{#vendorExtensions.x-setter-methods}} + +public {{resourceName}}Reader set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ + this.{{paramName}} = {{paramName}}; + return this; +} + +{{! Optional setter-- Ideally this shouldn't exists, keeping it for backward compatibility }} +{{#isArray}} +public {{resourceName}}Reader set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); +} +{{/isArray}} +{{! Optional setter, vendorExtensions.x-promotion stores promotion method}} +{{#vendorExtensions.x-promotion}} +public {{resourceName}}Reader set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final String {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{vendorExtensions.x-promotion}}); +} +{{/vendorExtensions.x-promotion}} +{{/vendorExtensions.x-setter-methods}} \ No newline at end of file diff --git a/src/main/resources/twilio-java/response.mustache b/src/main/resources/twilio-java/response.mustache new file mode 100644 index 000000000..e13bb653c --- /dev/null +++ b/src/main/resources/twilio-java/response.mustache @@ -0,0 +1,42 @@ +{{! -- Instance variables}} +{{#responseFlag}} + + +{{#response}} + @Getter + private final {{{dataType}}} {{name}}; +{{/response}} + +{{! -- Private Constructor}} +@JsonCreator +private {{resourceName}}( +{{#response}} + @JsonProperty("{{baseName}}") +{{#vendorExtensions.x-deserializer}} + @JsonDeserialize(using = {{vendorExtensions.x-deserializer}}.class) +{{/vendorExtensions.x-deserializer}} + final {{{dataType}}} {{name}}{{^-last}}, {{/-last}} +{{/response}} +){ +{{#response}} + this.{{name}} = {{name}}; +{{/response}} +} + +{{>equalsAndHashcode}} +{{/responseFlag}} + +{{^responseFlag}} +@JsonCreator +private {{resourceName}}() {} + +@Override +public boolean equals(Object obj) { + return obj != null && obj.getClass() == this.getClass(); +} + +@Override +public int hashCode() { + return 1; +} +{{/responseFlag}} \ No newline at end of file diff --git a/src/main/resources/twilio-java/staticMethods.mustache b/src/main/resources/twilio-java/staticMethods.mustache new file mode 100644 index 000000000..b24223857 --- /dev/null +++ b/src/main/resources/twilio-java/staticMethods.mustache @@ -0,0 +1,48 @@ + /** + * Converts a JSON String into a {{resourceName}} object using the provided ObjectMapper. + * + * @param json Raw JSON String + * @param objectMapper Jackson ObjectMapper + * @return {{resourceName}} object represented by the provided JSON + */ + public static {{resourceName}} fromJson(final String json, final ObjectMapper objectMapper) { + // Convert all checked exceptions to Runtime + try { + return objectMapper.readValue(json, {{resourceName}}.class); + } catch (final JsonMappingException | JsonParseException e) { + throw new ApiException(e.getMessage(), e); + } catch (final IOException e) { + throw new ApiConnectionException(e.getMessage(), e); + } + } + + /** + * Converts a JSON InputStream into a {{resourceName}} object using the provided + * ObjectMapper. + * + * @param json Raw JSON InputStream + * @param objectMapper Jackson ObjectMapper + * @return {{resourceName}} object represented by the provided JSON + */ + public static {{resourceName}} fromJson(final InputStream json, final ObjectMapper objectMapper) { + // Convert all checked exceptions to Runtime + try { + return objectMapper.readValue(json, {{resourceName}}.class); + } catch (final JsonMappingException | JsonParseException e) { + throw new ApiException(e.getMessage(), e); + } catch (final IOException e) { + throw new ApiConnectionException(e.getMessage(), e); + } + } + + public static String toJson(Object object, ObjectMapper mapper) { + try { + return mapper.writeValueAsString(object); + } catch (final JsonMappingException e) { + throw new ApiException(e.getMessage(), e); + } catch (JsonProcessingException e) { + throw new ApiException(e.getMessage(), e); + } catch (final IOException e) { + throw new ApiConnectionException(e.getMessage(), e); + } + } \ No newline at end of file diff --git a/src/main/resources/twilio-java/updater.mustache b/src/main/resources/twilio-java/updater.mustache index d14fd7661..e447ea9f5 100644 --- a/src/main/resources/twilio-java/updater.mustache +++ b/src/main/resources/twilio-java/updater.mustache @@ -1,132 +1,28 @@ {{>licenseInfo}} {{#resources}} package com.twilio.rest.{{domainPackage}}.{{apiVersion}}{{namespaceSubPart}}; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.twilio.constant.EnumConstants; -import com.twilio.converter.Promoter; -import com.twilio.exception.ApiConnectionException; -import com.twilio.converter.PrefixedCollapsibleMap; -import com.twilio.converter.Converter; -import com.twilio.exception.ApiException; -import com.twilio.exception.RestException; -import com.twilio.http.HttpMethod; -import com.twilio.http.Response; -import com.twilio.rest.Domains; -import java.time.format.DateTimeFormatter; -import com.twilio.converter.DateConverter; - -import java.io.IOException; -import java.io.InputStream; -import java.math.BigDecimal; -import java.net.URI; -import java.time.ZonedDateTime; -import java.time.LocalDate; - -{{^fullJavaUtil}} -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -{{/fullJavaUtil}} - -import lombok.ToString; - -{{#apiOperations}} -{{#vendorExtensions.x-is-update-operation}} -import com.twilio.base{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.Updater; -import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request; -import com.twilio.http{{vendorExtensions.x-auth-attributes.x-auth-import-class}}.{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient; - - -public class {{apiName}}Updater extends Updater<{{apiName}}>{ -{{#allParams}} - private {{{dataType}}} {{paramName}}; -{{/allParams}} - -{{#vendorExtensions.x-signature-list}} - public {{apiName}}Updater({{#.}}final {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/.}}){ - {{#.}} - this.{{paramName}} = {{paramName}}; - {{/.}} +{{>common/imports}} + +{{#operations}} +{{#vendorExtensions.x-update-operation}} + public class {{resourceName}}Updater extends Updater<{{resourceName}}> { + {{>common/instanceVariables}} + {{>common/constructors}} + {{>updater/setters}} + {{>updater/operationMethod}} + {{#queryParams.0}} + {{>common/addQueryParams}} + {{/queryParams.0}} + {{#formParams.0}} + {{>common/addPostParams}} + {{/formParams.0}} + {{#headerParams.0}} + {{>common/addHeaderParams}} + {{/headerParams.0}} + {{#bodyParams.0}} + {{>common/addPostParamsJson}} + {{/bodyParams.0}} } -{{/vendorExtensions.x-signature-list}} - -{{#vendorExtensions.x-non-path-params}} - public {{apiName}}Updater set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ - this.{{paramName}} = {{paramName}}; - return this; - } -{{#isArray}} - public {{apiName}}Updater set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ - return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); - } -{{/isArray}} -{{#vendorExtensions.x-promotions}} -{{#entrySet}} - - public {{apiName}}Updater set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{#lambda.titlecase}}{{key}}{{/lambda.titlecase}} {{paramName}}){ - return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{value}}); - } -{{/entrySet}} -{{/vendorExtensions.x-promotions}} -{{/vendorExtensions.x-non-path-params}} - - @Override - public {{apiName}} update(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient client){ -{{>generate_uri}} - {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request = new {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request( - {{vendorExtensions.x-http-method}}, - Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), - path - ); - {{#queryParams.0}} - addQueryParams(request); - {{/queryParams.0}} - {{^vendorExtensions.x-is-json}} - request.setContentType(EnumConstants.ContentType.FORM_URLENCODED); - {{/vendorExtensions.x-is-json}} - {{#vendorExtensions.x-is-json}} - request.setContentType(EnumConstants.ContentType.JSON); - {{/vendorExtensions.x-is-json}} - {{#formParams.0}} - addPostParams(request); - {{/formParams.0}} - {{#bodyParams.0}} - addPostParams(request, client); - {{/bodyParams.0}} - {{#headerParams.0}} - addHeaderParams(request); - {{/headerParams.0}} - Response response = client.request(request); - if (response == null) { - throw new ApiConnectionException("{{apiName}} update failed: Unable to connect to server"); - } else if (!{{vendorExtensions.x-auth-attributes.x-http-class-prefix}}TwilioRestClient.SUCCESS.test(response.getStatusCode())) { - RestException restException = RestException.fromJson(response.getStream(), client.getObjectMapper()); - if (restException == null) { - throw new ApiException("Server Error, no content", response.getStatusCode()); - } - throw new ApiException(restException); - } - - return {{apiName}}.fromJson(response.getStream(), client.getObjectMapper()); - } - -{{#vendorExtensions.x-has-form-params}} -{{>postParams}} -{{/vendorExtensions.x-has-form-params}} -{{#vendorExtensions.x-has-body-params}} -{{>postParams_body}} -{{/vendorExtensions.x-has-body-params}} -{{#vendorExtensions.x-has-header-params}} -{{>headerParams}} -{{/vendorExtensions.x-has-header-params}} -{{#vendorExtensions.x-has-query-params}} - private void addQueryParams(final {{vendorExtensions.x-auth-attributes.x-http-class-prefix}}Request request) { -{{>queryParams}} } -{{/vendorExtensions.x-has-query-params}} -} -{{/vendorExtensions.x-is-update-operation}} -{{/apiOperations}} -{{/resources}} +{{/vendorExtensions.x-update-operation}} +{{/operations}} +{{/resources}} \ No newline at end of file diff --git a/src/main/resources/twilio-java/updater/operationMethod.mustache b/src/main/resources/twilio-java/updater/operationMethod.mustache new file mode 100644 index 000000000..6744cbbc4 --- /dev/null +++ b/src/main/resources/twilio-java/updater/operationMethod.mustache @@ -0,0 +1,54 @@ +{{! +resourceName: Api Name as identified by Directory Structure service +x-common-action-method: used to define operation method and can have values: create, read, update, delete, fetch + Example: https://github.com/twilio/twilio-java/blob/9c2ba4dbc185c5576e67fbeb82ec6f4899093e79/src/main/java/com/twilio/rest/api/v2010/account/MessageCreator.java#L309 + +httpMethod: http method associated in the current operation. +domainName: example api, video, chat, etc. These can be found in Domains.java in twilio-java +vendorExtensions.x-content-type: content type of the request, example: application/json, application/x-www-form-urlencoded +}} + @Override + public {{resourceName}} {{vendorExtensions.x-common-action-method}}(final TwilioRestClient client) { + {{>common/generateUri}} + + Request request = new Request( + HttpMethod.{{httpMethod}}, + Domains.{{#lambda.uppercase}}{{domainName}}{{/lambda.uppercase}}.toString(), + path + ); + {{#vendorExtensions.x-request-content-type}} + request.setContentType(EnumConstants.ContentType.{{vendorExtensions.x-request-content-type}}); + {{/vendorExtensions.x-request-content-type}} + {{#vendorExtensions.x-no-auth}} + request.setAuth(NoAuthStrategy.getInstance()); + {{/vendorExtensions.x-no-auth}} + {{#queryParams.0}} + addQueryParams(request); + {{/queryParams.0}} + {{#headerParams.0}} + addHeaderParams(request); + {{/headerParams.0}} + {{#formParams.0}} + addPostParams(request); + {{/formParams.0}} + {{#bodyParams.0}} + addPostParams(request, client); + {{/bodyParams.0}} + + Response response = client.request(request); + + if (response == null) { + throw new ApiConnectionException("{{resourceName}} update failed: Unable to connect to server"); + } else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) { + RestException restException = RestException.fromJson( + response.getStream(), + client.getObjectMapper() + ); + if (restException == null) { + throw new ApiException("Server Error, no content", response.getStatusCode()); + } + throw new ApiException(restException); + } + + return {{resourceName}}.fromJson(response.getStream(), client.getObjectMapper()); + } \ No newline at end of file diff --git a/src/main/resources/twilio-java/updater/setters.mustache b/src/main/resources/twilio-java/updater/setters.mustache new file mode 100644 index 000000000..fe89a495b --- /dev/null +++ b/src/main/resources/twilio-java/updater/setters.mustache @@ -0,0 +1,20 @@ +{{#vendorExtensions.x-setter-methods}} + +public {{resourceName}}Updater set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{dataType}}} {{paramName}}){ + this.{{paramName}} = {{paramName}}; + return this; +} + +{{! Optional setter-- Ideally this shouldn't exists, keeping it for backward compatibility }} +{{#isArray}} +public {{resourceName}}Updater set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final {{{baseType}}} {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(Promoter.listOfOne({{paramName}})); +} +{{/isArray}} +{{! Optional setter, vendorExtensions.x-promotion stores promotion method}} +{{#vendorExtensions.x-promotion}} +public {{resourceName}}Updater set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(final String {{paramName}}){ + return set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{vendorExtensions.x-promotion}}); +} +{{/vendorExtensions.x-promotion}} +{{/vendorExtensions.x-setter-methods}} \ No newline at end of file diff --git a/src/main/resources/twilio-python/api-single.mustache b/src/main/resources/twilio-python/api-single.mustache index b95cea015..ae8ce0f37 100644 --- a/src/main/resources/twilio-python/api-single.mustache +++ b/src/main/resources/twilio-python/api-single.mustache @@ -1,7 +1,6 @@ {{>licenseInfo}} {{#resources}} from datetime import date, datetime -from decimal import Decimal from typing import Any, Dict, List, Optional, Union, Iterator, AsyncIterator from twilio.base import deserialize, serialize, values {{#instancePath}}from twilio.base.instance_context import InstanceContext{{/instancePath}} diff --git a/src/test/java/com/twilio/oai/TwilioGeneratorTest.java b/src/test/java/com/twilio/oai/TwilioGeneratorTest.java index b77ba704e..f8cb7b80e 100644 --- a/src/test/java/com/twilio/oai/TwilioGeneratorTest.java +++ b/src/test/java/com/twilio/oai/TwilioGeneratorTest.java @@ -40,7 +40,7 @@ public static void setUp() { @Test public void launchGenerator() { - final String pathname = "examples/spec/twilio_api_v2010.yaml"; + final String pathname = "examples/spec/twilio_flex_v1.yaml"; File filesList[] ; File directoryPath = new File(pathname); if (directoryPath.isDirectory()) { @@ -53,7 +53,8 @@ public void launchGenerator() { .setGeneratorName(generator.getValue()) .setInputSpec(file.getPath()) .setOutputDir("codegen/" + generator.getValue()) - .setInlineSchemaNameDefaults(Map.of("arrayItemSuffix", "")) + //.setInlineSchemaNameDefaults(Map.of("arrayItemSuffix", "")) // OpenAPI Generator 6.x.x + .setInlineSchemaOptions(Map.of("ARRAY_ITEM_SUFFIX", "")) // OpenAPI Generator 7.x.x .addGlobalProperty("apiTests", "false") .addGlobalProperty("apiDocs", "false"); final ClientOptInput clientOptInput = configurator.toClientOptInput(); diff --git a/src/test/resources/config/test_toggles.json b/src/test/resources/config/test_toggles.json index e0c3ec25d..89aaf1eea 100644 --- a/src/test/resources/config/test_toggles.json +++ b/src/test/resources/config/test_toggles.json @@ -1,5 +1,5 @@ { "json_ingress": { - "twilio-java": true + "twilio-java-legacy": true } }