Skip to content

OPENAPI-04: Add testing capabilities to verify and validate the generated OpenAPI specification#2

Open
capernix wants to merge 8 commits intoopenmrs:mainfrom
capernix:OPENAPI-04
Open

OPENAPI-04: Add testing capabilities to verify and validate the generated OpenAPI specification#2
capernix wants to merge 8 commits intoopenmrs:mainfrom
capernix:OPENAPI-04

Conversation

@capernix
Copy link
Copy Markdown
Contributor

Description of what I changed

This PR focused on wrapping up with test classes to validate and verify the generated OpenAPI spec to further prove it's working. We run a test on the REST module where we access all the REST endpoints, and use various third party libraries like JSONSchema and REST assured to validate each property against all representation types (Like ref, default, full). It also had a lot of improvements in the schema introspector implementation for various bugs.

Checklist: I completed these to help reviewers :)

  • [ x] My IDE is configured to follow the code style of this project.

    No? Unsure? -> configure your IDE, format the code and add the changes with git add . && git commit --amend

  • [] I have added tests to cover my changes. (If you refactored
    existing code that was well tested you do not have to add tests)

    No? -> write tests and add them to this commit git add . && git commit --amend

  • [x] I ran mvn clean package right before creating this pull request and
    added all formatting changes to my commit.

    No? -> execute above command

  • [x] All new and existing tests passed.

    No? -> figure out why and add the fix to your commit. It is your responsibility to make sure your code works.

  • [x] My pull request is based on the latest changes of the master branch.

    No? Unsure? -> execute command git pull --rebase upstream master

Copy link
Copy Markdown
Collaborator

@chibongho chibongho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I definitely haven't looked through everything yet, as this is a huge PR. Here are my comment.

# OpenMRS REST OpenAPI Generator

![alt text](src/static/openmrs.png)
![OpenMRS Logo](src/static/openmrs.png)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will, hopefully, be more than just a GSoC project. Can you remove this image, or replace with something more appropriate?

![OpenMRS Logo](src/static/openmrs.png)

A sophisticated Maven plugin that programmatically analyzes OpenMRS REST resources at build time to extract detailed representation metadata. This plugin uses a forked process approach to overcome Maven plugin classloader limitations and provides comprehensive analysis of REST resource handlers with their representation structures.
A Maven plugin that automatically generates **OpenAPI 3.0 specifications** from OpenMRS REST resources during the build process. This plugin uses runtime introspection to analyze REST resource handlers and produces comprehensive API documentation that's ready for tools like Swagger UI, Postman, or API clients.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A Maven plugin that automatically generates **OpenAPI 3.0 specifications** from OpenMRS REST resources during the build process. This plugin uses runtime introspection to analyze REST resource handlers and produces comprehensive API documentation that's ready for tools like Swagger UI, Postman, or API clients.
A Maven plugin that, when applied to OpenMRS modules, automatically generates **OpenAPI 3.0 specifications** for the module's REST resources during the build process. This plugin uses runtime introspection to analyze REST resource handlers and produces comprehensive API documentation that's ready for tools like Swagger UI, Postman, or API clients.

## 🚀 What This Plugin Does

This plugin automatically discovers and analyzes **all OpenMRS REST resource handlers** in your project, extracting:
The plugin **automatically discovers and analyzes** OpenMRS REST resources in your module, generating:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the eventual goals of the plugin, but I think it's important that we:

  • mention that it's a work in progress and not completed yet
  • document what works (GET routes, the usual representations) and doesn't work (POST / DELETE routes, named representations) as of now. Avoid words like "Complete" until we are actually there.

Maybe also mention that, for now, this plugin has been tested against the REST module and queues module.


## 📊 Sample Output

The plugin generates a complete OpenAPI 3.0 specification like this:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove "complete"

### 1. Install the Plugin

### Installation
First, build and install the plugin to your local Maven repository:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still accurate? We published the plugin, so no need to install locally right?

private static JsonSchemaFactory schemaFactory;

// Known working endpoints from ResilientContractTest - guaranteed to be accessible
private static final List<String> GUARANTEED_WORKING_ENDPOINTS = Arrays.asList(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ambiguous what "working" means, maybe rename to KNOWN_ACCESSIBLE_ENDPOINTS?

return resourceName.substring(0, 1).toUpperCase() + resourceName.substring(1).toLowerCase();
}

private List<String> getAllEndpointsFromOpenApiSpec() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this only return GET endpoints? If so, give it a better name.

Also, why do we need paths for both /ws/rest/v1/<resource> and /ws/rest/v1/<resource>/uuid? Isn't one of them sufficient for testing the GET representations?

private String extractEndpointFromPath(String path) {
// Convert "/ws/rest/v1/concept/{uuid}" to "/concept"
if (path.startsWith("/ws/rest/v1/")) {
path = path.substring("/ws/rest/v1".length());
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-assigning to the input variable like this is confusing.

}

// Remove {uuid} part
if (path.contains("/{uuid}")) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be else if?

Or better yet, can we just do early return?

return path.substring(0, path.indexOf("/{uuid}"));

private List<String> getAvailableRepresentationsForEndpoint(String endpoint) {
Set<String> representations = new HashSet<>();

// Skip problematic representations for known endpoints
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Elaborate on the problems. Would be nice if the comment also links to relevant JIRA tickets

/**
* Maps representation types to the corresponding method names that take delegate parameters
*/
private String getRepresentationMethodName(Representation representation) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is bad. We must not be depend on / assume the function name of the RepHandler. Loop through the methods of the class to find the @RepHandler function instead.

}

// Phase 1 Enhancement: Made package-private for testing
Schema<?> mapToSwaggerSchema(String javaType, Components components, String representationHint, boolean isArrayItem) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found that the swagger library has a ModelConverters class for this kind of thing. We shouldn't need to map int / string / boolean / date types ourselves. See if we can rely on that API to handle more complex types as well.


String resourceName = annotation.name();
String resourcePath = "/ws/rest/" + resourceName + "/{uuid}";
String resourcePath = "/ws/rest/" + RestConstants.VERSION_1 + "/" + resourceName + "/{uuid}";
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This incorrectly creates path with "v1" appearing twice, as in /ws/rest/v1/v1/patient

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants