@@ -20,6 +20,7 @@ import (
2020 "github.com/hashicorp/go-retryablehttp"
2121 "github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
2222 "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
23+ "github.com/hashicorp/terraform-plugin-framework/attr"
2324 "github.com/hashicorp/terraform-plugin-framework/diag"
2425 "github.com/hashicorp/terraform-plugin-framework/path"
2526 "github.com/hashicorp/terraform-plugin-framework/resource"
@@ -157,6 +158,19 @@ func (r *httpResource) Schema(ctx context.Context, req resource.SchemaRequest, r
157158 Optional : true ,
158159 },
159160
161+ "when" : rs.StringAttribute {
162+ Description : "When to send the HTTP request. Valid values are `apply` (default) and `destroy`. " +
163+ "When set to `apply`, the request is sent during resource creation and updates. " +
164+ "When set to `destroy`, the request is only sent during resource destruction." ,
165+ Optional : true ,
166+ Validators : []validator.String {
167+ stringvalidator .OneOf ([]string {
168+ "apply" ,
169+ "destroy" ,
170+ }... ),
171+ },
172+ },
173+
160174 "response_headers" : rs.MapAttribute {
161175 Description : `A map of response header field names and values.` +
162176 ` Duplicate headers are concatenated according to [RFC2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2).` ,
@@ -214,9 +228,31 @@ func (r *httpResource) Create(ctx context.Context, req resource.CreateRequest, r
214228 if resp .Diagnostics .HasError () {
215229 return
216230 }
217- if err := r .performRequest (ctx , & model , & resp .Diagnostics ); err != nil {
218- return
231+
232+ // Only perform request if "when" is set to "apply" (default behavior when not specified)
233+ whenValue := "apply"
234+ if ! model .When .IsNull () && ! model .When .IsUnknown () {
235+ whenValue = model .When .ValueString ()
236+ }
237+
238+ if whenValue == "apply" {
239+ if err := r .performRequest (ctx , & model , & resp .Diagnostics ); err != nil {
240+ return
241+ }
242+ } else {
243+ // Set default values for computed fields when not making request
244+ model .ID = types .StringValue (model .URL .ValueString ())
245+
246+ // Create an empty map for response headers
247+ emptyHeaders := make (map [string ]attr.Value )
248+ model .ResponseHeaders = types .MapValueMust (types .StringType , emptyHeaders )
249+
250+ model .ResponseBody = types .StringValue ("" )
251+ model .Body = types .StringValue ("" )
252+ model .ResponseBodyBase64 = types .StringValue ("" )
253+ model .StatusCode = types .Int64Value (0 )
219254 }
255+
220256 diags = resp .State .Set (ctx , model )
221257 resp .Diagnostics .Append (diags ... )
222258}
@@ -228,26 +264,96 @@ func (r *httpResource) Read(ctx context.Context, req resource.ReadRequest, resp
228264 if resp .Diagnostics .HasError () {
229265 return
230266 }
267+ // No HTTP request is performed during read operations
268+ // Ensure computed fields are properly set if they're null/unknown
269+ if model .ID .IsNull () || model .ID .IsUnknown () {
270+ model .ID = types .StringValue (model .URL .ValueString ())
271+ }
272+ if model .ResponseHeaders .IsNull () || model .ResponseHeaders .IsUnknown () {
273+ emptyHeaders := make (map [string ]attr.Value )
274+ model .ResponseHeaders = types .MapValueMust (types .StringType , emptyHeaders )
275+ }
276+ if model .ResponseBody .IsNull () || model .ResponseBody .IsUnknown () {
277+ model .ResponseBody = types .StringValue ("" )
278+ }
279+ if model .Body .IsNull () || model .Body .IsUnknown () {
280+ model .Body = types .StringValue ("" )
281+ }
282+ if model .ResponseBodyBase64 .IsNull () || model .ResponseBodyBase64 .IsUnknown () {
283+ model .ResponseBodyBase64 = types .StringValue ("" )
284+ }
285+ if model .StatusCode .IsNull () || model .StatusCode .IsUnknown () {
286+ model .StatusCode = types .Int64Value (0 )
287+ }
288+
231289 diags = resp .State .Set (ctx , model )
232290 resp .Diagnostics .Append (diags ... )
233291}
234292
235293func (r * httpResource ) Update (ctx context.Context , req resource.UpdateRequest , resp * resource.UpdateResponse ) {
236- var model modelV0
237- diags := req .Plan .Get (ctx , & model )
238- resp .Diagnostics .Append (diags ... )
294+ // Preserve computed fields across updates; reflect config changes and optionally perform request
295+ var plan , state modelV0
296+ var diags diag.Diagnostics
297+
298+ // Read desired configuration from plan
299+ d := req .Plan .Get (ctx , & plan )
300+ resp .Diagnostics .Append (d ... )
239301 if resp .Diagnostics .HasError () {
240302 return
241303 }
242- if err := r .performRequest (ctx , & model , & resp .Diagnostics ); err != nil {
304+
305+ // Read prior state to retain computed fields when needed
306+ d = req .State .Get (ctx , & state )
307+ resp .Diagnostics .Append (d ... )
308+ if resp .Diagnostics .HasError () {
243309 return
244310 }
311+
312+ whenValue := "apply"
313+ if ! plan .When .IsNull () && ! plan .When .IsUnknown () {
314+ whenValue = plan .When .ValueString ()
315+ }
316+
317+ // Begin with desired config (plan)
318+ model := plan
319+
320+ if whenValue == "apply" {
321+ if err := r .performRequest (ctx , & model , & resp .Diagnostics ); err != nil {
322+ return
323+ }
324+ } else {
325+ // Keep previous computed fields when not issuing a request
326+ model .ID = state .ID
327+ model .ResponseHeaders = state .ResponseHeaders
328+ model .ResponseBody = state .ResponseBody
329+ model .Body = state .Body
330+ model .ResponseBodyBase64 = state .ResponseBodyBase64
331+ model .StatusCode = state .StatusCode
332+ }
333+
245334 diags = resp .State .Set (ctx , model )
246335 resp .Diagnostics .Append (diags ... )
247336}
248337
249338func (r * httpResource ) Delete (ctx context.Context , req resource.DeleteRequest , resp * resource.DeleteResponse ) {
250- // No remote deletion; removing from state is sufficient.
339+ var model modelV0
340+ diags := req .State .Get (ctx , & model )
341+ resp .Diagnostics .Append (diags ... )
342+ if resp .Diagnostics .HasError () {
343+ return
344+ }
345+
346+ // Only perform request if "when" is set to "destroy"
347+ whenValue := "apply"
348+ if ! model .When .IsNull () && ! model .When .IsUnknown () {
349+ whenValue = model .When .ValueString ()
350+ }
351+
352+ if whenValue == "destroy" {
353+ if err := r .performRequest (ctx , & model , & resp .Diagnostics ); err != nil {
354+ return
355+ }
356+ }
251357}
252358
253359func (r * httpResource ) performRequest (ctx context.Context , model * modelV0 , diags * diag.Diagnostics ) error {
0 commit comments