Skip to content

Commit 0caa0d4

Browse files
committed
allow Authenticators to throw ServiceException
This feature request lets Authenticators throw ServiceExcpetions, which are then written in the standard JSON format. This change also refactors exception handling when calling an API method to clean up the logic a bit, and change the logging level so that 5xx-level ServiceExceptions log at the WARNING level, and others at INFO.
1 parent 0cd4fe7 commit 0caa0d4

File tree

6 files changed

+32
-36
lines changed

6 files changed

+32
-36
lines changed

endpoints-framework/src/main/java/com/google/api/server/spi/SystemService.java

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -345,30 +345,17 @@ public Method findServiceMethod(Object service, String methodName) throws Servic
345345
public void invokeServiceMethod(Object service, Method method, ParamReader paramReader,
346346
ResultWriter resultWriter) throws IOException {
347347

348-
Object[] params;
349348
try {
350-
params = paramReader.read();
349+
Object[] params = paramReader.read();
351350
logger.log(Level.FINE, "params={0} (String)", Arrays.toString(params));
352-
} catch (BadRequestException e) {
353-
resultWriter.writeError(e);
354-
return;
355-
}
356-
357-
Object response;
358-
try {
359-
response = method.invoke(service, params);
360-
} catch (IllegalArgumentException e) {
361-
logger.log(Level.SEVERE, "exception occurred while calling backend method", e);
362-
resultWriter.writeError(new BadRequestException(e));
363-
return;
364-
} catch (IllegalAccessException e) {
351+
Object response = method.invoke(service, params);
352+
resultWriter.write(response);
353+
} catch (IllegalArgumentException | IllegalAccessException e) {
365354
logger.log(Level.SEVERE, "exception occurred while calling backend method", e);
366355
resultWriter.writeError(new BadRequestException(e));
367-
return;
368356
} catch (InvocationTargetException e) {
369357
Throwable cause = e.getCause();
370358
Level level = Level.INFO;
371-
372359
if (cause instanceof ServiceException) {
373360
resultWriter.writeError((ServiceException) cause);
374361
} else if (cause instanceof IllegalArgumentException) {
@@ -378,18 +365,19 @@ public void invokeServiceMethod(Object service, Method method, ParamReader param
378365
} else if (isOAuthRequestException(cause.getClass())) {
379366
resultWriter.writeError(new UnauthorizedException(cause));
380367
} else if (cause.getCause() != null && cause.getCause() instanceof ServiceException) {
381-
cause = cause.getCause();
382-
resultWriter.writeError((ServiceException) cause);
368+
ServiceException serviceException = (ServiceException) cause.getCause();
369+
level = getLoggingLevel(serviceException);
370+
resultWriter.writeError(serviceException);
383371
} else {
384372
level = Level.SEVERE;
385373
resultWriter.writeError(new InternalServerErrorException(cause));
386374
}
387-
logger.log(level, "exception occurred while calling backend method",
388-
cause);
389-
return;
375+
logger.log(level, "exception occurred while calling backend method", cause);
376+
} catch (ServiceException e) {
377+
Level level = getLoggingLevel(e);
378+
logger.log(level, "exception occurred while calling backend method", e);
379+
resultWriter.writeError(e);
390380
}
391-
392-
resultWriter.write(response);
393381
}
394382

395383
/**
@@ -413,6 +401,10 @@ private void validateRegisteredServices(ApiConfigValidator validator) throws Api
413401
}
414402
}
415403

404+
private static Level getLoggingLevel(ServiceException e) {
405+
return e.getStatusCode() >= 500 ? Level.SEVERE : Level.INFO;
406+
}
407+
416408
private static boolean isOAuthRequestException(Class<?> clazz) {
417409
while (Object.class != clazz) {
418410
if (OAUTH_EXCEPTION_CLASS.equals(clazz.getName())) {

endpoints-framework/src/main/java/com/google/api/server/spi/config/Authenticator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package com.google.api.server.spi.config;
1717

18+
import com.google.api.server.spi.ServiceException;
1819
import com.google.api.server.spi.auth.common.User;
1920

2021
import javax.servlet.http.HttpServletRequest;
@@ -35,5 +36,5 @@ public interface Authenticator {
3536
*
3637
* @return The authenticated user or null if there is no auth or auth has failed.
3738
*/
38-
User authenticate(HttpServletRequest request);
39+
User authenticate(HttpServletRequest request) throws ServiceException;
3940
}

endpoints-framework/src/main/java/com/google/api/server/spi/request/Auth.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package com.google.api.server.spi.request;
1717

