Skip to content

Now can override default status code with @Produces #150

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions http-api/src/main/java/io/avaje/http/api/Produces.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,26 @@
*
* }</pre>
*/
@Target(value={TYPE, METHOD})
@Retention(value=RUNTIME)
@Target(value = {TYPE, METHOD})
@Retention(value = RUNTIME)
public @interface Produces {

String value();
/**
* Specify response media type.
*
* <p>When not specified the default MediaType is APPLICATION_JSON
*/
String value() default MediaType.APPLICATION_JSON;

/**
* The default status code of the generated route.
*
* <p>When not specified, the default status are as follows: <br>
* GET(200) <br>
* POST(201) <br>
* PUT(200, void methods 204) <br>
* PATCH(200, void methods 204) <br>
* DELETE(200, void methods 204)
*/
int defaultStatus() default 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class MethodReader {
* Holds enum Roles that are required for the method.
*/
private final List<String> methodRoles;
private final String produces;
private final Optional<Produces> producesAnnotation;
private final List<OpenAPIResponse> apiResponses;
private final ExecutableType actualExecutable;
private final List<? extends TypeMirror> actualParams;
Expand All @@ -54,7 +54,7 @@ public class MethodReader {
this.actualParams = (actualExecutable == null) ? null : actualExecutable.getParameterTypes();
this.isVoid = element.getReturnType().getKind() == TypeKind.VOID;
this.methodRoles = Util.findRoles(element);
this.produces = produces(bean);
this.producesAnnotation = Optional.ofNullable(findAnnotation(Produces.class));
initWebMethodViaAnnotation();

this.superMethods = ctx.superMethods(element.getEnclosingElement(), element.getSimpleName().toString());
Expand Down Expand Up @@ -151,11 +151,6 @@ public Javadoc javadoc() {
return javadoc;
}

private String produces(ControllerReader bean) {
final var produces = findAnnotation(Produces.class);
return (produces != null) ? produces.value() : bean.produces();
}

private List<OpenAPIResponse> buildApiResponses() {
final var container =
Optional.ofNullable(findAnnotation(OpenAPIResponses.class)).stream()
Expand Down Expand Up @@ -275,8 +270,12 @@ public boolean isVoid() {
return isVoid;
}

public boolean hasProducesStatus() {
return producesAnnotation.map(Produces::defaultStatus).filter(s -> s > 0).isPresent();
}

public String produces() {
return produces;
return producesAnnotation.map(Produces::value).orElseGet(bean::produces);
}

public List<OpenAPIResponse> apiResponses() {
Expand All @@ -291,7 +290,11 @@ public TypeMirror returnType() {
}

public String statusCode() {
return Integer.toString(webMethod.statusCode(isVoid));

return producesAnnotation
.map(Produces::defaultStatus)
.filter(s -> s > 0)
.orElseGet(() -> webMethod.statusCode(isVoid)).toString();
}

public PathSegments pathSegments() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public void build() {
response.setDescription(javadoc.getReturnDescription());

final var produces = methodReader.produces();
final var hasProducesStatus = methodReader.hasProducesStatus();
final var contentMediaType = (produces == null) ? MediaType.APPLICATION_JSON : produces;

if (methodReader.isVoid()) {
Expand All @@ -99,7 +100,7 @@ public void build() {
// if user wants to define their own 2xx status code
if (responseAnnotation.responseCode().startsWith("2")) {
newResponse.setContent(response.getContent());
override2xx = true;
override2xx = !hasProducesStatus;
}
TypeMirror returnType = null;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.avaje.http.api.Path;
import io.avaje.http.api.Post;
import io.avaje.http.api.Produces;
import io.avaje.http.api.Put;
import io.javalin.http.Context;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
Expand Down Expand Up @@ -78,4 +79,17 @@ Person testPostl(List<Person> m) {

return new Person(0, "baby");
}

@Put("/put")
@Produces(value = MediaType.TEXT_PLAIN, defaultStatus = 203)
@OpenAPIResponse(responseCode = "204", type = String.class)
String testDefaultStatus(Context ctx) {

if (ctx.contentType().equals(MediaType.APPLICATION_PDF)) {
ctx.status(204);
return "";
}

return "only partial info";
}
}
35 changes: 33 additions & 2 deletions tests/test-javalin-jsonb/src/test/resources/expectedOpenApi.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,39 @@
},
"deprecated": true
}
}
},
},
"/openapi/put" : {
"put" : {
"tags" : [

],
"summary" : "",
"description" : "",
"responses" : {
"204" : {
"description" : "",
"content" : {
"text/plain" : {
"schema" : {
"type" : "string"
}
}
}
},
"203" : {
"description" : "",
"content" : {
"text/plain" : {
"schema" : {
"type" : "string"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"ErrorResponse": {
Expand Down