From b940b9ea855e59367132e759c436320e6ba8d72f Mon Sep 17 00:00:00 2001 From: Arnold Visser Date: Mon, 2 Oct 2023 14:20:53 -0400 Subject: [PATCH 1/2] whitespace updates from 'go fmt' commands --- restapi/api_client.go | 9 ++++-- restapi/common.go | 50 +++++++++++++++++------------ restapi/datasource_api_object.go | 2 +- restapi/resource_api_object.go | 22 ++++++++----- restapi/resource_api_object_test.go | 9 ++++-- 5 files changed, 57 insertions(+), 35 deletions(-) diff --git a/restapi/api_client.go b/restapi/api_client.go index be90cf82..78a8d3ad 100644 --- a/restapi/api_client.go +++ b/restapi/api_client.go @@ -76,7 +76,7 @@ type APIClient struct { oauthConfig *clientcredentials.Config } -//NewAPIClient makes a new api client for RESTful calls +// NewAPIClient makes a new api client for RESTful calls func NewAPIClient(opt *apiClientOpt) (*APIClient, error) { if opt.debug { log.Printf("api_client.go: Constructing debug api_client\n") @@ -210,8 +210,11 @@ func (client *APIClient) toString() string { return buffer.String() } -/* Helper function that handles sending/receiving and handling - of HTTP data in and out. */ +/* +Helper function that handles sending/receiving and handling + + of HTTP data in and out. +*/ func (client *APIClient) sendRequest(method string, path string, data string) (string, error) { fullURI := client.uri + path var req *http.Request diff --git a/restapi/common.go b/restapi/common.go index 7c831645..2b27295b 100755 --- a/restapi/common.go +++ b/restapi/common.go @@ -10,9 +10,12 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -/* After any operation that returns API data, we'll stuff - all the k,v pairs into the api_data map so users can - consume the values elsewhere if they'd like */ +/* +After any operation that returns API data, we'll stuff + + all the k,v pairs into the api_data map so users can + consume the values elsewhere if they'd like +*/ func setResourceState(obj *APIObject, d *schema.ResourceData) { apiData := make(map[string]string) for k, v := range obj.apiData { @@ -22,8 +25,11 @@ func setResourceState(obj *APIObject, d *schema.ResourceData) { d.Set("api_response", obj.apiResponse) } -/*GetStringAtKey uses GetObjectAtKey to verify the resulting - object is either a JSON string or Number and returns it as a string */ +/* +GetStringAtKey uses GetObjectAtKey to verify the resulting + + object is either a JSON string or Number and returns it as a string +*/ func GetStringAtKey(data map[string]interface{}, path string, debug bool) (string, error) { res, err := GetObjectAtKey(data, path, debug) if err != nil { @@ -41,19 +47,21 @@ func GetStringAtKey(data map[string]interface{}, path string, debug bool) (strin } } -/*GetObjectAtKey is a handy helper that will dig through a map and find something - at the defined key. The returned data is not type checked - Example: - Given: - { - "attrs": { - "id": 1234 - }, - "config": { - "foo": "abc", - "bar": "xyz" - } -} +/* +GetObjectAtKey is a handy helper that will dig through a map and find something + + at the defined key. The returned data is not type checked + Example: + Given: + { + "attrs": { + "id": 1234 + }, + "config": { + "foo": "abc", + "bar": "xyz" + } + } Result: attrs/id => 1234 @@ -138,8 +146,10 @@ func GetKeys(hash map[string]interface{}) []string { return keys } -/*GetEnvOrDefault is a helper function that returns the value of the -given environment variable, if one exists, or the default value */ +/* +GetEnvOrDefault is a helper function that returns the value of the +given environment variable, if one exists, or the default value +*/ func GetEnvOrDefault(k string, defaultvalue string) string { v := os.Getenv(k) if v == "" { diff --git a/restapi/datasource_api_object.go b/restapi/datasource_api_object.go index 4327a0f9..6ec4c86f 100755 --- a/restapi/datasource_api_object.go +++ b/restapi/datasource_api_object.go @@ -8,7 +8,7 @@ import ( func dataSourceRestAPI() *schema.Resource { return &schema.Resource{ - Read: dataSourceRestAPIRead, + Read: dataSourceRestAPIRead, Description: "Performs a cURL get command on the specified url.", Schema: map[string]*schema.Schema{ diff --git a/restapi/resource_api_object.go b/restapi/resource_api_object.go index 4289fc87..abeb2987 100644 --- a/restapi/resource_api_object.go +++ b/restapi/resource_api_object.go @@ -183,10 +183,13 @@ func resourceRestAPI() *schema.Resource { } } -/* Since there is nothing in the ResourceData structure other - than the "id" passed on the command line, we have to use an opinionated - view of the API paths to figure out how to read that object - from the API */ +/* +Since there is nothing in the ResourceData structure other + + than the "id" passed on the command line, we have to use an opinionated + view of the API paths to figure out how to read that object + from the API +*/ func resourceRestAPIImport(d *schema.ResourceData, meta interface{}) (imported []*schema.ResourceData, err error) { input := d.Id() @@ -339,10 +342,13 @@ func resourceRestAPIExists(d *schema.ResourceData, meta interface{}) (exists boo return exists, err } -/* Simple helper routine to build an api_object struct - for the various calls terraform will use. Unfortunately, - terraform cannot just reuse objects, so each CRUD operation - results in a new object created */ +/* +Simple helper routine to build an api_object struct + + for the various calls terraform will use. Unfortunately, + terraform cannot just reuse objects, so each CRUD operation + results in a new object created +*/ func makeAPIObject(d *schema.ResourceData, meta interface{}) (*APIObject, error) { opts, err := buildAPIObjectOpts(d) if err != nil { diff --git a/restapi/resource_api_object_test.go b/restapi/resource_api_object_test.go index f00a6dad..2ed702d6 100644 --- a/restapi/resource_api_object_test.go +++ b/restapi/resource_api_object_test.go @@ -106,9 +106,12 @@ func TestAccRestApiObject_Basic(t *testing.T) { svr.Shutdown() } -/* This function generates a terraform JSON configuration from - a name, JSON data and a list of params to set by coaxing it - all to maps and then serializing to JSON */ +/* +This function generates a terraform JSON configuration from + + a name, JSON data and a list of params to set by coaxing it + all to maps and then serializing to JSON +*/ func generateTestResource(name string, data string, params map[string]interface{}) string { strData, _ := json.Marshal(data) config := []string{ From e904dad1aa06c0112a5cb1eeb77930c7f41641a8 Mon Sep 17 00:00:00 2001 From: Arnold Visser Date: Mon, 2 Oct 2023 14:21:28 -0400 Subject: [PATCH 2/2] adding ability to inject '{id}' value in update_data --- docs/resources/object.md | 18 +++++++++++++++--- restapi/api_object.go | 3 +++ restapi/api_object_test.go | 15 +++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/docs/resources/object.md b/docs/resources/object.md index 2344756d..9148cef7 100644 --- a/docs/resources/object.md +++ b/docs/resources/object.md @@ -15,11 +15,23 @@ Acting as a wrapper of cURL, this object supports POST, GET, PUT and DELETE on t ```terraform resource "restapi_object" "Foo2" { provider = restapi.restapi_headers - path = "/api/objects" - data = "{ \"id\": \"55555\", \"first\": \"Foo\", \"last\": \"Bar\" }" + path = "/api/objects" + data = "{ \"id\": \"55555\", \"first\": \"Foo\", \"last\": \"Bar\" }" } ``` +We provide a special keyword `{id}` that can be used when updating objects to put the object's id into the update payload, this is for situations where the id_Attribute is set by the create, and is required for the payload as opposed to the URL +```terraform +resource "restapi_object" "Foo2" { + provider = restapi.restapi_headers + path = "/api/objects" + update_path = "/api/objects" + data = "{ \"first\": \"Foo\", \"last\": \"Bar\" }" + update_data = "{ \"id\": \"{id}\", \"first\": \"Foo\", \"last\": \"Bar\" }" +} +``` + + ## Schema @@ -43,7 +55,7 @@ resource "restapi_object" "Foo2" { - `read_method` (String) Defaults to `read_method` set on the provider. Allows per-resource override of `read_method` (see `read_method` provider config documentation) - `read_path` (String) Defaults to `path/{id}`. The API path that represents where to READ (GET) objects of this type on the API server. The string `{id}` will be replaced with the terraform ID of the object. - `read_search` (Map of String) Custom search for `read_path`. This map will take `search_key`, `search_value`, `results_key` and `query_string` (see datasource config documentation) -- `update_data` (String) Valid JSON object to pass during to update requests. +- `update_data` (String) Valid JSON object to pass during to update requests. The value `{id}` is available to inject the object id_attribute into the update payload - `update_method` (String) Defaults to `update_method` set on the provider. Allows per-resource override of `update_method` (see `update_method` provider config documentation) - `update_path` (String) Defaults to `path/{id}`. The API path that represents where to UPDATE (PUT) objects of this type on the API server. The string `{id}` will be replaced with the terraform ID of the object. diff --git a/restapi/api_object.go b/restapi/api_object.go index 771e8215..838cffc2 100644 --- a/restapi/api_object.go +++ b/restapi/api_object.go @@ -366,6 +366,9 @@ func (obj *APIObject) updateObject() error { b, _ := json.Marshal(obj.data) updateData, _ := json.Marshal(obj.updateData) + // Replace the "{id}" String with the id attribute of the object + updateData = bytes.ReplaceAll(updateData, []byte(`{id}`), []byte(obj.id)) + if string(updateData) != "{}" { if obj.debug { log.Printf("api_object.go: Using update data '%s'", string(updateData)) diff --git a/restapi/api_object_test.go b/restapi/api_object_test.go index ede3b0b2..e71f4fef 100644 --- a/restapi/api_object_test.go +++ b/restapi/api_object_test.go @@ -227,6 +227,21 @@ func TestAPIObject(t *testing.T) { } }) + /* Update once more with {id} placeholder info in update_data */ + t.Run("update_object_with_update_data", func(t *testing.T) { + if testDebug { + log.Printf("api_object_test.go: Testing update_object() with update_data") + } + testingObjects["no Colors"].updateData["update_id"] = "{id}" + testingObjects["no Colors"].updateObject() + if err != nil { + t.Fatalf("api_object_test.go: Failed in update_object() test: %s", err) + } else if testingObjects["no Colors"].apiData["update_id"] != "3" { + t.Fatalf("api_object_test.go: Failed to set an 'update_id' field of 'no Colors' object. Expected it to be '%s' but it is '%s'\nFull obj: %+v\n", + "3", testingObjects["no Colors"].apiData["no Colors"], testingObjects["no Colors"]) + } + }) + /* Delete one and make sure a 404 follows */ t.Run("delete_object", func(t *testing.T) { if testDebug {