1818
import com.google.api.server.spi.EnvUtil;
19+
import com.google.api.server.spi.ServiceException;
1920
import com.google.api.server.spi.auth.EndpointsAuthenticator;
2021
import com.google.api.server.spi.auth.common.User;
2122
import com.google.api.server.spi.config.Authenticator;
@@ -92,7 +93,7 @@ Iterable<Authenticator> getAuthenticatorInstances() {
9293
/**
9394
* Authenticate the request and retrieve a {@code User}. Should only run once per request.
9495
*/
95-
User authenticate() {
96+
User authenticate() throws ServiceException {
9697
Iterable<Authenticator> authenticators = getAuthenticatorInstances();
9798
User user = null;
9899
if (authenticators != null) {
@@ -110,7 +111,7 @@ User authenticate() {
110111
* Authenticate the request and retrieve an {@code com.google.appengine.api.users.User}. Should
111112
* only run once per request.
112113
*/
113-
com.google.appengine.api.users.User authenticateAppEngineUser() {
114+
com.google.appengine.api.users.User authenticateAppEngineUser() throws ServiceException {
114115
if (!EnvUtil.isRunningOnAppEngine()) {
115116
return null;
116117
}

endpoints-framework/src/main/java/com/google/api/server/spi/request/ParamReader.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616
package com.google.api.server.spi.request;
1717

18-
import com.google.api.server.spi.response.BadRequestException;
18+
import com.google.api.server.spi.ServiceException;
1919

2020
/**
2121
* Reads a request and returns an array of parameter values.
@@ -24,8 +24,8 @@ public interface ParamReader {
2424

2525
/**
2626
* Reads parameters in JSON into an Object array to be used to invoke an Endpoint method.
27-
* @throws BadRequestException when reading of input stream failed, input JSON is invalid,
28-
* or cannot be mapped into parameter objects.
27+
* @throws ServiceException when reading of input stream failed, input JSON is invalid,
28+
* or cannot be mapped into parameter objects, or user authentication fails.
2929
*/
30-
Object[] read() throws BadRequestException;
30+
Object[] read() throws ServiceException;
3131
}

endpoints-framework/src/main/java/com/google/api/server/spi/request/RestServletRequestParamReader.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import com.google.api.server.spi.EndpointMethod;
1919
import com.google.api.server.spi.IoUtil;
20+
import com.google.api.server.spi.ServiceException;
2021
import com.google.api.server.spi.Strings;
2122
import com.google.api.server.spi.config.model.ApiMethodConfig;
2223
import com.google.api.server.spi.config.model.ApiParameterConfig;
@@ -69,7 +70,7 @@ public RestServletRequestParamReader(EndpointMethod method,
6970
}
7071

7172
@Override
72-
public Object[] read() throws BadRequestException {
73+
public Object[] read() throws ServiceException {
7374
// Assumes input stream to be encoded in UTF-8
7475
// TODO: Take charset from content-type as encoding
7576
try {

endpoints-framework/src/main/java/com/google/api/server/spi/request/ServletRequestParamReader.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.google.api.server.spi.ConfiguredObjectMapper;
1919
import com.google.api.server.spi.EndpointMethod;
2020
import com.google.api.server.spi.IoUtil;
21+
import com.google.api.server.spi.ServiceException;
2122
import com.google.api.server.spi.auth.common.User;
2223
import com.google.api.server.spi.config.Named;
2324
import com.google.api.server.spi.config.annotationreader.AnnotationUtil;
@@ -122,7 +123,7 @@ protected static List<String> getParameterNames(EndpointMethod endpointMethod)
122123
}
123124

124125
protected Object[] deserializeParams(JsonNode node) throws IOException, IllegalAccessException,
125-
InvocationTargetException, NoSuchMethodException {
126+
InvocationTargetException, NoSuchMethodException, ServiceException {
126127
EndpointMethod method = getMethod();
127128
Class<?>[] paramClasses = method.getParameterClasses();
128129
TypeToken<?>[] paramTypes = method.getParameterTypes();
@@ -187,12 +188,12 @@ protected Object[] deserializeParams(JsonNode node) throws IOException, IllegalA
187188
}
188189

189190
@VisibleForTesting
190-
User getUser() {
191+
User getUser() throws ServiceException {
191192
return Auth.from(servletRequest).authenticate();
192193
}
193194

194195
@VisibleForTesting
195-
com.google.appengine.api.users.User getAppEngineUser() {
196+
com.google.appengine.api.users.User getAppEngineUser() throws ServiceException {
196197
return Auth.from(servletRequest).authenticateAppEngineUser();
197198
}
198199

@@ -297,7 +298,7 @@ public ServletRequestParamReader(EndpointMethod method, HttpServletRequest servl
297298
}
298299

299300
@Override
300-
public Object[] read() throws BadRequestException {
301+
public Object[] read() throws ServiceException {
301302
// Assumes input stream to be encoded in UTF-8
302303
// TODO: Take charset from content-type as encoding
303304
try {

0 commit comments

Comments
 (0)