Skip to content

Commit

Permalink
Add support for POST with request schema only containing inputs and
Browse files Browse the repository at this point in the history
response model containing computed properties
  • Loading branch information
dikhan committed Jul 13, 2021
1 parent 5a7c1e3 commit 9252e2f
Show file tree
Hide file tree
Showing 8 changed files with 2,501 additions and 811 deletions.
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ show-terraform-version:
# dockerhub-login logs into Docker if the environment variable PERFORM_DOCKER_LOGIN is set. This is used by Travis CI
# to avoid Docker toomanyrequests: You have reached your pull rate limit.
dockerhub-login:
@echo "[INFO] Logging into Docker Hub Enabled=$(PERFORM_DOCKER_LOGIN)"
ifdef PERFORM_DOCKER_LOGIN
echo $(DOCKER_PASSWORD) | docker login -u $(DOCKER_USERNAME) --password-stdin
endif
Expand Down Expand Up @@ -148,6 +149,18 @@ else
@echo "Cancelling release due to new version $(RELEASE_TAG) <= latest release version $(CURRENT_RELEASE_TAG)"
endif

# RELEASE_ALPHA_VERSION=2.1.0 make release-alpha
release-alpha:
@$(eval ALPHA_VERSION := v$(RELEASE_ALPHA_VERSION)-alpha.1)
git tag $(ALPHA_VERSION)
git push origin $(ALPHA_VERSION)

# RELEASE_ALPHA_VERSION=2.1.0 make delete-release-alpha
delete-release-alpha:
@$(eval ALPHA_VERSION := v$(RELEASE_ALPHA_VERSION)-alpha.1)
git tag -d $(ALPHA_VERSION)
git push --delete origin $(ALPHA_VERSION)

