Skip to main content
Ben Nadel at BFusion / BFLEX 2009 (Bloomington, Indiana) with: Simon Free
Ben Nadel at BFusion / BFLEX 2009 (Bloomington, Indiana) with: Simon Free

HTTP GET And HTTP POST Are Sufficient (For Me) In ColdFusion

By
Published in Comments (7)

As of this writing, HTML supports two different HTTP methods: GET and POST. And for the last 25-years, I've been building web-based applications very successfully on top of these two operation. Many people, however, are not satisfied with these limitations; and, would like to see PUT, PATCH, and DELETE added to the list of natively supported methods in HTML. Personally, I'm quite satisfied with GET and POST and haven't really experience any pain-points. So, I thought it might be interesting to try and articulate my perspective.

It's A Simpler Mental Model

Having two HTTP methods, GET and POST, creates a very simple mental model. You're either reading data with a GET or you're mutating data with a POST. There's no need to hand-wring about what type of mutation you're performing—are you creating new data, replacing data, or updating data—you're just mutating it. Period.

The fact that people even argue about when to use PUT and when to use POST is already a red flag (in my mind) that the addition of new HTTP methods adds confusion, not clarity.

It's All A Leaky Abstraction Anyway

The idea that you can have your HTTP method match your intent is already a fairly leaky abstraction. Even with GET and POST, the intent of the request only roughly matches what happens behind the scenes. When you GET a resource, it may very well mutate the data that you're accessing. For example, when viewing a resource, the application may implicitly change the last_accessed_at timestamp. And, when you make a request to "delete" a resource, the application may very well "soft delete" that resource by simply setting the deleted_at timestamp.

In middle school science, we learned the concept of "significant digits". As I remember it, these significant digits mean that the outcome of a calculation can only be as accurate as the least accurate part of the equation. So, if one of your inputs is only accurate to two significant digits, your result can only be accurate to two significant digits (even if your calculator gives you an answer to the 8th decimal place).

With a web application, the "significant digits" are "read" and "mutate". You really have no idea what's going on behind the scenes. And, attempting to layer more semantics on top of these two actions is attempting to add clarity where clarity can't exist.

File-Based Routing "Just Works"

A lot of the discussion around HTTP methods tends to coincide with a discussion about Routers and resource definitions. But, many applications don't use sophisticated routers with pattern matching—they just have files that match the URL / resource being requested.

That's not to say that a router doesn't add value; only that we have to remember that the application landscape is extremely varied. And, that in a file-based routing situation, the ability to make a request with many different HTTP methods may not be meaningful or helpful.

If the point of having more HTTP methods supported natively in HTML is supposed to make things "easier", then starting any argument with, "In your router, you would..." seems like a non-starter. Meaning, it seems like what you're saying is that in order to make things easier you have to start by adding a lot of complexity.

ColdFusion Effortlessly Differentiates Between GET And POST

In the ColdFusion world, a GET request and a POST request can be differentiated though the population of the url and form scopes, respectively. That's not to say that a POST can't also supply url parameters—only that ColdFusion has in-built mechanisms for differentiating URL-based data from body-based data.

This is particularly helpful for the highly prevalent "post back" pattern wherein a View rendered with a GET can then POST back to itself in order to perform an action. Think about something like a "delete confirmation" page wherein the application prompts the user to confirm the state mutation that is about to take place:

<cfscript>

	param name="url.resourceID" type="numeric";
	param name="form.submitted" type="boolean" default=false;

	// Check for POST method by seeing if form scope is populated.
	if ( form.submitted ) {

		deleteResource( url.resourceID );
		goto( "list.cfm" );

	}

</cfscript>
<cfoutput>

	<!--- POST back to self to perform mutation. --->
	<form method="post" action="?resourceID=4">
		<input type="hidden" name="submitted" value="true" />
		<p>
			Are you sure you want to delete this resource?
		</p>
		<button type="submit">
			Yes, delete it
		</button>
	</form>

</cfoutput>

Here, we're able to effortlessly differentiate the initial GET request from the subsequent POST request by looking to see if form.submitted was populated (with a truthy value).

What would this look like if we started trying to differentiate between more HTTP methods? Would we have to introduce new scopes? Would we have to start inspecting the cgi.request_method in our processing logic? Would we have to drive all the data into the URL?

We could, of course, do that—we could add more mechanics to the language or add more logic to the processing. But, I only argue that this wouldn't really be solving any problems—it would only be swapping one check for another (on top of what is already a very leaky abstraction, see above).

DELETE Can't Have A Body

Note: From what I'm seeing on Google, this has more to do with server implementations than it does with the actual HTTP specification.

This is 100% subjective; but, to me it feels very strange that a DELETE request cannot have a body. Which is to say that all data conveyed in a DELETE request must be present in the URL (or in the HTTP headers). This is probably just me fighting against the gravity of 25 years of web development; but, all mutation data feel like it should be at—least partially—outside of the URL.

I'll concede that this discomfort is likely me just trying to reconcile the old world with the new world. But, let's just look at the previous example using a theoretically-supported DELETE verb in HTML:

<cfscript>

	param name="url.resourceID" type="numeric";
	param name="url.submitted" type="boolean" default=false;

	// Check for DELETE method by seeing if url scope is populated.
	if ( url.submitted ) {

		deleteResource( url.resourceID );
		goto( "list.cfm" );

	}

</cfscript>
<cfoutput>

	<!--- DELETE back to self to perform mutation. --->
	<form method="delete" action="?resourceID=4&submitted=true">
		<p>
			Are you sure you want to delete this resource?
		</p>
		<button type="submit">
			Yes, delete it
		</button>
	</form>

</cfoutput>

Again, this is 100% subjective and mostly emotional. But it just feels "wrong" to examine nothing but the url scope in order to perform a delete operation.

That said, imagine a delete confirmation form in which I had to upload a file as part of the deletion process? Maybe I have a PDF that documents permission for me to perform the delete. How would I even do that in a "semantic" way? I don't think DELETE can coincide with an upload (on most server implementations). I think (and maybe I'm just naive here) that you'd have to use a POST in order to perform a deletion with a file upload.

Which again, if true, just points to the "theater" of it all (that is, pretending like the semantics of a DELETE are somehow more meaningful than the semantics of a POST).

Bulk Operations Aren't Confusing

This goes back to my earlier point that GET and POST create a simple mental model. What happens if you want to delete multiple resources at a time? In a GET and POST world, the answer is obvious: you POST to the server with the collection of resource identifiers that you want to delete.

But, in a world where DELETE is supported, should this be a DELETE operation? You're not talking about a single resource - you're talking about many resources. Does a DELETE make sense in that case? I don't know. And, in a GET/POST world, I don't have to care.

It's OK If You Want To Use PUT, PATCH, And DELETE

To be clear, I'm not here to yuck your yum. As someone who loves ColdFusion, I can totally relate to the notion that other people can't see the magic in the way you want to work. And, if you want HTML to support these methods so that you can use them in your applications, I think that's fine. My only point in this post is that these HTTP method don't inherently make life easier (or more intentful) for my ColdFusion applications.

Want to use code from this post? Check out the license.

Reader Comments

267 Comments

Well said! I think your strongest point was on bulk DELETE.

Another reason could just be simply the inconsistent application of the verbs.

16,001 Comments

@Chris,

Well you're a CFWheels guy, if I recall from a previous conversation. So, I know (or at least I'm learning now) that Wheels does a lot of this behind the scenes for you (with the _method hidden fields) as long as you pass the right route to the startFormTag().

That said, the biggest workflow difference for me in the Wheels world is that it doesn't use the "post back" kind of workflow that I have always done. There's a lot of POSTing to a different controller (ie, new posts over to create, which then re-renders the new View as needed). This is taking me a bit to get used to; especially with the two different controller methods having to prepare the same data for a view.

But, there's cool stuff here - lots of magic to learn.

267 Comments

@Ben Nadel,

Indeed I am. Filters are your friend when multiple routes all work with the same model to help cut down on the boilerplate. But I'm sure you know that already.

It does require a bit of a mental shift, but I like how it also keeps things orderly and consistent as well.

2 Comments

You didn't mention REST, but some of my criticisms of that pattern align with your frustration. While I'm not convinced that GET and POST are the holiest of HTTP verbs, I believe HTTP (and subsequently REST) do not have good answers for bulk operations. In your basic example, I would, and have, just provided a list in the query string.

16,001 Comments

@Jason,

100% I'm not saying that GET and POST are perfect - only that they are simple and sufficient. The older I get, the more I like simple.

7 Comments

Hey Ben,

Yep, HTML only support GET and POST, and probably always will, and I do understand where you are coming from.

I also love your point about keeping things simple, I am a huge proponent and wish others would do the same.

So yeah, you could write any app with only those two methods. No issue there.

And if it speeds your productivity of building great CF apps, it really doesn't matter what anyone thinks.

Keep this in mind however... it's important to know who your intended users are.

If they are people clicking on a browser, no problem.

But if they are servers run by third-party engineers connecting to your API, then consider following standard REST principles and semantics instead.

Cheers

Post A Comment — I'd Love To Hear From You!

Post a Comment

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel