Hi Luis,
We’ve been working with Relax 1.5 lately and have been very impressed with the new features. We do have some feedback and wanted to share it with the group.
Defining Endpoints in Relax.cfc
Headers - I have added headers to the config of an endpoint, as well parameters. When I select an endpoint on the right nav, the parameters load/populate, however the API headers do not. I have both global headers and enpoint specific headers defined.
We have an endpoint called /users/:id which can have both a GET and PUT method called on the resource. GET can only have parameter - essentially the ID, whereas PUT can have many parameters. We have these endpoint configured like so:
/****** Retrieve User ******/
{
pattern="/users/:id",description=“Retrieves User Profile”,methods=“GET,DELETE”
,headers=[
{name=“authorization”, required=true, type=“string”}
]
,parameters=[
{name=“apikey”, required=“true”}
]
,placeholders=[{name=“id”,description=“User ID”,required=true}]
,response=
{
schemas=[{format=“json”, description=“Success response status code 200. The following will be returned when the format requested is JSON.”, body=fileRead("#dirPath#schemas/user.json")}]
}
},
/****** Update User ******/
{
pattern="/users/:id",description=“Updates User Profile”,methods=“PUT”
,headers=[
{name=“authorization”, required=true, type=“string”}
]
,parameters=[
{name=“apikey”, required=“true”},
{name=“firstname”, required=“true”,type=“string”},
{name=“lastname”, required=“true”,type=“string”},
{name=“email”, required=“true”,type=“string”},
{name=“password”, required=“false”,type=“string”},
{name=“mobile_telephone”, required=“true”,type=“string”},
{name=“home_telephone”, required=“false”,type=“string”},
{name=“work_telephone”, required=“false”,type=“string”},
{name=“blood_type”, required=“false”,type=“int”,description=“0=unspecified,1=A+,2=A-,3=B+,4=B-,5=AB+,6=AB-,7=O+,8=O-”},
{name=“gender”, required=“false”,type=“int”,description=“0=unspecified,1=male,2=female”},
{name=“eye_color”, required=“false”,type=“int”,description=“0=unspecified,1=Amber,2=Blue,3=Brown,4=Grey,5=Green,6=Hazel,7=Red,8=Other”},
{name=“hair_color”, required=“false”,type=“int”,description=“0=unspecified,1=Black,2=Brown,3=Blonde,4=Dirty Blonde,5=Grey,6=Silver,7=White,8=Red,9=Orange,10=Blue,11=Other,12=None”},
{name=“height”, required=“false”,type=“int”,description=“Metric in cm”},
{name=“Weight”, required=“false”,type=“int”,description=“Metric in kg”}
]
,placeholders=[{name=“id”,description=“User ID”,required=true}]
,response=
{
schemas=[{format=“json”, description=“Success response status code 200. The following will be returned when the format requested is JSON.”, body=fileRead("#dirPath#schemas/user.json")}]
}
},
Creating two entries allows us to execute the endpoint easily with the required params prepopulated however it causes a few issues.
In the resource definitions list in the sidenav and the documentation it lists users/:id twice. this gets confusing because at first glance you don’t know which one is the GET and which one is the PUT. The way to resolve this would be to consolidate all of the information into one entry like so:
/****** User Endpoint******/
{
pattern="/users/:id",description=“Retrieves and updates a User profile”,methods=“GET,PUT,DELETE”
,headers=[
{name=“authorization”, required=true, type=“string”}
]
,parameters=[
{name=“apikey”, required=“true”},
{name=“firstname”, required=“true”,type=“string”},
{name=“lastname”, required=“true”,type=“string”},
{name=“email”, required=“true”,type=“string”},
{name=“password”, required=“false”,type=“string”},
{name=“mobile_telephone”, required=“true”,type=“string”},
{name=“home_telephone”, required=“false”,type=“string”},
{name=“work_telephone”, required=“false”,type=“string”},
{name=“blood_type”, required=“false”,type=“int”,description=“0=unspecified,1=A+,2=A-,3=B+,4=B-,5=AB+,6=AB-,7=O+,8=O-”},
{name=“gender”, required=“false”,type=“int”,description=“0=unspecified,1=male,2=female”},
{name=“eye_color”, required=“false”,type=“int”,description=“0=unspecified,1=Amber,2=Blue,3=Brown,4=Grey,5=Green,6=Hazel,7=Red,8=Other”},
{name=“hair_color”, required=“false”,type=“int”,description=“0=unspecified,1=Black,2=Brown,3=Blonde,4=Dirty Blonde,5=Grey,6=Silver,7=White,8=Red,9=Orange,10=Blue,11=Other,12=None”},
{name=“height”, required=“false”,type=“int”,description=“Metric in cm”},
{name=“Weight”, required=“false”,type=“int”,description=“Metric in kg”}
]
,placeholders=[{name=“id”,description=“User ID”,required=true}]
,response=
{
schemas=[{format=“json”, description=“Success response status code 200. The following will be returned when the format requested is JSON.”, body=fileRead("#dirPath#schemas/user.json")}]
}
},
I think the above (1 entry) is the preferred approach for documentation purposes however 2 entries (above above) is the preferred entry for testing purposes.
One entry simplifies the documentation and resource listings however it assumes that the parameters are used across all 3 methods, which is not the case. Is there a way that we can specify that a group of HTTP methods belong to the single endpoint, yet have different parameter configurations for different methods? I see that you’ve done this in the description field - i.e The user firstname. Only used on PUT and POST operations. I guess this is fine however it seems to be mixing the object definition with the method functionality. Just wondering if there is a better way of achieving clean documentation without sacrificing the testing functionality of Relax.
I also have a couple of other suggestions that I want to run by the group.
- Add a default method to an endpoint config. This is more for testing purposes so that when you load a resource in RelaxURL it defaults to say POST instead of GET. Currently everything defaults to GET
- The same applies for the format. Would it make sense to add format restrictions to an endpoint? i.e format=“JSON,JSONT”. It is quite possible in an API that the return format is not consistent across all API endpoints. i.e endpoint 1 only returns XML whereas endpoint2 returns JSON, JSONT,XML. Furthermore, it would be great to have a global setting to populate the return format drop down, as well as be able to had endpoint specific settings for populating the default. Again some of these suggestions are to help make testing easier, whereas some are to get granular in the documentation
- How do you define defaults for parameters and headers - I tried adding default=“foobars” to the below globalHeader config and this blows a CF error. What is the proper syntax to define a default?
this.globalHeaders = [
// Sample global header, Available keys: name,description,required,default,type
{name=“authorization”,description=“The apikey needed for request authentication.”,required=true,default=“foobars”}
];
- I noticed this in the the route generation -
// Throw exception 406 when an invalid extension is detected?
setThrowOnInvalidExtension( false );
Is this part of CB 3.5?
This is all I have right now. I welcome any feedback or suggestions from the list on the above. Loving Relax Louis. We use it daily in our development and testing.
Thanks very much.
Nolan