define install_plugin
@$(eval PROVIDER_NAME := $(1))
@./scripts/install.sh --provider-name $(PROVIDER_NAME) --provider-source-address "terraform.example.com/examplecorp" --compiled-plugin-path $(TF_OPENAPI_PROVIDER_PLUGIN_NAME) --debug
Expand Down
134 changes: 104 additions & 30 deletions docs/how_to.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,31 +208,23 @@ paths:
If a given resource is missing any of the aforementioned required operations, the resource will not be available
as a terraform resource.
- Paths should be versioned as described in the [versioning](#versioning) document following ‘/v{number}/resource’ pattern
(e,g: ‘/v1/resource’). A version upgrade (e,g: v1 -> v2) will be needed when the interface of the resource changes, hence
the new version is non backwards compatible. See that only the 'Major' version is considered in the path, this is recommended
as the service provider will have less paths to maintain overall. if there are minor/patches applied to the backend that
should not affect the way consumer interacts with the APIs whatsoever and the namespace should remain as is.
- POST operation may have a body payload referencing a schema object (see example below) defined at the root level
[definitions](#swaggerDefinitions) section. The $ref can be a link to a local model definition or a definition hosted
externally. Payload schema should not be defined inside the path’s configuration; however, if it is defined the schema
must be the same as the GET and PUT operations, including the expected input properties as well as the computed ones.
The reason for this is to make sure the model for the the resource state is shared across different operations (POST, GET, PUT)
ensuring no diffs with terraform will happen at runtime due to inconsistency with properties. It is suggested to use the same
definition shared across the resource operations for a given version (e,g: $ref: "#/definitions/resource) so consistency
in terms of data model for a given resource version is maintained throughout all the operations. This helps keeping the
swagger file well structured and encourages object definition re-usability. Different end point versions should their own
payload definitions as the example below, path ```/v1/resource``` has a corresponding ```resourceV1``` definition object:
- POST operation may have a request body payload either defined inside the path’s configuration or referencing a schema object (using $ref)
defined at the root level [definitions](#swaggerDefinitions) section. The $ref can be a link to a local model definition or a definition hosted
externally. The request payload schema may be the same as the response schema, including the expected input properties (required and optional) as well
as the computed ones (readOnly):
````
/v1/resource:
post:
parameters:
- in: "body"
name: "body"
schema:
$ref: "#/definitions/resourceV1" # this can be a link to an external definition hostead somewhere else (e.g: $ref:"http://another-host.com/#/definitions/ContentDeliveryNetwork")
$ref: "#/definitions/resourceV1"
responses:
201:
schema:
$ref: "#/definitions/resourceV1"
definitions:  
  resourceV1:    
    type: object   
Expand All @@ -246,11 +238,80 @@ definitions:  
        type: string
````
- If the POST operation does not contain a body parameter, in order for the endpoint to be considered terraform compliant:
- the operation responses must contain at least one 'successful' response which can be either a 200, 201 or 202 response. The schema associated with
- If the POST operation does not share the same definition for the request payload and the response payload, in order for the endpoint to be considered terraform compliant:
- the POST request payload must contain only input properties, that is required and optional properties.
- the POST operation responses must contain at least one 'successful' response which can be either a 200, 201 or 202 response. The schema associated with
the successful response will need to contain all the input properties from the request payload (but configured as readOnly) as well as any other
computed property (readOnly) auto-generated by the API.
- the POST response schema must contain only readOnly properties. If the response schema properties are not explicitly configured as readOnly, the provider will automatically convert them as computed (readOnly).
- If the POST response schema does not contain any property called 'id', at least one property must contain the [x-terraform-id](#attributeDetails) extension which
serves as the resource identifier.
The following shows an example of a compatible terraform resource that expects in the request body only the input properties (`label` required property and `optional_property` an optioanl property)
and returns in the response payload both the inputs as well as any other output (computed properties) generated by the API:
````
/v1/resource:
post:
parameters:
- in: "body"
name: "body"
required: true
schema:
$ref: "#/definitions/ResourceRequestPayload"
responses:
201:
schema:
$ref: "#/definitions/ResourceResponsePayload"
/v1/resource/{resource_id}:
get:
parameters:
- name: "resource_id"
in: "path"
required: true
type: "string"
responses:
200:
schema:
$ref: "#/definitions/ResourceResponsePayload"
definitions:
ResourceRequestPayload:
type: "object"
required:
- label
properties:
label:
type: "string"
optional_property:
type: "string"
ResourceResponsePayload:
type: "object"
properties:
id:
type: "string"
readOnly: true
label:
type: "string"
readOnly: true
optional_property:
type: "string"
readOnly: true
````
The resulted resource's terraform schema configuration will contain the combination of the request and response schemas keeping
the corresponding input configurations as is (eg: required and optional properties will still be required and optional in the resulted final schema) as well as the output computed properties (readOnly properties from the response).
Note, if both the request and response schema properties contain extensions and their values are different, the extension value kept
for the property will be the one in the response.
- If the POST operation does not contain a request body payload, in order for the endpoint to be considered terraform compliant:
- the POST operation responses must contain at least one 'successful' response which can be either a 200, 201 or 202 response. The schema associated with
the successful response will be the one used as the resource schema. Note if more than one successful response is present in the
responses the first one found (in no particular order) will be used.
- the response schema must contain only read only properties; otherwise the resource will not be considered terraform compatible.
- the POST response schema must contain only readOnly properties.
- If the POST response schema does not contain any property called 'id', at least one property must contain the [x-terraform-id](#attributeDetails) extension which
serves as the resource identifier.
The following shows an example of a compatible terraform resource that does not expect any input upon creation but does return
computed data:
Expand Down Expand Up @@ -288,20 +349,33 @@ definitions:
Refer to [readOnly](#attributeDetails) attributes to learn more about how to define an object that has computed properties
(value auto-generated by the API).
- The schema object definition should be described on the root level [definitions](#swaggerDefinitions) section and must
not be embedded within the API definition. This is enforced to keep the swagger file well structured and to encourage
object re-usability across the resource CRUD operations. Operations such as POST/GET/PUT are expected to have a 'schema' property
with a link to the same definition (e,g: `$ref: "#/definitions/resource`). The ref can be a link to an external source
as described in the [OpenAPI documentation for $ref](https://swagger.io/docs/specification/using-ref/).
- The resource's POST, GET and PUT (if exposed) operations must have the same response schema configuration. This is required to ensure
the resource state is consistent.
- The resource's PUT operation (if exposed) request payload must be the same as the resources POST's request schema. The OpenAPI provider expects this
to ensure the update operation enables replacement of the representation of the target resource.
- The resource's PUT operation may return one of the following successful responses:
- 200 OK with a response payload containing the final state of the resource representation in accordance with the state of the enclosed representation and any other computed property. The response schema must be the same as the GET operation response schema.
- 202 Accepted for async resources. Refer to [asynchronous resources](https://github.com/dikhan/terraform-provider-openapi/blob/master/docs/how_to.md#xTerraformResourcePollEnabled) for more info.
- 204 No Content with an empty response payload.
- The schema object must have a property that uniquely identifies the resource instance. This can be done by either
having a computed property (readOnly) called ```id``` or by adding the [x-terraform-id](#attributeDetails) extension to one of the
existing properties.
- The resource schema object definition should be described on the root level [definitions](#swaggerDefinitions) section and should not
be embedded within the API definition. This is recommended to keep the OpenAPI document well structured and to encourage
object re-usability across the resource CRUD operations. The resource POST/GET/PUT operations are expected to have a 'schema' property
for both the request and response payloads with a link to the same definition (e,g: `$ref: "#/definitions/resource`). The ref can
be a link to an external source as described in the [OpenAPI documentation for $ref](https://swagger.io/docs/specification/using-ref/).
- The PUT operation may return one of the the following successful responses:
- 200 OK with a response payload containing the final state of the resource representation in accordance with the state of the enclosed representation and any other computed property.
- 202 Accepted for async resources. Refer to [asynchronous resources](https://github.com/dikhan/terraform-provider-openapi/blob/master/docs/how_to.md#xTerraformResourcePollEnabled) for more info.
- 204 No Content with an empty response payload.
- Paths should be versioned as described in the [versioning](#versioning) document following ‘/v{number}/resource’ pattern
(e,g: ‘/v1/resource’). A version upgrade (e,g: v1 -> v2) will be needed when the interface of the resource changes, hence
the new version is non backwards compatible. See that only the 'Major' version is considered in the path, this is recommended
as the service provider will have less paths to maintain overall. if there are minor/patches applied to the backend that
should not affect the way consumer interacts with the APIs whatsoever and the namespace should remain as is.
- Different end point versions should their own payload definitions as the example below, path ```/v1/resource``` has a corresponding ```resourceV1``` definition object:
###### Data source instance
Expand Down
22 changes: 21 additions & 1 deletion docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,24 @@ Note - For new releases, the PR title should follow the below convention (replac

With the above title, the new version would be v0.2.0.

The PR will need one admin approval. Once approved and merged, the release will be automatically performed by Travis CI.
The PR will need one admin approval. Once approved and merged, the release will be automatically performed by Travis CI.

## How to release a new alpha version

Alpha means the features haven't been locked down, it's an exploratory phase. Releasing an alpha version enable users to
start early adopting the version even though it may not be production ready yet and functionality might still change until
the final version released. The following targets have been created to help create alpha release versions:

- To create a new alpha release version run the following command:
````
RELEASE_ALPHA_VERSION=2.1.0 make release-alpha
````
This will create a local tag in the form v$(RELEASE_ALPHA_VERSION)-alpha.1. For the example above that would be `v2.1.0-alpha.1` and
push the tag to origin.

- To delete a previously create alpha version run the following command:
````
RELEASE_ALPHA_VERSION=2.1.0 make delete-release-alpha
````
This will delete a local tag in the form v$(RELEASE_ALPHA_VERSION)-alpha.1. For the example above that would be `v2.1.0-alpha.1` and
delete the tag in origin.
Loading

0 comments on commit 9252e2f

Please sign in to comment.