I'm developing a service invoking script that looks like:
我正在开发一个服务调用脚本,看起来像:
<cfinvoke webservice="#ServiceURL#" method="AddCustomer" returnvariable="ResponseData" argumentcollection="#stAguments#">
<cfinvokeargument name="api_key" value="#ServiceKey#" />
</cfinvoke>
stAguments structure filled before this call, obviously. Imagine you've forgot to add one of arguments into this container or used wrong argument type, say created invalid request. ColdFusion throws exception that can be catched, but can not (not literally) be read:
显然,在此调用之前填充的stAguments结构。想象一下,你忘了在这个容器中添加一个参数或者使用了错误的参数类型,比如创建了无效的请求。 ColdFusion抛出可以捕获的异常,但不能(不是字面上)读取:
*Web service operation AddCustomer with parameters {postcode={12345},org_name={Terms test 7.79661762856},fax={},html={1},addr1={address1},firstname={sergey},city={Austin},country={},taxable={},notify={1},lastname={galashyn},addr2={},ssn={},api_key={8FE9AD0BCF2382D92A1080DB3AA62DB9},taxrate={0},terms={Net 15},active={},state={},salutation={Mr.},password={123},account_manager={1}} cannot be found.*
It breaks my head checking all these arguments manually one by one. This is the problem.
它一个接一个地手动检查所有这些参数。这就是问题。
Maybe anyone uses some technique to make this easier.
也许有人会使用某种技术来使这更容易。
I've even thought about some kind of parser to automate this comparison.
我甚至考虑过某种解析器来自动进行这种比较。
Will appreciate any thought and ideas.
会欣赏任何想法和想法。
Thank you.
P.S. Sorry for my English -- not my native language. Please ask if I've wrote anything not clear enough.
附:抱歉我的英语 - 不是我的母语。请问我是否写了一些不够清楚的东西。
EDIT:
To clarify. Problem is not in accessing service. I am owner of it and I am definitely know all arguments and their types of each method.
澄清。问题不在于访问服务。我是它的拥有者,我肯定知道每个方法的所有参数和类型。
Problem is only in reading error message when creating request -- filling method arguments container.
问题仅在于在创建请求时读取错误消息 - 填充方法参数容器。
For example, method got 10 arguments and accidentally I've added 9 -- local instance of CF throws error that method can't be found and shows raw list (em'ed above) of fields I've passed. And I need to compare them one by one with method arguments to find what I've missed.
例如,方法获得了10个参数,并且意外地我添加了9 - CF的本地实例抛出了无法找到方法的错误,并显示了我已经传递的字段的原始列表(上面的em')。我需要将它们与方法参数逐一进行比较,以找到我错过的内容。
Really, it's an usability and time saving problem.
真的,这是一个可用性和节省时间的问题。
3 个解决方案
#1
Really, it's an usability and time saving problem.
真的,这是一个可用性和节省时间的问题。
Okay, so if I understand you correctly, you need a "debugging" way to compare what you have to what you need.
好的,所以如果我理解正确的话,你需要一种“调试”方式来比较你所拥有的东西。
Let's assume you have a "this is how it should be"-struct:
让我们假设你有一个“它应该是这样的”-struct:
<cfset WSargs = StructNew()>
<cfset WSargs.AddCustomer = StructNew()>
<cfset WSargs.AddCustomer.postcode = "\d{5}">
<cfset WSargs.AddCustomer.org_name = ".+">
<cfset WSargs.AddCustomer.fax = ".*">
<cfset WSargs.AddCustomer.html = "^[01]$">
<cfset WSargs.AddCustomer.addr1 = ".*">
<cfset WSargs.AddCustomer.firstname = ".*">
<cfset WSargs.AddCustomer.city = ".*">
<cfset WSargs.AddCustomer.country = ".*">
<cfset WSargs.AddCustomer.taxable = ".*">
<cfset WSargs.AddCustomer.notify = "^[01]$">
<cfset WSargs.AddCustomer.lastname = ".*">
<cfset WSargs.AddCustomer.addr2 = ".*">
<cfset WSargs.AddCustomer.ssn = ".*">
<cfset WSargs.AddCustomer.taxrate = "^\d*$">
<cfset WSargs.AddCustomer.terms = ".*">
<cfset WSargs.AddCustomer.active = ".*">
<cfset WSargs.AddCustomer.state = ".*">
<cfset WSargs.AddCustomer.salutation= ".*">
<cfset WSargs.AddCustomer.password = ".+">
<cfset WSargs.AddCustomer.account_manager = "^[01]$">
And you want a function that compares the argumentcollection
to this.
你想要一个比较argumentcollection的函数。
<cffunction name="CompareStructs" returntype="array" output="no">
<cfargument name="template" type="struct" required="yes">
<cfargument name="data" type="struct" required="yes">
<cfset var errors = ArrayNew(1)>
<cfset var key = "">
<cfloop collection="#template#" item="key">
<cfif StructKeyExists(data, key)>
<cfif REFind(template[key], ToString(data[key])) eq 0>
<cfset ArrayAppend(errors, "Field '#key#' has an invalid value.")>
</cfif>
<cfelse>
<cfset ArrayAppend(errors, "Field '#key#' is missing.")>
</cfif>
</cfloop>
<cfloop collection="#data#" item="key">
<cfif not StructKeyExists(template, key)>
<cfset ArrayAppend(errors, "Field '#key#' is not allowed.")>
</cfif>
</cfloop>
<cfreturn errors>
</cffunction>
Called like this:
这样称呼:
<cfset errors = CompareStructs(WSargs.AddCustomer, stAguments)>
<cfif ArrayLen(errors) eq 0>
<cfinvoke
webservice="#ServiceURL#"
method="AddCustomer"
returnvariable="ResponseData"
argumentcollection="#stAguments#"
>
<cfinvokeargument name="api_key" value="#ServiceKey#" />
</cfinvoke>
<cfelse>
<cfdump var="#errors#" label="Errors calling AddCustomer()">
<cfabort>
<!--- or whatever --->
</cfif>
#2
your headache is stemming from just accepting the values that are passed into your method without validating that the input. this is easily fixed by adding validation and overloading into your method.
您的头痛源于仅接受传递给您的方法的值而不验证输入。通过在方法中添加验证和重载可以轻松解决这个问题。
#3
Finally I've finished with writing additional code to help me testing my service. Also, I needed to provide my API users with examples in CFML and combined these tasks.
最后,我完成了编写其他代码以帮助我测试我的服务。此外,我需要为我的API用户提供CFML中的示例并组合这些任务。
Would like to share code samples, maybe someone else will find them useful.
想分享代码示例,也许别人会觉得它们很有用。
I've used validating structures method (but a bit simplified it by removing regex'es because of they are overhead in my case -- service validates incoming arguments and reports errors). Main idea was to pull WSDL and build structure-template to compare with testing data. Also, added simple script with interface to test different methods, it helps me to test changes in service faster.
我已经使用了验证结构方法(但是通过删除正则表达式来简化它,因为它们在我的情况下是开销 - 服务验证传入的参数并报告错误)。主要思想是提取WSDL并构建结构模板以与测试数据进行比较。另外,添加了带有接口的简单脚本来测试不同的方法,它可以帮助我更快地测试服务中的变化。
So, here is UDFs for fetching WSDL and comparing structures (my XPath-fu can be not a perfect :) and here is base testing code.
所以,这里有用于获取WSDL和比较结构的UDF(我的XPath-fu可能不是完美:),这里是基本测试代码。
Hope this way of publishing code is not a rules violation. Thought it's not a good idea to post it all right here.
希望这种发布代码的方式不违反规则。认为在这里发布它不是一个好主意。
Special thanks to Tomalak for his ideas.
特别感谢Tomalak的想法。
#1
Really, it's an usability and time saving problem.
真的,这是一个可用性和节省时间的问题。
Okay, so if I understand you correctly, you need a "debugging" way to compare what you have to what you need.
好的,所以如果我理解正确的话,你需要一种“调试”方式来比较你所拥有的东西。
Let's assume you have a "this is how it should be"-struct:
让我们假设你有一个“它应该是这样的”-struct:
<cfset WSargs = StructNew()>
<cfset WSargs.AddCustomer = StructNew()>
<cfset WSargs.AddCustomer.postcode = "\d{5}">
<cfset WSargs.AddCustomer.org_name = ".+">
<cfset WSargs.AddCustomer.fax = ".*">
<cfset WSargs.AddCustomer.html = "^[01]$">
<cfset WSargs.AddCustomer.addr1 = ".*">
<cfset WSargs.AddCustomer.firstname = ".*">
<cfset WSargs.AddCustomer.city = ".*">
<cfset WSargs.AddCustomer.country = ".*">
<cfset WSargs.AddCustomer.taxable = ".*">
<cfset WSargs.AddCustomer.notify = "^[01]$">
<cfset WSargs.AddCustomer.lastname = ".*">
<cfset WSargs.AddCustomer.addr2 = ".*">
<cfset WSargs.AddCustomer.ssn = ".*">
<cfset WSargs.AddCustomer.taxrate = "^\d*$">
<cfset WSargs.AddCustomer.terms = ".*">
<cfset WSargs.AddCustomer.active = ".*">
<cfset WSargs.AddCustomer.state = ".*">
<cfset WSargs.AddCustomer.salutation= ".*">
<cfset WSargs.AddCustomer.password = ".+">
<cfset WSargs.AddCustomer.account_manager = "^[01]$">
And you want a function that compares the argumentcollection
to this.
你想要一个比较argumentcollection的函数。
<cffunction name="CompareStructs" returntype="array" output="no">
<cfargument name="template" type="struct" required="yes">
<cfargument name="data" type="struct" required="yes">
<cfset var errors = ArrayNew(1)>
<cfset var key = "">
<cfloop collection="#template#" item="key">
<cfif StructKeyExists(data, key)>
<cfif REFind(template[key], ToString(data[key])) eq 0>
<cfset ArrayAppend(errors, "Field '#key#' has an invalid value.")>
</cfif>
<cfelse>
<cfset ArrayAppend(errors, "Field '#key#' is missing.")>
</cfif>
</cfloop>
<cfloop collection="#data#" item="key">
<cfif not StructKeyExists(template, key)>
<cfset ArrayAppend(errors, "Field '#key#' is not allowed.")>
</cfif>
</cfloop>
<cfreturn errors>
</cffunction>
Called like this:
这样称呼:
<cfset errors = CompareStructs(WSargs.AddCustomer, stAguments)>
<cfif ArrayLen(errors) eq 0>
<cfinvoke
webservice="#ServiceURL#"
method="AddCustomer"
returnvariable="ResponseData"
argumentcollection="#stAguments#"
>
<cfinvokeargument name="api_key" value="#ServiceKey#" />
</cfinvoke>
<cfelse>
<cfdump var="#errors#" label="Errors calling AddCustomer()">
<cfabort>
<!--- or whatever --->
</cfif>
#2
your headache is stemming from just accepting the values that are passed into your method without validating that the input. this is easily fixed by adding validation and overloading into your method.
您的头痛源于仅接受传递给您的方法的值而不验证输入。通过在方法中添加验证和重载可以轻松解决这个问题。
#3
Finally I've finished with writing additional code to help me testing my service. Also, I needed to provide my API users with examples in CFML and combined these tasks.
最后,我完成了编写其他代码以帮助我测试我的服务。此外,我需要为我的API用户提供CFML中的示例并组合这些任务。
Would like to share code samples, maybe someone else will find them useful.
想分享代码示例,也许别人会觉得它们很有用。
I've used validating structures method (but a bit simplified it by removing regex'es because of they are overhead in my case -- service validates incoming arguments and reports errors). Main idea was to pull WSDL and build structure-template to compare with testing data. Also, added simple script with interface to test different methods, it helps me to test changes in service faster.
我已经使用了验证结构方法(但是通过删除正则表达式来简化它,因为它们在我的情况下是开销 - 服务验证传入的参数并报告错误)。主要思想是提取WSDL并构建结构模板以与测试数据进行比较。另外,添加了带有接口的简单脚本来测试不同的方法,它可以帮助我更快地测试服务中的变化。
So, here is UDFs for fetching WSDL and comparing structures (my XPath-fu can be not a perfect :) and here is base testing code.
所以,这里有用于获取WSDL和比较结构的UDF(我的XPath-fu可能不是完美:),这里是基本测试代码。
Hope this way of publishing code is not a rules violation. Thought it's not a good idea to post it all right here.
希望这种发布代码的方式不违反规则。认为在这里发布它不是一个好主意。
Special thanks to Tomalak for his ideas.
特别感谢Tomalak的想法。