diff --git a/modules/openapi-generator/src/main/resources/r/modelGeneric.mustache b/modules/openapi-generator/src/main/resources/r/modelGeneric.mustache index 7d1cf70e6df..a47824208ae 100644 --- a/modules/openapi-generator/src/main/resources/r/modelGeneric.mustache +++ b/modules/openapi-generator/src/main/resources/r/modelGeneric.mustache @@ -65,10 +65,10 @@ stopifnot(is.numeric(`{{name}}`), length(`{{name}}`) == 1) {{/isInteger}} {{#isLong}} - stopifnot(is.numeric(`{{name}}`), length(`{{nme}}`) == 1) + stopifnot(is.numeric(`{{name}}`), length(`{{name}}`) == 1) {{/isLong}} {{#isFloat}} - stopifnot(is.numeric(`{{nme}}`), length(`{{nme}}`) == 1) + stopifnot(is.numeric(`{{name}}`), length(`{{name}}`) == 1) {{/isFloat}} {{#isDouble}} stopifnot(is.numeric(`{{name}}`), length(`{{name}}`) == 1) @@ -85,6 +85,12 @@ {{#isDateTime}} stopifnot(is.character(`{{name}}`), length(`{{name}}`) == 1) {{/isDateTime}} + {{#isUri}} + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", `{{name}}`))) { + stop(paste("Error! Invalid URL:", `{{name}}`)) + } + {{/isUri}} {{^isPrimitiveType}} stopifnot(R6::is.R6(`{{name}}`)) {{/isPrimitiveType}} @@ -135,6 +141,12 @@ {{#isDateTime}} stopifnot(is.character(`{{name}}`), length(`{{name}}`) == 1) {{/isDateTime}} + {{#isUri}} + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", `{{name}}`))) { + stop(paste("Error! Invalid URL:", `{{name}}`)) + } + {{/isUri}} {{^isPrimitiveType}} stopifnot(R6::is.R6(`{{name}}`)) {{/isPrimitiveType}} @@ -238,6 +250,12 @@ stop(paste("Error! \"", this_object$`{{baseName}}`, "\" cannot be assigned to `{{baseName}}`. Must be {{#_enum}}\"{{{.}}}\"{{^-last}}, {{/-last}}{{/_enum}}.", sep = "")) } {{/isEnum}} + {{#isUri}} + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", this_object$`{{baseName}}`))) { + stop(paste("Error! Invalid URL:", this_object$`{{baseName}}`)) + } + {{/isUri}} self$`{{name}}` <- this_object$`{{baseName}}` {{/isPrimitiveType}} {{^isPrimitiveType}} @@ -364,6 +382,12 @@ stop(paste("Error! \"", this_object$`{{baseName}}`, "\" cannot be assigned to `{{baseName}}`. Must be {{#_enum}}\"{{{.}}}\"{{^-last}}, {{/-last}}{{/_enum}}.", sep = "")) } {{/isEnum}} + {{#isUri}} + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", this_object$`{{name}}`))) { + stop(paste("Error! Invalid URL:", this_object$`{{name}}`)) + } + {{/isUri}} self$`{{name}}` <- this_object$`{{name}}` {{/isPrimitiveType}} {{^isPrimitiveType}} @@ -419,6 +443,12 @@ {{#isDateTime}} stopifnot(is.character(input_json$`{{name}}`), length(input_json$`{{name}}`) == 1) {{/isDateTime}} + {{#isUri}} + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", input_json$`{{name}}`))) { + stop(paste("Error! Invalid URL:", input_json$`{{name}}`)) + } + {{/isUri}} {{^isPrimitiveType}} stopifnot(R6::is.R6(input_json$`{{name}}`)) {{/isPrimitiveType}} @@ -493,6 +523,12 @@ return(FALSE) } {{/pattern}} + {{#isUri}} + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", self$`{{{name}}}`))) { + return(FALSE) + } + {{/isUri}} {{#maxItems}} if (length(self$`{{{name}}}`) > {{maxItems}}) { return(FALSE) @@ -553,6 +589,12 @@ invalid_fields["{{{name}}}"] <- "Invalid value for `{{{name}}}`, must conform to the pattern {{{pattern}}}." } {{/pattern}} + {{#isUri}} + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", self$`{{name}}`))) { + invalid_fields["{{{name}}}"] <- "Invalid value for `{{{name}}}`, must be URL." + } + {{/isUri}} {{#maxItems}} if (length(self$`{{{name}}}`) > {{maxItems}}) { invalid_fields["{{{name}}}"] <- "Invalid length for `{{{name}}}`, number of items must be less than or equal to {{maxItems}}." diff --git a/modules/openapi-generator/src/test/resources/3_0/r/petstore.yaml b/modules/openapi-generator/src/test/resources/3_0/r/petstore.yaml index d7ff12f529c..55bedd6d474 100644 --- a/modules/openapi-generator/src/test/resources/3_0/r/petstore.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/r/petstore.yaml @@ -1115,5 +1115,9 @@ components: percent_description: description: using % in the description type: string + url_property: + type: string + format: uri required: - className + - url_property diff --git a/samples/client/petstore/R-httr2-wrapper/R/date.R b/samples/client/petstore/R-httr2-wrapper/R/date.R index d7ca6bebf0f..1797a087aa4 100644 --- a/samples/client/petstore/R-httr2-wrapper/R/date.R +++ b/samples/client/petstore/R-httr2-wrapper/R/date.R @@ -9,6 +9,7 @@ #' @format An \code{R6Class} generator object #' @field className character #' @field percent_description using \% in the description character [optional] +#' @field url_property character #' @field _field_list a list of fields list(character) #' @field additional_properties additional properties list(character) [optional] #' @importFrom R6 R6Class @@ -19,7 +20,8 @@ Date <- R6::R6Class( public = list( `className` = NULL, `percent_description` = NULL, - `_field_list` = c("className", "percent_description"), + `url_property` = NULL, + `_field_list` = c("className", "percent_description", "url_property"), `additional_properties` = list(), #' Initialize a new Date class. #' @@ -27,17 +29,26 @@ Date <- R6::R6Class( #' Initialize a new Date class. #' #' @param className className + #' @param url_property url_property #' @param percent_description using \% in the description #' @param additional_properties additonal properties (optional) #' @param ... Other optional arguments. #' @export initialize = function( - `className`, `percent_description` = NULL, additional_properties = NULL, ... + `className`, `url_property`, `percent_description` = NULL, additional_properties = NULL, ... ) { if (!missing(`className`)) { stopifnot(is.character(`className`), length(`className`) == 1) self$`className` <- `className` } + if (!missing(`url_property`)) { + stopifnot(is.character(`url_property`), length(`url_property`) == 1) + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", `url_property`))) { + stop(paste("Error! Invalid URL:", `url_property`)) + } + self$`url_property` <- `url_property` + } if (!is.null(`percent_description`)) { stopifnot(is.character(`percent_description`), length(`percent_description`) == 1) self$`percent_description` <- `percent_description` @@ -65,6 +76,10 @@ Date <- R6::R6Class( DateObject[["percent_description"]] <- self$`percent_description` } + if (!is.null(self$`url_property`)) { + DateObject[["url_property"]] <- + self$`url_property` + } for (key in names(self$additional_properties)) { DateObject[[key]] <- self$additional_properties[[key]] } @@ -87,6 +102,13 @@ Date <- R6::R6Class( if (!is.null(this_object$`percent_description`)) { self$`percent_description` <- this_object$`percent_description` } + if (!is.null(this_object$`url_property`)) { + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", this_object$`url_property`))) { + stop(paste("Error! Invalid URL:", this_object$`url_property`)) + } + self$`url_property` <- this_object$`url_property` + } # process additional properties/fields in the payload for (key in names(this_object)) { if (!(key %in% self$`_field_list`)) { # json key not in list of fields @@ -120,6 +142,14 @@ Date <- R6::R6Class( ', self$`percent_description` ) + }, + if (!is.null(self$`url_property`)) { + sprintf( + '"url_property": + "%s" + ', + self$`url_property` + ) } ) jsoncontent <- paste(jsoncontent, collapse = ",") @@ -142,6 +172,11 @@ Date <- R6::R6Class( this_object <- jsonlite::fromJSON(input_json) self$`className` <- this_object$`className` self$`percent_description` <- this_object$`percent_description` + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", this_object$`url_property`))) { + stop(paste("Error! Invalid URL:", this_object$`url_property`)) + } + self$`url_property` <- this_object$`url_property` # process additional properties/fields in the payload for (key in names(this_object)) { if (!(key %in% self$`_field_list`)) { # json key not in list of fields @@ -166,6 +201,16 @@ Date <- R6::R6Class( } else { stop(paste("The JSON input `", input, "` is invalid for Date: the required field `className` is missing.")) } + # check the required field `url_property` + if (!is.null(input_json$`url_property`)) { + stopifnot(is.character(input_json$`url_property`), length(input_json$`url_property`) == 1) + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", input_json$`url_property`))) { + stop(paste("Error! Invalid URL:", input_json$`url_property`)) + } + } else { + stop(paste("The JSON input `", input, "` is invalid for Date: the required field `url_property` is missing.")) + } }, #' To string (JSON format) #' @@ -190,6 +235,11 @@ Date <- R6::R6Class( return(FALSE) } + # check if the required `url_property` is null + if (is.null(self$`url_property`)) { + return(FALSE) + } + TRUE }, #' Return a list of invalid fields (if any). @@ -206,6 +256,11 @@ Date <- R6::R6Class( invalid_fields["className"] <- "Non-nullable required field `className` cannot be null." } + # check if the required `url_property` is null + if (is.null(self$`url_property`)) { + invalid_fields["url_property"] <- "Non-nullable required field `url_property` cannot be null." + } + invalid_fields }, #' Print the object diff --git a/samples/client/petstore/R-httr2-wrapper/docs/Date.md b/samples/client/petstore/R-httr2-wrapper/docs/Date.md index cf2497e7ea5..ed61f58682c 100644 --- a/samples/client/petstore/R-httr2-wrapper/docs/Date.md +++ b/samples/client/petstore/R-httr2-wrapper/docs/Date.md @@ -7,5 +7,6 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **className** | **character** | | **percent_description** | **character** | using % in the description | [optional] +**url_property** | **character** | | diff --git a/samples/client/petstore/R-httr2-wrapper/tests/testthat/test_petstore.R b/samples/client/petstore/R-httr2-wrapper/tests/testthat/test_petstore.R index c69378f0ff2..8314ad8098c 100644 --- a/samples/client/petstore/R-httr2-wrapper/tests/testthat/test_petstore.R +++ b/samples/client/petstore/R-httr2-wrapper/tests/testthat/test_petstore.R @@ -591,3 +591,12 @@ test_that("Tests anyOf", { expect_error(pig$validateJSON('{}'), 'No match found when deserializing the payload into AnyOfPig with anyOf schemas BasquePig, DanishPig. Details: The JSON input ` \\{\\} ` is invalid for BasquePig: the required field `className` is missing\\., The JSON input ` \\{\\} ` is invalid for DanishPig: the required field `className` is missing\\.') }) + +test_that("Tests URL validation", { + valid_json <- '{"className":"date","percent_description":"abc","url_property":"https://abc.com/a/1/b/2"}' + Date$public_methods$validateJSON(valid_json) # shouldn't throw exception + + invalid_json <- '{"className":"date","percent_description":"abc","url_property":"invalid_url"}' + expect_error(Date$public_methods$validateJSON(invalid_json), 'Error! Invalid URL: invalid_url') # should throw exception + +}) diff --git a/samples/client/petstore/R-httr2/R/date.R b/samples/client/petstore/R-httr2/R/date.R index e86de4700d6..f8387d1de08 100644 --- a/samples/client/petstore/R-httr2/R/date.R +++ b/samples/client/petstore/R-httr2/R/date.R @@ -9,6 +9,7 @@ #' @format An \code{R6Class} generator object #' @field className character #' @field percent_description using \% in the description character [optional] +#' @field url_property character #' @importFrom R6 R6Class #' @importFrom jsonlite fromJSON toJSON #' @export @@ -17,22 +18,32 @@ Date <- R6::R6Class( public = list( `className` = NULL, `percent_description` = NULL, + `url_property` = NULL, #' Initialize a new Date class. #' #' @description #' Initialize a new Date class. #' #' @param className className + #' @param url_property url_property #' @param percent_description using \% in the description #' @param ... Other optional arguments. #' @export initialize = function( - `className`, `percent_description` = NULL, ... + `className`, `url_property`, `percent_description` = NULL, ... ) { if (!missing(`className`)) { stopifnot(is.character(`className`), length(`className`) == 1) self$`className` <- `className` } + if (!missing(`url_property`)) { + stopifnot(is.character(`url_property`), length(`url_property`) == 1) + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", `url_property`))) { + stop(paste("Error! Invalid URL:", `url_property`)) + } + self$`url_property` <- `url_property` + } if (!is.null(`percent_description`)) { stopifnot(is.character(`percent_description`), length(`percent_description`) == 1) self$`percent_description` <- `percent_description` @@ -55,6 +66,10 @@ Date <- R6::R6Class( DateObject[["percent_description"]] <- self$`percent_description` } + if (!is.null(self$`url_property`)) { + DateObject[["url_property"]] <- + self$`url_property` + } DateObject }, #' Deserialize JSON string into an instance of Date @@ -73,6 +88,13 @@ Date <- R6::R6Class( if (!is.null(this_object$`percent_description`)) { self$`percent_description` <- this_object$`percent_description` } + if (!is.null(this_object$`url_property`)) { + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", this_object$`url_property`))) { + stop(paste("Error! Invalid URL:", this_object$`url_property`)) + } + self$`url_property` <- this_object$`url_property` + } self }, #' To JSON string @@ -99,6 +121,14 @@ Date <- R6::R6Class( ', self$`percent_description` ) + }, + if (!is.null(self$`url_property`)) { + sprintf( + '"url_property": + "%s" + ', + self$`url_property` + ) } ) jsoncontent <- paste(jsoncontent, collapse = ",") @@ -116,6 +146,11 @@ Date <- R6::R6Class( this_object <- jsonlite::fromJSON(input_json) self$`className` <- this_object$`className` self$`percent_description` <- this_object$`percent_description` + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", this_object$`url_property`))) { + stop(paste("Error! Invalid URL:", this_object$`url_property`)) + } + self$`url_property` <- this_object$`url_property` self }, #' Validate JSON input with respect to Date @@ -133,6 +168,16 @@ Date <- R6::R6Class( } else { stop(paste("The JSON input `", input, "` is invalid for Date: the required field `className` is missing.")) } + # check the required field `url_property` + if (!is.null(input_json$`url_property`)) { + stopifnot(is.character(input_json$`url_property`), length(input_json$`url_property`) == 1) + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", input_json$`url_property`))) { + stop(paste("Error! Invalid URL:", input_json$`url_property`)) + } + } else { + stop(paste("The JSON input `", input, "` is invalid for Date: the required field `url_property` is missing.")) + } }, #' To string (JSON format) #' @@ -157,6 +202,11 @@ Date <- R6::R6Class( return(FALSE) } + # check if the required `url_property` is null + if (is.null(self$`url_property`)) { + return(FALSE) + } + TRUE }, #' Return a list of invalid fields (if any). @@ -173,6 +223,11 @@ Date <- R6::R6Class( invalid_fields["className"] <- "Non-nullable required field `className` cannot be null." } + # check if the required `url_property` is null + if (is.null(self$`url_property`)) { + invalid_fields["url_property"] <- "Non-nullable required field `url_property` cannot be null." + } + invalid_fields }, #' Print the object diff --git a/samples/client/petstore/R-httr2/docs/Date.md b/samples/client/petstore/R-httr2/docs/Date.md index cf2497e7ea5..ed61f58682c 100644 --- a/samples/client/petstore/R-httr2/docs/Date.md +++ b/samples/client/petstore/R-httr2/docs/Date.md @@ -7,5 +7,6 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **className** | **character** | | **percent_description** | **character** | using % in the description | [optional] +**url_property** | **character** | | diff --git a/samples/client/petstore/R/R/date.R b/samples/client/petstore/R/R/date.R index d7ca6bebf0f..1797a087aa4 100644 --- a/samples/client/petstore/R/R/date.R +++ b/samples/client/petstore/R/R/date.R @@ -9,6 +9,7 @@ #' @format An \code{R6Class} generator object #' @field className character #' @field percent_description using \% in the description character [optional] +#' @field url_property character #' @field _field_list a list of fields list(character) #' @field additional_properties additional properties list(character) [optional] #' @importFrom R6 R6Class @@ -19,7 +20,8 @@ Date <- R6::R6Class( public = list( `className` = NULL, `percent_description` = NULL, - `_field_list` = c("className", "percent_description"), + `url_property` = NULL, + `_field_list` = c("className", "percent_description", "url_property"), `additional_properties` = list(), #' Initialize a new Date class. #' @@ -27,17 +29,26 @@ Date <- R6::R6Class( #' Initialize a new Date class. #' #' @param className className + #' @param url_property url_property #' @param percent_description using \% in the description #' @param additional_properties additonal properties (optional) #' @param ... Other optional arguments. #' @export initialize = function( - `className`, `percent_description` = NULL, additional_properties = NULL, ... + `className`, `url_property`, `percent_description` = NULL, additional_properties = NULL, ... ) { if (!missing(`className`)) { stopifnot(is.character(`className`), length(`className`) == 1) self$`className` <- `className` } + if (!missing(`url_property`)) { + stopifnot(is.character(`url_property`), length(`url_property`) == 1) + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", `url_property`))) { + stop(paste("Error! Invalid URL:", `url_property`)) + } + self$`url_property` <- `url_property` + } if (!is.null(`percent_description`)) { stopifnot(is.character(`percent_description`), length(`percent_description`) == 1) self$`percent_description` <- `percent_description` @@ -65,6 +76,10 @@ Date <- R6::R6Class( DateObject[["percent_description"]] <- self$`percent_description` } + if (!is.null(self$`url_property`)) { + DateObject[["url_property"]] <- + self$`url_property` + } for (key in names(self$additional_properties)) { DateObject[[key]] <- self$additional_properties[[key]] } @@ -87,6 +102,13 @@ Date <- R6::R6Class( if (!is.null(this_object$`percent_description`)) { self$`percent_description` <- this_object$`percent_description` } + if (!is.null(this_object$`url_property`)) { + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", this_object$`url_property`))) { + stop(paste("Error! Invalid URL:", this_object$`url_property`)) + } + self$`url_property` <- this_object$`url_property` + } # process additional properties/fields in the payload for (key in names(this_object)) { if (!(key %in% self$`_field_list`)) { # json key not in list of fields @@ -120,6 +142,14 @@ Date <- R6::R6Class( ', self$`percent_description` ) + }, + if (!is.null(self$`url_property`)) { + sprintf( + '"url_property": + "%s" + ', + self$`url_property` + ) } ) jsoncontent <- paste(jsoncontent, collapse = ",") @@ -142,6 +172,11 @@ Date <- R6::R6Class( this_object <- jsonlite::fromJSON(input_json) self$`className` <- this_object$`className` self$`percent_description` <- this_object$`percent_description` + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", this_object$`url_property`))) { + stop(paste("Error! Invalid URL:", this_object$`url_property`)) + } + self$`url_property` <- this_object$`url_property` # process additional properties/fields in the payload for (key in names(this_object)) { if (!(key %in% self$`_field_list`)) { # json key not in list of fields @@ -166,6 +201,16 @@ Date <- R6::R6Class( } else { stop(paste("The JSON input `", input, "` is invalid for Date: the required field `className` is missing.")) } + # check the required field `url_property` + if (!is.null(input_json$`url_property`)) { + stopifnot(is.character(input_json$`url_property`), length(input_json$`url_property`) == 1) + # validate URL using https://github.com/cran/librarian/blob/master/R/internal_functions.R#L131 credit: Desi Quintans + if (!any(grepl("(https?|ftp)://[^\\s/$.?#].[^\\s]*", input_json$`url_property`))) { + stop(paste("Error! Invalid URL:", input_json$`url_property`)) + } + } else { + stop(paste("The JSON input `", input, "` is invalid for Date: the required field `url_property` is missing.")) + } }, #' To string (JSON format) #' @@ -190,6 +235,11 @@ Date <- R6::R6Class( return(FALSE) } + # check if the required `url_property` is null + if (is.null(self$`url_property`)) { + return(FALSE) + } + TRUE }, #' Return a list of invalid fields (if any). @@ -206,6 +256,11 @@ Date <- R6::R6Class( invalid_fields["className"] <- "Non-nullable required field `className` cannot be null." } + # check if the required `url_property` is null + if (is.null(self$`url_property`)) { + invalid_fields["url_property"] <- "Non-nullable required field `url_property` cannot be null." + } + invalid_fields }, #' Print the object diff --git a/samples/client/petstore/R/docs/Date.md b/samples/client/petstore/R/docs/Date.md index cf2497e7ea5..ed61f58682c 100644 --- a/samples/client/petstore/R/docs/Date.md +++ b/samples/client/petstore/R/docs/Date.md @@ -7,5 +7,6 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **className** | **character** | | **percent_description** | **character** | using % in the description | [optional] +**url_property** | **character** | |