Attributes for Documenting TEMSDataSetResource

by Jan 15, 2020

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

The post Attributes for Documenting TEMSDataSetResource appeared first on Stephen Ball's Technical Blog.