Skip to content

Commit

Permalink
Add API documentation using swagger
Browse files Browse the repository at this point in the history
  • Loading branch information
bertrik committed Mar 30, 2024
1 parent 9b7326b commit 27b0a68
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 7 deletions.
6 changes: 4 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,20 @@ retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref= "retrofit"
retrofit-jackson = { module = "com.squareup.retrofit2:converter-jackson", version.ref= "retrofit" }
retrofit-scalars = { module = "com.squareup.retrofit2:converter-scalars", version.ref= "retrofit" }

dropwizard-core = { module = "io.dropwizard:dropwizard-core", version.ref = "dropwizard" }
dropwizard-assets = { module = "io.dropwizard:dropwizard-assets", version.ref = "dropwizard" }
dropwizard-core = { module = "io.dropwizard:dropwizard-core", version.ref = "dropwizard" }
dropwizard-swagger = { module = "com.smoketurner:dropwizard-swagger", version = "4.0.5-1" }

jersey-media-sse = { module = "org.glassfish.jersey.media:jersey-media-sse", version = "3.1.5" }
jdbf = { module = "com.github.spyhunter99:jdbf", version = "2.2.4" }

junit = { module = "junit:junit", version = "4.13.2" }

swagger-annotations = { module = "io.swagger:swagger-annotations", version = "1.6.14" }

[bundles]
jackson = ["jackson-bind", "jackson-yaml", "jackson-xml", "jackson-jsr310", "jackson-jdk8"]
retrofit = ["retrofit", "retrofit-jackson", "retrofit-scalars"]
dropwizard = ["dropwizard-core", "dropwizard-assets"]

[plugins]
versions = { id = "com.github.ben-manes.versions", version = "0.51.0" }
Expand Down
8 changes: 5 additions & 3 deletions verkeersdrukte/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ application {
dependencies {
implementation libs.bundles.retrofit
implementation libs.bundles.jackson
implementation libs.bundles.dropwizard
implementation libs.jdbf

// https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-sse
implementation libs.dropwizard.core
implementation libs.dropwizard.assets
implementation libs.dropwizard.swagger
implementation libs.jdbf
implementation libs.jersey.media.sse
implementation libs.swagger.annotations
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package nl.bertriksikken.verkeersdrukte.app;

import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.info.Contact;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.servers.Server;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.sse.Sse;
import jakarta.ws.rs.sse.SseEventSink;
import nl.bertriksikken.geojson.FeatureCollection;

import java.net.URISyntaxException;
import java.util.Optional;

@OpenAPIDefinition(
info = @Info(
title = "Verkeersdrukte",
description = "Provides near real-time speed/intensity data for motorways in the Netherlands",
contact = @Contact(name = "Bertrik Sikken", email = "[email protected]")),
servers = {@Server(url = "https://stofradar.nl"), @Server(url = "http://stofradar.nl:9002")},
tags = {@Tag(name = "static"), @Tag(name = "dynamic")})
public interface IVerkeersDrukteResource {
@Operation(hidden = true)
void redirectSwagger() throws URISyntaxException;

@Operation(summary = "Get GeoJSON containing all locations")
@Tag(name = "static")
FeatureCollection getStatic();

@Operation(summary = "Get static data for a specific location")
@Tag(name = "static")
Optional<FeatureCollection.Feature> getStatic(@PathParam("location") String location);

@Operation(summary = "Get dynamic traffic data for a specific location")
@Tag(name = "dynamic")
Optional<VerkeersDrukteResource.MeasurementResult> getDynamic(@PathParam("location") String location);

@Operation(summary = "Get event stream with dynamic traffic data for a specific location")
@Tag(name = "dynamic")
void getTrafficEvents(@Context Sse sse, @Context SseEventSink sseEventSink, @PathParam("location") String location);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
import io.dropwizard.assets.AssetsBundle;
import io.dropwizard.core.Application;
import io.dropwizard.core.Configuration;
import io.dropwizard.core.setup.Bootstrap;
import io.dropwizard.core.setup.Environment;
import io.federecio.dropwizard.swagger.SwaggerBundle;
import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerResponseContext;
import jakarta.ws.rs.container.ContainerResponseFilter;
Expand All @@ -29,6 +32,10 @@ private VerkeersDrukteApp() {
public void initialize(Bootstrap<VerkeersDrukteAppConfig> bootstrap) {
bootstrap.getObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
bootstrap.addBundle(new AssetsBundle("/assets/verkeersdrukte.png", "/favicon.ico"));

SwaggerBundleConfiguration swaggerBundleConfiguration = new SwaggerBundleConfiguration();
swaggerBundleConfiguration.setResourcePackage(VerkeersDrukteResource.class.getPackage().getName());
bootstrap.addBundle(new TrafficSwaggerBundle(swaggerBundleConfiguration));
}

@Override
Expand All @@ -46,7 +53,7 @@ public void run(VerkeersDrukteAppConfig configuration, Environment environment)
}

private void addHeaders(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
headers.forEach((header,value) -> responseContext.getHeaders().add(header, value));
headers.forEach((header, value) -> responseContext.getHeaders().add(header, value));
}

public static void main(String[] args) throws Exception {
Expand All @@ -63,4 +70,17 @@ public static void main(String[] args) throws Exception {
app.run("server", CONFIG_FILE);
}

private static final class TrafficSwaggerBundle extends SwaggerBundle<Configuration> {
private final SwaggerBundleConfiguration swaggerBundleConfiguration;

TrafficSwaggerBundle(SwaggerBundleConfiguration configuration) {
this.swaggerBundleConfiguration = configuration;
}

@Override
protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(Configuration configuration) {
return swaggerBundleConfiguration;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URI;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
Expand All @@ -32,7 +33,7 @@

@Path(VerkeersDrukteResource.TRAFFIC_PATH)
@Produces(MediaType.APPLICATION_JSON)
public final class VerkeersDrukteResource {
public final class VerkeersDrukteResource implements IVerkeersDrukteResource {
private static final Logger LOG = LoggerFactory.getLogger(VerkeersDrukteResource.class);

static final String TRAFFIC_PATH = "/traffic";
Expand All @@ -52,6 +53,14 @@ public final class VerkeersDrukteResource {
mapper.findAndRegisterModules();
}

@Override
@GET
@Path("/")
public void redirectSwagger() {
throw new RedirectionException(301, URI.create("/swagger"));
}

@Override
@GET
@Path(STATIC_PATH)
public FeatureCollection getStatic() {
Expand Down Expand Up @@ -81,6 +90,7 @@ private FeatureCollection.Feature addUrlProperties(FeatureCollection.Feature f)
return feature;
}

@Override
@GET
@Path(STATIC_PATH + "/{location}")
public Optional<FeatureCollection.Feature> getStatic(@PathParam("location") String location) {
Expand All @@ -91,6 +101,7 @@ public Optional<FeatureCollection.Feature> getStatic(@PathParam("location") Stri
return Optional.ofNullable(feature);
}

@Override
@GET
@Path(DYNAMIC_PATH + "/{location}")
@CacheControl(maxAge = 1, maxAgeUnit = TimeUnit.MINUTES)
Expand All @@ -103,6 +114,7 @@ public Optional<MeasurementResult> getDynamic(@PathParam("location") String loca
return Optional.of(new MeasurementResult(aggregateMeasurement));
}

@Override
@GET
@Path(DYNAMIC_PATH + "/{location}/events")
@Produces(MediaType.SERVER_SENT_EVENTS)
Expand Down

0 comments on commit 27b0a68

Please sign in to comment.