Skip to content

Commit a9d93ff

Browse files
committed
always json
1 parent d55a7a6 commit a9d93ff

File tree

4 files changed

+78
-62
lines changed

4 files changed

+78
-62
lines changed
Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package io.avaje.http.inject;
22

3-
import static java.util.stream.Collectors.joining;
4-
53
import io.avaje.http.api.ValidationException;
64
import io.helidon.webserver.http.HttpFeature;
75
import io.helidon.webserver.http.HttpRouting.Builder;
@@ -16,19 +14,9 @@ public void setup(Builder routing) {
1614
routing.error(ValidationException.class, this::handle);
1715
}
1816

19-
private void handle(ServerRequest req, ServerResponse res, ValidationException exception) {
20-
var violations = exception.getErrors();
21-
22-
int violationCount = violations.size();
23-
String violationList =
24-
violations.stream()
25-
.map(violation -> "'" + violation.getField() + "' " + violation.getMessage())
26-
.collect(joining("\n"));
17+
private void handle(ServerRequest req, ServerResponse res, ValidationException ex) {
2718

28-
res.status(exception.getStatus())
29-
.send(
30-
String.format(
31-
"Bad Request [%s validation violations: \n%s]", violationCount, violationList)
32-
.getBytes());
19+
res.status(ex.getStatus()).header("Content-Type", "application/problem+json")
20+
.send(new ValidationResponse(ex.getStatus(), ex.getErrors(), req.path().rawPath()).toJson());
3321
}
3422
}
Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
package io.avaje.http.inject;
22

3-
import static java.util.stream.Collectors.joining;
4-
5-
import java.util.List;
6-
73
import io.avaje.http.api.AvajeJavalinPlugin;
84
import io.avaje.http.api.ValidationException;
95
import io.javalin.config.JavalinConfig;
@@ -17,26 +13,7 @@ public void onStart(JavalinConfig config) {
1713

1814
private void handler(ValidationException ex, Context ctx) {
1915

20-
var json = ctx.status(ex.getStatus()).jsonMapper();
21-
22-
List<ValidationException.Violation> violations = ex.getErrors();
23-
if (json == null) {
24-
int violationCount = violations.size();
25-
String violationList =
26-
violations.stream()
27-
.map(violation -> "'" + violation.getField() + "' " + violation.getMessage())
28-
.collect(joining("\n"));
29-
30-
// return a plain-text error message
31-
ctx.result(
32-
String.format(
33-
"Bad Request [%s validation violations: \n%s]", violationCount, violationList));
34-
return;
35-
}
3616
ctx.contentType("application/problem+json")
37-
.result(
38-
json.toJsonString(
39-
new ValidationResponse(ex.getStatus(), violations, ctx.path()),
40-
ValidationResponse.class));
17+
.result(new ValidationResponse(ex.getStatus(), ex.getErrors(), ctx.path()).toJson());
4118
}
4219
}
Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
package io.avaje.http.inject;
22

3-
import static java.util.stream.Collectors.joining;
4-
5-
import java.util.List;
6-
73
import io.avaje.http.api.ValidationException;
84
import io.avaje.jex.Routing;
95
import io.avaje.jex.Routing.HttpService;
@@ -19,23 +15,7 @@ public void add(Routing arg0) {
1915

2016
private void handler(Context ctx, ValidationException ex) {
2117

22-
var json = ctx.status(ex.getStatus()).jsonService();
23-
24-
List<ValidationException.Violation> violations = ex.getErrors();
25-
if (json == null) {
26-
int violationCount = violations.size();
27-
String violationList =
28-
violations.stream()
29-
.map(violation -> "'" + violation.getField() + "' " + violation.getMessage())
30-
.collect(joining("\n"));
31-
32-
// return a plain-text error message
33-
ctx.text(
34-
String.format(
35-
"Bad Request [%s validation violations: \n%s]", violationCount, violationList));
36-
return;
37-
}
3818
ctx.contentType("application/problem+json")
39-
.write(json.toJsonString(new ValidationResponse(ex.getStatus(), violations, ctx.path())));
19+
.write(new ValidationResponse(ex.getStatus(), ex.getErrors(), ctx.path()).toJson());
4020
}
4121
}

http-inject-plugin/src/main/java/io/avaje/http/inject/ValidationResponse.java

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ public class ValidationResponse {
88

99
private static String type = "tag:io.avaje.http.api.Validator";
1010
private static String title = "Request Failed Validation";
11-
private static String detail =
12-
"You tried to call this endpoint, but your data failed validation";
11+
private static String detail = "You tried to call this endpoint, but your data failed validation";
1312
private final int status;
1413
private final List<Violation> errors;
1514
private final String instance;
@@ -43,4 +42,76 @@ public int status() {
4342
public List<Violation> errors() {
4443
return errors;
4544
}
45+
46+
// Custom serialize so we don't need any json lib
47+
public String toJson() {
48+
StringBuilder sb = new StringBuilder();
49+
sb.append('{');
50+
sb.append("\"type\":").append(escapeJson(type)).append(",");
51+
sb.append("\"title\":").append(escapeJson(title)).append(",");
52+
sb.append("\"detail\":").append(escapeJson(detail)).append(",");
53+
sb.append("\"instance\":").append(escapeJson(instance)).append(",");
54+
sb.append("\"status\":").append(status).append(',');
55+
56+
sb.append("\"errors\":[");
57+
for (int i = 0; i < errors().size(); i++) {
58+
if (i > 0) {
59+
sb.append(',');
60+
}
61+
var e = errors.get(i);
62+
sb.append('{');
63+
sb.append("\"path\":").append(escapeJson(e.getPath())).append(",");
64+
sb.append("\"field\":").append(escapeJson(e.getField())).append(",");
65+
sb.append("\"message\":").append(escapeJson(e.getMessage()));
66+
sb.append('}');
67+
}
68+
69+
sb.append(']');
70+
71+
sb.append('}');
72+
return sb.toString();
73+
}
74+
75+
private static String escapeJson(String s) {
76+
if (s == null) {
77+
return "null";
78+
}
79+
StringBuilder sb = new StringBuilder();
80+
sb.append('"');
81+
for (int i = 0; i < s.length(); i++) {
82+
char ch = s.charAt(i);
83+
switch (ch) {
84+
case '"':
85+
sb.append("\\\"");
86+
break;
87+
case '\\':
88+
sb.append("\\\\");
89+
break;
90+
case '\b':
91+
sb.append("\\b");
92+
break;
93+
case '\f':
94+
sb.append("\\f");
95+
break;
96+
case '\n':
97+
sb.append("\\n");
98+
break;
99+
case '\r':
100+
sb.append("\\r");
101+
break;
102+
case '\t':
103+
sb.append("\\t");
104+
break;
105+
default:
106+
// Handle control characters or just append
107+
if (ch < ' ' || ch > '~') {
108+
sb.append(String.format("\\u%04x", (int) ch));
109+
} else {
110+
sb.append(ch);
111+
}
112+
}
113+
}
114+
sb.append('"');
115+
return sb.toString();
116+
}
46117
}

0 commit comments

Comments
 (0)