Skip to content

Commit

Permalink
Merge pull request #77 from dikhan/feature/array-of-objects-support
Browse files Browse the repository at this point in the history
Feature/array of objects support
  • Loading branch information
dikhan authored Dec 4, 2018
2 parents 2335f28 + 718cb9b commit ece0db7
Show file tree
Hide file tree
Showing 22 changed files with 3,073 additions and 205 deletions.
83 changes: 78 additions & 5 deletions docs/how_to.md
Original file line number Diff line number Diff line change
Expand Up @@ -615,15 +615,88 @@ The following property types will be translated into their corresponding terrafo
Swagger Type | TF Type | Description
---|:---:|---
string | Type: schema.TypeString | string value
[string] | schema.TypeList (schema.TypeString) | list of string values
integer | schema.TypeInt | int value
number | schema.TypeFloat | float value
boolean | schema.TypeBool | boolean value
object | schema.TypeMap | map value
[object](https://github.com/dikhan/terraform-provider-openapi/blob/master/docs/how_to.md#object-definitions) | schema.TypeMap | map value
[array](https://github.com/dikhan/terraform-provider-openapi/blob/master/docs/how_to.md#array-definitions) | schema.TypeList | list of values of the same type. The list item types can be primitives (string, integer, number or bool) or complex data structures (objects)

###### Array definitions

Arrays can be constructed containing simple values like primitive types (string, integer, number or bool) or complex
types defined by the object definition. In any case, the swagger property 'items' must be populated when describing
an array property.

- Arrays of primitive values (string, integer, number or bool primitives):

````
definitions:
ContentDeliveryNetworkV1:
type: "object"
...
properties:
arrayOfOStringsExample: # This is an example of an array of strings
type: "array"
items:
type: "string"
````

The above OpenAPI configuration would translate into the following Terraform configuration:

````
resource "swaggercodegen_cdn_v1" "my_cdn" {
...
array_of_strings_example = ["somevalue", "some-other-value"]
...
````

- Arrays of complex values (objects):

The example below shows how the property named 'arrayOfObjectsExample' is configured with type 'array' and the 'items'
are of type object, meaning that the array holds objects inside as described in the object 'properties' section.

````
definitions:
ContentDeliveryNetworkV1:
type: "object"
...
properties:
arrayOfObjectsExample: # This is an example of an array of objects
type: "array"
items:
type: "object"
properties:
protocol:
type: string
````

The above OpenAPI configuration would translate into the following Terraform configuration:

````
resource "swaggercodegen_cdn_v1" "my_cdn" {
...
array_of_objects_example = [
{
protocol = "http"
},
{
protocol = "tcp"
}
]
...
````

**Note**: The items support both nested object definitions (in which case the type **must** be object) and ref to other schema
definitions as described in the [Object definitions](https://github.com/dikhan/terraform-provider-openapi/blob/master/docs/how_to.md#object-definitions)
section.

###### Object definitions

Object types can be defined in two fashions:

###### Nested properties
####### Nested properties

Properties can have their schema definition in place or nested; and they must be of type 'object'.

Expand All @@ -641,9 +714,9 @@ definitions:
type: string
````

###### Ref schema definition
####### Ref schema definition

A property that has a $ref attribute is considered automatically and object so defining the type is optional (although
A property that has a $ref attribute is considered automatically an object so defining the type 'object' is optional (although
it's recommended).

````
Expand Down
23 changes: 23 additions & 0 deletions examples/swaggercodegen/api/api/cdn.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ func ContentDeliveryNetworkCreateV1(w http.ResponseWriter, r *http.Request) {
sendErrorResponse(http.StatusBadRequest, err.Error(), w)
return
}

if err := validateMandatoryFields(cdn); err != nil {
sendErrorResponse(http.StatusBadRequest, err.Error(), w)
return
}

populateComputePropertiesCDN(cdn)
db[cdn.Id] = cdn
log.Printf("POST [%+v\n]", cdn)
Expand Down Expand Up @@ -69,6 +75,22 @@ func populateComputePropertiesCDN(cdn *ContentDeliveryNetworkV1) {
}
}

func validateMandatoryFields(cdn *ContentDeliveryNetworkV1) error {
if cdn.Label == "" {
return fmt.Errorf("mandatory 'label' field not populated")
}
if len(cdn.Ips) <= 0 {
return fmt.Errorf("mandatory 'ips' list field not populated")
}
if len(cdn.Hostnames) <= 0 {
return fmt.Errorf("mandatory 'hostnames' field not populated")
}
if cdn.Label == "" {
return fmt.Errorf("mandatory label field not populated")
}
return nil
}

func updateCDN(dbCDN, updatedCDN *ContentDeliveryNetworkV1) {
dbCDN.Label = updatedCDN.Label
dbCDN.Ips = updatedCDN.Ips
Expand All @@ -77,6 +99,7 @@ func updateCDN(dbCDN, updatedCDN *ContentDeliveryNetworkV1) {
dbCDN.ExampleNumber = updatedCDN.ExampleNumber
dbCDN.ExampleBoolean = updatedCDN.ExampleBoolean
dbCDN.ObjectProperty = updatedCDN.ObjectProperty
dbCDN.ArrayOfObjectsExample = updatedCDN.ArrayOfObjectsExample
db[dbCDN.Id] = dbCDN
}

Expand Down
2 changes: 2 additions & 0 deletions examples/swaggercodegen/api/api/content_delivery_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ type ContentDeliveryNetworkV1 struct {
ObjectProperty *ObjectProperty `json:"object_property"`

ObjectNestedSchemeProperty *ContentDeliveryNetworkV1ObjectNestedSchemeProperty `json:"object_nested_scheme_property,omitempty"`

ArrayOfObjectsExample []ContentDeliveryNetworkV1ArrayOfObjectsExample `json:"arrayOfObjectsExample"`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Dummy Service Provider generated using 'swaggercodegen' that has two resources 'cdns' and 'lbs' which are terraform compliant
*
* This service provider allows the creation of fake 'cdns' and 'lbs' resources
*
* API version: 1.0.0
* Contact: apiteam@serviceprovider.io
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/

package api

type ContentDeliveryNetworkV1ArrayOfObjectsExample struct {

Protocol string `json:"protocol"`

OriginPort int32 `json:"originPort"`

}
10 changes: 9 additions & 1 deletion examples/swaggercodegen/api/api/object_property.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,13 @@
package api

type ObjectProperty struct {
Message string `json:"message,omitempty"`
Message string `json:"message"`

DetailedMessage string `json:"detailedMessage"`

ExampleInt int32 `json:"exampleInt"`

ExampleNumber float32 `json:"exampleNumber"`

ExampleBoolean bool `json:"example_boolean"`
}
25 changes: 25 additions & 0 deletions examples/swaggercodegen/api/resources/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -368,13 +368,37 @@ definitions:
properties:
name:
type: string
arrayOfObjectsExample: # This is an example of an array of objects
type: "array"
items:
type: "object"
properties:
protocol:
type: string
originPort:
type: integer
x-terraform-field-name: "origin_port"

ObjectProperty:
type: object
required:
- message
- detailedMessage
- exampleInt
- exampleNumber
- example_boolean
properties:
message:
type: string
detailedMessage:
type: string
x-terraform-field-name: "detailed_message"
exampleInt:
type: integer
exampleNumber:
type: number
example_boolean:
type: boolean

LBV1:
type: "object"
Expand Down Expand Up @@ -415,6 +439,7 @@ definitions:
$ref: "#/definitions/Status"
x-terraform-field-status: true # identifies the field that should be used as status for async operations. This is handy when the field name is not status but some other name the service provider might have chosen and enables the provider to identify the field as the status field that will be used to track progress for the async operations
readOnly: true

Status:
type: object
properties:
Expand Down
47 changes: 44 additions & 3 deletions examples/swaggercodegen/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,56 @@ resource "swaggercodegen_cdn_v1" "my_cdn" {
ips = ["127.0.0.1"] ## This is a force-new property (refer to swagger file)
hostnames = ["origin.com"]

example_int = 12
better_example_number_field_name = 1.12
example_int = 25
better_example_number_field_name = 15.78
example_boolean = true

object_property = {
message = "some message news"
message = "some message news2"
detailed_message = "some message news with details"
example_int = 11
example_number = 12.23
example_boolean = true
}

array_of_objects_example = [
{
protocol = "http"
origin_port = 81
},
{
protocol = "https"
origin_port = 443
}
]
}

# This is an example on how to use interpolation for 'object' types like the object_property and be able to pass
# along to other resources property values from objects
resource "swaggercodegen_cdn_v1" "my_cdn2" {
label = "label" ## This is an immutable property (refer to swagger file)
ips = ["127.0.0.2"] ## This is a force-new property (refer to swagger file)
hostnames = ["origin.com"]

example_int = "${swaggercodegen_cdn_v1.my_cdn.object_property.example_int}"
better_example_number_field_name = "${swaggercodegen_cdn_v1.my_cdn.object_property.example_number}"
example_boolean = "${swaggercodegen_cdn_v1.my_cdn.object_property.example_boolean}"

object_property = {
message = "some message news2"
detailed_message = "some message news with details"
example_int = "${swaggercodegen_cdn_v1.my_cdn.object_property.example_int}"
example_number = "${swaggercodegen_cdn_v1.my_cdn.object_property.example_number}"
example_boolean = "${swaggercodegen_cdn_v1.my_cdn.object_property.example_boolean}"
}

array_of_objects_example = [
"${swaggercodegen_cdn_v1.my_cdn.array_of_objects_example[0]}",
"${swaggercodegen_cdn_v1.my_cdn.array_of_objects_example[1]}",
]
}


resource "swaggercodegen_lbs_v1" "my_lb" {
name = "some_name"
backends = ["backend.com"]
Expand Down
9 changes: 9 additions & 0 deletions openapi/openapi_spec_resource_schema_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,12 @@ func (s *specSchemaDefinition) getProperty(name string) (*specSchemaDefinitionPr
}
return nil, fmt.Errorf("property with name '%s' not existing in resource schema definition", name)
}

func (s *specSchemaDefinition) getPropertyBasedOnTerraformName(terraformName string) (*specSchemaDefinitionProperty, error) {
for _, property := range s.Properties {
if property.getTerraformCompliantPropertyName() == terraformName {
return property, nil
}
}
return nil, fmt.Errorf("property with terraform name '%s' not existing in resource schema definition", terraformName)
}
Loading

0 comments on commit ece0db7

Please sign in to comment.