Normally, a custom proof type is associated with a single dataset defined in your 'dataSource.json'. This single dataset is usually a GET or even a POST whose response contains the data we want to display in our proof. When Hyperproof is asked to generate proof, this API endpoint is called, and the response is transformed into our proof per the 'proof.json' file we created.
A common scenario when generating reports with a REST API is sending a POST request with some reporting criteria so that the target application can generate a report. The target application then needs time to generate a custom response based on this criteria. Then, sometime after the report has been generated, a second GET request is sent to retrieve the data from the report.
It is possible to work with multiple calls, each with its own criteria, when retrieving a single proof, although we have not provided samples in the Hypersync SDK.
One customer has the following scenario...
- A POST request is made with beginning and end date criteria, telling the target application to generate a report. This returns 'searchJobId' as a response.
- A GET request is made using the 'searchJobId' parameter to determine the 'status' of the report. This returns a 'status' of "Generating Report" or "Report is Ready"
- A GET request is made using the 'searchJobId' to retrieve the contents of the report that is now ready and use the data in our proof.
Let's solve for this use case.
First, let's take care of what we already know how to do by leveraging the SDK's JSON markup as much as possible. We can start by defining our proof and our final dataset in the normal manner, as though the previous two API calls were not required.
In our 'datasource.json', define the reportDataset as we normally would, including the 'searchJobId' in the appropriate location.
For example, as a URL parameter
"url": "/v2/getReport/{{searchJobId}}",Next, we can define our 'proof.json' as we normally would, this time leaving the criteria array EMPTY...
"criteria": [],At the same time, add 'searchJobId' to our dataSetParams property...
"dataSetParams": { "searchJobId": "{{criteria.searchJobId}}"}NOTE: We do NOT have to create this criteria in the 'criteria.json' file. We will create the 'searchJobId' criteria value programmatically later on.
Next, let's add all the information we know about the two pre-requisite calls that need to be made. We need to create two more datasets in our 'datasource.json' file.
A dataset that POST's the request to generate the report. We will call this 'generateReport'.
A dataset that GET's the status of the report. We will call this 'getReportStatus'.
The 'generateReport' dataset can be defined, again, as any normal dataset. Putting '{{beginDate}}' and '{{endDate}}' in the appropriate locations (URL, body, etc). Be sure to return the 'searchJobId' field that we are looking for, as a property in the 'transform' section of the dataset.
The 'getReportStatus' dataset can be defined like any other GET request, designating the fields to retrieve and utilizing the job Id returned from the post. Be sure to return the 'status' field that we are looking for as a property in the 'transform' section of the dataset.
Again, as a URL parameter
"url": "/v2/getReportStatus/{{searchJobId}}",Now we are all set with our proof and the datasets that are required to generate this proof...
We now need to tell Hyperproof to interrupt the generation of this proof, and run each dataset in the correct order to get the job id AND make sure the data is ready.
This step requires a little bit of TypeScript programming.
In our 'App.ts' file, we will add an override method that tells the Hypersync to run the API calls in the correct order.
At the bottom of the file, add a method 'public override async getProofData'.
As you type, your IDE should help you fill in the blanks. If not, you should have a method that looks like this...
public override async getProofData(
dataSource: IDataSource, criteriaProvider: ICriteriaProvider,
proofProviderFactory: ProofProviderFactory,
hypersync: IHypersync, hyperproofUser: IHyperproofUser, userProfile: object,
syncStartDate: string, page?: string, metadata?: SyncMetadata, retryCount?: number):
Promise<IProofFile[] | IGetProofDataResponse> {
return super.getProofData(dataSource,criteriaProvider,proofProviderFactory,hypersync,hyperproofUser,userProfile,syncStartDate,page,metadata,retryCount)
}The 'getProofData' method is called anytime a proof is generated. We are overriding this method in order to interrupt the process and add any additional information needed before the proof is generated.
Inside this override method, we are going to add some code with comments to call each of the pre-requisite API calls.
//lets set some variables from the input.
const { settings } = hypersync;
const { criteria } = settings;
const POLL_INTERVAL = 5000; // Wait 5 seconds between checks
//we can generate start and end times for the report
//we will set the report for a 12 hour period
// Set endDate to the current time
const endDate = new Date();
// Set beginDate to 12 hours earlier
const beginDate = new Date(now.getTime() - (12 * 60 * 60 * 1000));
//only override if HP is requesting this particular proof..
// we want to make sure that we only run our pre-requisite API calls on this particular proof
if (criteria.proofType === 'name_of_our_report_proof') {
//tell HP to do the POST request to the server using our dataset name
//set the begin and end dates into the criteria for this call
//the result will return our 'searchJobId'
const generateReportDataresult = await dataSource.getData(
'generateReport' , { "beginDate": beginDate, "endDate": endDate, }
);
//set 'searchJobId' from our generateReportDataresult into our criteria settings for the final proof
// @ts-expect-error: type mismatch
hypersync.settings.criteria.searchJobId = generateReportDataresult.data.searchJobId;
//define our 'getReportStatus' data result
let getReportStatusDataresult;
//the following comment prevents errors in the build process because typescript doesn't know about the resulting dataset structure
// @ts-expect-error: type mismatch
while (getReportStatusDataresult.data.status != "Report is Ready") {
//Loop until the getReportStatus dataset indicates "Report is Ready"
//Pause 5 seconds between calls to allow time for the dataset to be ready.
await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL)); // Delay before the next check
//Here we call the getReportStatus and manually add the criteria of 'searchJobId'
getReportStatusDataresult = await dataSource.getData(
// @ts-expect-error: type mismatch
'getReportStatus', { "searchJobId": generateReportDataresult.data.searchJobId }
);
}
//We have existed the loop, indicating that the report is ready.
//Hyperproof can continue and generate the proof as though none of the above code has interrupted it.
}- Checks to make sure we are generating the correct proof
if (criteria.proofType === 'name_of_our_report_proof') {- Calls the 'generateReport' Dataset
const generateReportDataresult = await dataSource.getData(
'generateReport'
);- Sets the job id into the criteria array
hypersync.settings.criteria.searchJobId = generateReportDataresult.data.searchJobId;- Checks the status of the report data by calling the 'getReportStatus' dataset with the job id
getReportStatusDataresult = await dataSource.getData(
// @ts-expect-error: type mismatch
'getReportStatus', { "searchJobId": generateReportDataresult.data.searchJobId }
);- after the status is confirmed, we return the processing back to Hyperproof to generate the proof normally, but with our job id added to the criteria. (from step 3 above)
return super.getProofData(dataSource,criteriaProvider,proofProviderFactory,hypersync,hyperproofUser,userProfile,syncStartDate,page,metadata,retryCount)This should serve as a good example of how to override 'getProofData' and perform additional actions required by certain proof.