Attributes for Documenting TEMSDataSetResource
I recently blogged about a number of RAD Server topics, including using TEMSDataSetResource, (the component that enables a TDataSet to be expose as a RESTful resource, and manage all the List, Get, Put, Post, Delete methods – very cool!), how to set named parameters for the TEMSDataSetResource documentation (where multiple keys are passed in e.g. with Master Detail relationships (reviewed below)), and how the YAML and JSON documentation is auto generated with custom RESTful resources / end points
Typically, each custom REST endpoint method (List, Get, Put, Post, Delete), would be supported by separate procedures in the code, with each having their attributes to support documentation, resource name etc.
Typically, List and Post would have no parameters, but Get, Put and Delete would all take the ID of the object being requested / updated / removed. The approach with separate procedures in code makes it very easy to add attributes to list parameters based on their method. Which leads me to the challenge with TEMSDataSetResource. How do you define parameters for the different methods with the same component?
ResourceSuffix Attribute
In the last blog, I highlighted how the ResourceSuffix can be used to set the name of values in the resource, rather than using the default ‘id’ value. – This is essential when multiple parameters are used.
[ResourceName('exams')] TExamsResource1 = class(TDataModule) [ResourceSuffix('./{EXAM_ID}/questions')] [ResourceSuffix('List', './')] [ResourceSuffix('Get', './{QUESTION_ID}')] [ResourceSuffix('Post', './')] [ResourceSuffix('Put', './{QUESTION_ID}')] [ResourceSuffix('Delete', './{QUESTION_ID}')] dsrEXAM_QUESTIONS: TEMSDataSetResource;
The documentation picks up the parameter name automatically into the YAML documentation for that method. But now it needs to be defined. In this example, EXAM_ID is required for each call, and QUESTION_ID is also required, but only for the Get, Put and Delete.
EndPointRequestParameter Attribute
To define the required attribute EXAM_ID, it is possible to use a single EndPointRequestParameterAttribute (note: Attribute part of the name at the end is optional)
[EndPointRequestParameter( TAPIDocParameter.TParameterIn.Path, 'EXAM_ID', // Param name 'EXAM_ID for the selected /exam/ ', //about it true, // required TAPIDoc.TPrimitiveType.spInteger, // type TAPIDoc.TPrimitiveFormat.Int64, // ext format TAPIDoc.TPrimitiveType.spInteger, // array? '', // Scheme '')] // Reference dsrEXAM_QUESTIONS: TEMSDataSetResource;
But here in lies the twist….. If we did the same for QUESTION_ID, we would have issues with it showing for List and Post. The answer (once found) is actually quite simple. You need to define the parameters in the same way as the ResourceSuffix. e.g.
[EndPointRequestParameter( 'Get', TAPIDocParameter.TParameterIn.Path, 'QUESTION_ID', // Param name 'QUESTION_ID for the question to get', //desc true, // required TAPIDoc.TPrimitiveType.spInteger, // type TAPIDoc.TPrimitiveFormat.Int64, // ext format TAPIDoc.TPrimitiveType.spInteger, // array? '', // Scheme '')] // Reference [EndPointRequestParameter( 'Put', TAPIDocParameter.TParameterIn.Path, 'QUESTION_ID', // Param name 'QUESTION_ID for question to update', //desc true, // required TAPIDoc.TPrimitiveType.spInteger, // type TAPIDoc.TPrimitiveFormat.Int64, // ext format TAPIDoc.TPrimitiveType.spInteger, // array? '', // Scheme '')] // Reference [EndPointRequestParameter( 'Delete', TAPIDocParameter.TParameterIn.Path, 'QUESTION_ID', // Param name 'QUESTION_ID for the question to delete ', true, // required TAPIDoc.TPrimitiveType.spInteger, // type TAPIDoc.TPrimitiveFormat.Int64, // ext format TAPIDoc.TPrimitiveType.spInteger, // array? '', // Scheme '')] // Reference dsrEXAM_QUESTIONS: TEMSDataSetResource;
The issue here however, is that as soon as you define method specific attributes, you stop inheriting the defined parameters for the TEMSDataSetResource. This means you need to define all of parameters them for that method. (so you need to add in the EXAM_ID again for each of the Get, Put and Delete methods with extra EndPointRequestParameter’s) e.g..
[EndPointRequestParameter( 'Get', TAPIDocParameter.TParameterIn.Path, 'EXAM_ID', // Param name 'EXAM_ID for the exam to get', //desc true, // required TAPIDoc.TPrimitiveType.spInteger, // type TAPIDoc.TPrimitiveFormat.Int64, // ext format TAPIDoc.TPrimitiveType.spInteger, // array? '', // Scheme '')] // Reference [EndPointRequestParameter( 'Get', TAPIDocParameter.TParameterIn.Path, 'QUESTION_ID', // Param name 'QUESTION_ID for question to update', //desc true, // required TAPIDoc.TPrimitiveType.spInteger, // type TAPIDoc.TPrimitiveFormat.Int64, // ext format TAPIDoc.TPrimitiveType.spInteger, // array? '', // Scheme '')] // Reference ...
EndPointRequestSummary Attribute
The same approach can also be used for the EndPointRequestSummaryAttribute.
[EndPointRequestSummary ('Exams', // Tags 'Exams', // Summary 'Each Exam has a list of questions, each containing multiple answers', // Description 'application/json', // Produces '')] // Consumes or [EndPointRequestSummary ('Get', // Method 'Exams', // Tags 'Exams', // Summary 'Fetches an specific Exam', // Description 'application/json', // Produces '')] // Consumes etc
More about attributes…
See Custom_API_Documentation on DocWiki