diff --git a/src/lib/src/main/java/gov/usgs/earthquake/nshmp/netcdf/www/Swagger.java b/src/lib/src/main/java/gov/usgs/earthquake/nshmp/netcdf/www/Swagger.java new file mode 100644 index 0000000000000000000000000000000000000000..8f586df432531674a0df97649703a6dd745635da --- /dev/null +++ b/src/lib/src/main/java/gov/usgs/earthquake/nshmp/netcdf/www/Swagger.java @@ -0,0 +1,173 @@ +package gov.usgs.earthquake.nshmp.netcdf.www; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import gov.usgs.earthquake.nshmp.geo.Bounds; +import gov.usgs.earthquake.nshmp.geo.Location; +import gov.usgs.earthquake.nshmp.geo.LocationList; +import gov.usgs.earthquake.nshmp.netcdf.NetcdfDataFiles; +import gov.usgs.earthquake.nshmp.netcdf.data.NetcdfData; +import gov.usgs.earthquake.nshmp.netcdf.data.ScienceBaseMetadata; +import gov.usgs.earthquake.nshmp.www.SwaggerUtils; + +import io.micronaut.http.HttpRequest; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.parser.OpenAPIV3Parser; + +/** + * Update Swagger landing page. + * + * @author U.S. Geological Survey + */ +abstract class Swagger<T extends NetcdfService<?>> { + + final HttpRequest<?> request; + final T service; + + Swagger(HttpRequest<?> request, T service) { + this.request = request; + this.service = service; + } + + /** + * Returns the main description header text. + */ + abstract String descriptionHeader(); + + /** + * Returns the service info text. + */ + abstract String serviceInfo(); + + /** + * Returns the service patterns sections + */ + abstract String servicePatternSection(); + + /** + * Creeates the main swagger description section. + * + * @param netcdfDataFiles The data files + */ + String description(NetcdfDataFiles<?> netcdfDataFiles) { + StringBuilder builder = new StringBuilder() + .append(serviceInfo()) + .append("\n## " + descriptionHeader() + "\n"); + + netcdfDataFiles + .forEach(netcdf -> { + ScienceBaseMetadata metadata = netcdf.netcdfData().scienceBaseMetadata(); + builder + .append("### " + metadata.label + "\n") + .append(metadata.description + "\n") + .append(parameterSection(netcdf.netcdfData()) + "\n") + .append(scienceBaseSection(metadata) + "\n"); + }); + + return builder.toString(); + } + + /** + * Creates the parameter section for the description. + * + * @param netcdfData The NetCDF data + */ + String parameterSection(NetcdfData netcdfData) { + return new StringBuilder() + .append( + "<details>\n" + + "<summary>Parameters</summary>\n") + .append( + SwaggerUtils.locationBoundsInfo(netcdfData.minimumBounds(), netcdfData.maximumBounds(), + Optional.of("###"))) + .append(SwaggerUtils.siteClassInfo(netcdfData.siteClasses(), Optional.of("###"))) + .append("</details>") + .toString(); + } + + /** + * Creates the response format section for the description. + */ + String responseFormatSection() { + return new StringBuilder() + .append( + "<details>\n" + + "<summary>Response Format: CSV or JSON</summary>\n") + .append( + "The web service can respond in JSON or CSV format.\n" + + "<br><br>" + + "Choose the format type by adding a `format` query to the service call:" + + "`?format=JSON` or `?format=CSV`\n\n" + + "<br><br>" + + "Default: `JSON`") + .append("</details>") + .toString(); + } + + /** + * Creates the science base section for the description. + * + * @param scienceBaseMetadata The metadata. + */ + String scienceBaseSection(ScienceBaseMetadata scienceBaseMetadata) { + return new StringBuilder() + .append( + "<details>\n" + + "<summary>ScienceBase Information</summary>\n") + .append("Data history: " + scienceBaseMetadata.history) + .append("<br><br>") + .append( + String.format( + "Returned data are spatially interpolated from " + + "the %s grid data from ScienceBase:\n", + scienceBaseMetadata.gridStep)) + .append(Arrays.stream(scienceBaseMetadata.scienceBaseInfo) + .map(info -> String.format("- [%s](%s)", info.url, info.url)) + .collect(Collectors.joining("\n"))) + .append("</details>") + .toString(); + } + + void updateLocationBounds(OpenAPI openApi) { + List<Location> locations = service.netcdfDataFiles().stream() + .map(netcdf -> netcdf.netcdfData()) + .flatMap(netcdfData -> List.of(netcdfData.minimumBounds(), netcdfData.maximumBounds()).stream()) + .collect(Collectors.toList()); + + Bounds bounds = LocationList.copyOf(locations).bounds(); + SwaggerUtils.addLocationBounds(openApi, bounds.min, bounds.max); + } + + /** + * Update the {@link OpenAPI} documentation. + * + * @throws IOException + */ + OpenAPI updateOpenApi() throws IOException { + OpenAPI openApi = new OpenAPIV3Parser().read("META-INF/swagger/nshmp-ws-static.yml"); + updateLocationBounds(openApi); + Components components = openApi.getComponents(); + Map<String, Schema> schemas = components.getSchemas(); + SwaggerUtils.siteClassSchema(schemas, List.copyOf(service.netcdfDataFiles().siteClasses())); + openApi.servers(null); + + openApi.getInfo().setTitle(service.getServiceName()); + + // Update description + String description = new StringBuilder() + .append(description(service.netcdfDataFiles())) + .append("## Formating \n" + responseFormatSection() + "\n") + .append("## Service Patterns \n" + servicePatternSection()) + .toString(); + openApi.getInfo().setDescription(description); + + return openApi; + } +}