Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emulating CFHTTP's throwOnError feature #6

Open
dswitzer opened this issue Sep 13, 2021 · 4 comments
Open

Emulating CFHTTP's throwOnError feature #6

dswitzer opened this issue Sep 13, 2021 · 4 comments

Comments

@dswitzer
Copy link
Contributor

While working on replacing CFHTTP with BoltHTTP, I needed to replicate the throwOnError option of CFHTTP, so I wanted to share this service layer function I wrote in case it helps anyone else. All it does is capture exceptions and if the throwOnError is false, remaps the exceptions to match what CFHTTP returns on similar errors.

I thought it worth sharing since it took a little trial and error to figure out the various exceptions and remap them.

/**
* @hint  Generates an HTTP request using the BoltHttp client.
*
* @url           The URL for the HTTP request.
* @method        The method for the HTTP request.
* @params        An array of CFHTTP-like parameters to supply to the BoltHttp client.
* @options       An struct of options to pass to the BoltHttp client.
* @config        Overrides the default configuration for the BoltHttp client.
* @throwOnError  Determines if we should try to ignore errors an HTTP issue occurs. This is to mimic the CFHTTP throwOnError feature.
	*/
public struct function http(string url, string method="GET", array params=[], struct options={}, struct config={}, boolean throwOnError=true) output="false" {
	var boltClient = new rootcom.thirdparty.bolthttp.bolthttp(arguments.config);

	try {
		return boltClient.request(
			  url=arguments.url
			, method=arguments.method
			, params=arguments.params
			, options=arguments.options
		);
	} catch( Any e ){
		/*
			We want to mimic CFHTTP's throwOnError flag, which will not throw hard errors when a
			HTTP issue occurs, but instead returns a standard response.
		*/
		if( !arguments.throwOnError ){
			switch( e.type ){
				/*
					These errors happen when the "connectTimeout" has been reached and the
					host could not be reached.
				*/
				case "org.apache.http.conn.ConnectTimeoutException":
				case "java.net.NoRouteToHostException":
					return {
						  "ErrorDetail"="I/O Exception: No route to host (Host unreachable)"
						, "Mimetype"="Unable to determine MIME type of file."
						, "Statuscode"="Connection Failure. Status code unavailable."
						, "Filecontent"="Connection Failure"
						, "Responseheader"={}
						, "Text"=true
						, "Charset"=""
						, "Header"=""
					};
				/*
					These errors happen when the "socketTimeout" has been reached and a connection
					to the host occurred, but the server did not respond within a timely manor.
				*/
				case "java.net.SocketTimeoutException":
					return {
						  "ErrorDetail"=""
						, "Mimetype"="Unable to determine MIME type of file."
						, "Statuscode"="408 Request Time-out"
						, "Filecontent"="Connection Timeout"
						, "Responseheader"={}
						, "Text"=true
						, "Charset"=""
						, "Header"=""
					};
				/*
					These errors happen when the host name is invalid.
				*/
				case "java.net.UnknownHostException":
					var requestedUrl = createObject("java", "java.net.URL").init(javaCast("string", arguments.url));

					return {
						  "ErrorDetail"="Unknown host: #requestedUrl.getHost()#: Name or service not known"
						, "Mimetype"="Unable to determine MIME type of file."
						, "Statuscode"="Connection Failure. Status code unavailable."
						, "Filecontent"="Connection Failure"
						, "Responseheader"={}
						, "Text"=true
						, "Charset"=""
						, "Header"=""
					};
			}
		}

		rethrow;
	}
}

I'm not sure if this is worth refactoring into the code or just documented in. It could be easily refactored into a requestNoError() or safeRequest() helper, or even adding as an attribute to the request method.

@pfreitag
Copy link
Member

@dswitzer yeah I think it would be worth merging into the code for the request() function, as it tries to mimic cfhttp. If you want to do a pull request, I'm open to that.

@dswitzer
Copy link
Contributor Author

@pfreitag Would you want it implemented as something in the options structure or as it's own argument?

@pfreitag
Copy link
Member

I think it's own argument would make sense as the options tend to be for Client Specific settings - do you agree?

@dswitzer
Copy link
Contributor Author

dswitzer commented Sep 13, 2021

@pfreitag I think you could make valid arguments either way.

If the purpose of the options is to control the behavior of how BoltHTTP functions and/or you easily want to be able to create a generic "config" option which is passed to each HTTP request, then I think it makes sense to add it as an option value, even though it doesn't map directly to the Apache HttpClient library.

However, if the purpose of options is strictly intended to be a mapping of Apache HttpClient functionality, then it makes sense to keep it isolated.

I suppose making it it's own method, bypasses those issues altogether because when you want to "ignore" common exceptions and just get a response, you call the error safe method. I just don't love any of the names I've come up with for the method. 😋

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants