Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,6 @@ protected String getBuildSystem(Option buildSystemOption) {
return getOptionOrDefault(buildSystemOption, DEFAULT_BUILD_SYSTEM);
}

protected String getFormat(Option formatOption) {
return getOptionOrDefault(formatOption, DEFAULT_FORMAT);
}

protected boolean getDebug(Option debugOption) {
return debugOption.getValue() != null;
}
Expand Down Expand Up @@ -406,13 +402,6 @@ public void setHelpDisplayNeeded(boolean helpDisplayNeeded) {
this.helpDisplayNeeded = helpDisplayNeeded;
}

/**
* Return the example string which will be displayed in the usage.
*/
public String getExampleString() {
return exampleString;
}

/**
* Set the example string which will be displayed in the usage.
*/
Expand Down Expand Up @@ -467,6 +456,17 @@ public static EndpointsOption makeVisibleNonFlagOption(
return new EndpointsOption(shortName, longName, false, true, placeHolderValue, description);
}

public static EndpointsOption makeVisibleFlagOption(
@Nullable String longName,
@Nullable String description) {
return new EndpointsOption(null, longName, true, true, null, description) {
@Override
public void apply() {
getValues().add("true");
}
};
}

public static EndpointsOption makeInvisibleFlagOption(
@Nullable String shortName,
@Nullable String longName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,12 @@ public class GetDiscoveryDocAction extends EndpointsToolAction {
private Option classPathOption = makeClassPathOption();
private Option outputOption = makeOutputOption();
private Option warOption = makeWarOption();
private Option debugOption = makeDebugOption();
private Option hostnameOption = makeHostnameOption();
private Option basePathOption = makeBasePathOption();

public GetDiscoveryDocAction() {
super(NAME);
setOptions(Arrays.asList(classPathOption, outputOption, warOption, debugOption, hostnameOption,
setOptions(Arrays.asList(classPathOption, outputOption, warOption, hostnameOption,
basePathOption));
setShortDescription("Generates discovery documents");
setExampleString("<Endpoints tool> get-discovery-doc "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.google.api.server.spi.tools;

import static com.google.api.server.spi.tools.EndpointsToolAction.EndpointsOption.makeVisibleFlagOption;
import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.api.server.spi.ServiceContext;
Expand Down Expand Up @@ -52,6 +53,20 @@ public class GetOpenApiDocAction extends EndpointsToolAction {
private Option warOption = makeWarOption();
private Option hostnameOption = makeHostnameOption();
private Option basePathOption = makeBasePathOption();
private Option titleOption = makeTitleOption();
private Option descriptionOption = makeDescriptionOption();
private Option addGoogleJsonErrorAsDefaultResponseOption = makeVisibleFlagOption(
"addGoogleJsonErrorAsDefaultResponse", "Add GoogleJsonError as default response"
);
private Option addErrorCodesForServiceExceptionsOption = makeVisibleFlagOption(
"addErrorCodesForServiceExceptions", "Add GoogleJsonError for codes in ServiceExceptions"
);
private Option extractCommonParametersAsRefsOption = makeVisibleFlagOption(
"extractCommonParametersAsRefs", "Extract common parameters as refs at specification level"
);
private Option combineCommonParametersInSamePathOption = makeVisibleFlagOption(
"combineCommonParametersInSamePath", "Combine common parameters in same path"
);

public GetOpenApiDocAction() {
this(NAME, true);
Expand All @@ -60,13 +75,36 @@ public GetOpenApiDocAction() {
protected GetOpenApiDocAction(String alias, boolean displayHelp) {
super(alias);
setOptions(
Arrays.asList(classPathOption, outputOption, warOption, hostnameOption, basePathOption));
Arrays.asList(classPathOption, outputOption, warOption, hostnameOption, basePathOption,
titleOption, descriptionOption,
addGoogleJsonErrorAsDefaultResponseOption, addErrorCodesForServiceExceptionsOption,
extractCommonParametersAsRefsOption, combineCommonParametersInSamePathOption));
setShortDescription("Generates an OpenAPI document");
setExampleString("<Endpoints tool> " + getNames()[0]
+ " com.google.devrel.samples.ttt.spi.BoardV1 com.google.devrel.samples.ttt.spi.ScoresV1");
setHelpDisplayNeeded(displayHelp);
}

private static Option makeTitleOption() {
return EndpointsOption.makeVisibleNonFlagOption(
"t",
"title",
"TITLE",
"Sets the title for the generated document. Default is the app's host.");
}

private static Option makeDescriptionOption() {
return EndpointsOption.makeVisibleNonFlagOption(
"d",
"description",
"DESCRIPTION",
"Sets the description for the generated document. Is empty by default.");
}

private static boolean getBooleanOptionValue(Option option) {
return option.getValue() != null;
}

@Override
public String getUsageString() {
return getNames()[0] + " <options> <service class>...";
Expand All @@ -81,7 +119,14 @@ public boolean execute() throws ClassNotFoundException, IOException, ApiConfigEx
}
genOpenApiDoc(computeClassPath(warPath, getClassPath(classPathOption)),
getOpenApiOutputPath(outputOption), getHostname(hostnameOption, warPath),
getBasePath(basePathOption), serviceClassNames, true);
getBasePath(basePathOption),
getOptionOrDefault(titleOption, null),
getOptionOrDefault(descriptionOption, null),
getBooleanOptionValue(addGoogleJsonErrorAsDefaultResponseOption),
getBooleanOptionValue(addErrorCodesForServiceExceptionsOption),
getBooleanOptionValue(extractCommonParametersAsRefsOption),
getBooleanOptionValue(combineCommonParametersInSamePathOption),
serviceClassNames, true);
return true;
}

Expand All @@ -98,6 +143,9 @@ public boolean execute() throws ClassNotFoundException, IOException, ApiConfigEx
*/
public String genOpenApiDoc(
URL[] classPath, String outputFilePath, String hostname, String basePath,
String title, String description,
boolean addGoogleJsonErrorAsDefaultResponse, boolean addErrorCodesForServiceExceptionsOption,
boolean extractCommonParametersAsRefsOption, boolean combineCommonParametersInSamePathOption,
List<String> serviceClassNames, boolean outputToDisk)
throws ClassNotFoundException, IOException, ApiConfigException {
File outputFile = new File(outputFilePath);
Expand All @@ -120,7 +168,13 @@ public String genOpenApiDoc(
SwaggerGenerator generator = new SwaggerGenerator();
SwaggerContext swaggerContext = new SwaggerContext()
.setHostname(hostname)
.setBasePath(basePath);
.setBasePath(basePath)
.setTitle(title)
.setDescription(description)
.setAddErrorCodesForServiceExceptions(addGoogleJsonErrorAsDefaultResponse)
.setAddErrorCodesForServiceExceptions(addErrorCodesForServiceExceptionsOption)
.setExtractCommonParametersAsRefs(extractCommonParametersAsRefsOption)
.setCombineCommonParametersInSamePath(combineCommonParametersInSamePathOption);
Swagger swagger = generator.writeSwagger(apiConfigs, swaggerContext);
String swaggerStr = Json.mapper().writer(new EndpointsPrettyPrinter())
.writeValueAsString(swagger);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ public class GetOpenApiDocActionTest extends EndpointsToolTest {
private String basePath;
private List<String> serviceClassNames;
private boolean outputToDisk;
private boolean addGoogleJsonErrorAsDefaultResponse;
private boolean addErrorCodesForServiceExceptionsOption;

@Override
protected void addTestAction(Map<String, EndpointsToolAction> actions) {
Expand All @@ -53,12 +55,21 @@ protected void addTestAction(Map<String, EndpointsToolAction> actions) {
@Override
public String genOpenApiDoc(
URL[] classPath, String outputFilePath, String hostname, String basePath,
String title, String description,
boolean addGoogleJsonErrorAsDefaultResponse,
boolean addErrorCodesForServiceExceptionsOption,
boolean extractCommonParametersAsRefsOption,
boolean combineCommonParametersInSamePathOption,
List<String> serviceClassNames, boolean outputToDisk) {
GetOpenApiDocActionTest.this.classPath = classPath;
GetOpenApiDocActionTest.this.outputFilePath = outputFilePath;
GetOpenApiDocActionTest.this.basePath = basePath;
GetOpenApiDocActionTest.this.serviceClassNames = serviceClassNames;
GetOpenApiDocActionTest.this.outputToDisk = outputToDisk;
GetOpenApiDocActionTest.this.addGoogleJsonErrorAsDefaultResponse
= addGoogleJsonErrorAsDefaultResponse;
GetOpenApiDocActionTest.this.addErrorCodesForServiceExceptionsOption
= addErrorCodesForServiceExceptionsOption;
return null;
}

Expand All @@ -84,7 +95,9 @@ public void setUp() throws Exception {
public void testGetOpenApiDoc() throws Exception {
tool.execute(
new String[]{GetOpenApiDocAction.NAME, option(EndpointsToolAction.OPTION_CLASS_PATH_SHORT),
"classPath", option(EndpointsToolAction.OPTION_OUTPUT_DIR_SHORT), "outputDir", "MyService",
"classPath", option(EndpointsToolAction.OPTION_OUTPUT_DIR_SHORT), "outputDir",
option("addGoogleJsonErrorAsDefaultResponse", false),
"MyService",
"MyService2"});
assertFalse(usagePrinted);
assertThat(Lists.newArrayList(classPath))
Expand All @@ -95,6 +108,8 @@ public void testGetOpenApiDoc() throws Exception {
.toURL());
assertEquals("outputDir", outputFilePath);
assertEquals(EndpointsToolAction.DEFAULT_BASE_PATH, basePath);
assertTrue(addGoogleJsonErrorAsDefaultResponse);
assertFalse(addErrorCodesForServiceExceptionsOption);
assertStringsEqual(Arrays.asList("MyService", "MyService2"), serviceClassNames);
assertTrue(outputToDisk);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,28 @@
*/
package com.google.api.server.spi.config.model;

import com.google.api.server.spi.Constant;
import com.google.api.server.spi.EndpointMethod;
import com.google.api.server.spi.ServiceException;
import com.google.api.server.spi.TypeLoader;
import com.google.api.server.spi.config.AuthLevel;
import com.google.api.server.spi.config.Authenticator;
import com.google.api.server.spi.config.PeerAuthenticator;
import com.google.api.server.spi.config.model.ApiParameterConfig.Classification;
import com.google.api.server.spi.config.scope.AuthScopeExpression;
import com.google.api.server.spi.response.BadRequestException;
import com.google.api.server.spi.response.ConflictException;
import com.google.api.server.spi.response.ErrorMap;
import com.google.api.server.spi.response.ForbiddenException;
import com.google.api.server.spi.response.InternalServerErrorException;
import com.google.api.server.spi.response.NotFoundException;
import com.google.api.server.spi.response.ServiceUnavailableException;
import com.google.api.server.spi.response.UnauthorizedException;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.reflect.TypeToken;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
Expand All @@ -45,6 +56,17 @@
*/
public class ApiMethodConfig {

private static final Map<? extends Class<? extends ServiceException>, Integer>
KNOWN_EXCEPTION_CODES = ImmutableMap.<Class<? extends ServiceException>, Integer>builder()
.put(BadRequestException.class, BadRequestException.CODE)
.put(ForbiddenException.class, ForbiddenException.CODE)
.put(ServiceUnavailableException.class, ServiceUnavailableException.CODE)
.put(UnauthorizedException.class, UnauthorizedException.CODE)
.put(NotFoundException.class, NotFoundException.CODE)
.put(ConflictException.class, ConflictException.CODE)
.put(InternalServerErrorException.class, InternalServerErrorException.CODE)
.build();

private enum RestMethod {
LIST("list", "GET") {
@Override
Expand Down Expand Up @@ -159,6 +181,7 @@ public String guessResourceName(
private boolean deprecated = false;
private Boolean apiKeyRequired;
private TypeToken<?> returnType;
private Class<?>[] exceptionTypes;
private List<ApiMetricCostConfig> metricCosts;

private final TypeLoader typeLoader;
Expand Down Expand Up @@ -231,6 +254,7 @@ protected void setDefaults(EndpointMethod endpointMethod, TypeLoader typeLoader,
ignored = false;
apiKeyRequired = null;
returnType = endpointMethod.getReturnType();
exceptionTypes = endpointMethod.getMethod().getExceptionTypes();
metricCosts = ImmutableList.of();
}

Expand Down Expand Up @@ -519,6 +543,24 @@ public TypeToken<?> getReturnType() {
return returnType;
}

public Map<Integer, String> getErrorCodesAndDescriptions() {
ErrorMap errorMap = new ErrorMap();
Map<Integer, String> descriptionByCode = Maps.newLinkedHashMap();
for (Class<?> exceptionType : exceptionTypes) {
//TODO support custom exception types by either:
// - introspecting the CODE static field (convention)
// - introducing a new annotation for Exceptions
Integer code = KNOWN_EXCEPTION_CODES.get(exceptionType);
if (code != null) {
String reason = errorMap.getReason(code);
if (reason != null) {
descriptionByCode.put(code, reason);
}
}
}
return descriptionByCode;
}

/**
* Returns whether or not the method has a resource (is non-void) in the response.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*/
public class BadRequestException extends ServiceException {

private static final int CODE = 400;
public static final int CODE = 400;

public BadRequestException(String message) {
super(CODE, message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*/
public class ConflictException extends ServiceException {

private static final int CODE = 409;
public static final int CODE = 409;

public ConflictException(String message) {
super(CODE, message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*/
public class ForbiddenException extends ServiceException {

private static final int CODE = 403;
public static final int CODE = 403;

public ForbiddenException(String message) {
super(CODE, message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*/
public class InternalServerErrorException extends ServiceException {

private static final int CODE = 500;
public static final int CODE = 500;

public InternalServerErrorException(String message) {
super(CODE, message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*/
public class NotFoundException extends ServiceException {

private static final int CODE = 404;
public static final int CODE = 404;

public NotFoundException(String message) {
super(CODE, message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*/
public class ServiceUnavailableException extends ServiceException {

private static final int CODE = 503;
public static final int CODE = 503;

public ServiceUnavailableException(String message) {
super(CODE, message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class UnauthorizedException extends ServiceException {
public static final String AUTH_SCHEME_BEARER = "Bearer";
private static final Map<String, String> GOOGLE_REALM =
ImmutableMap.of("realm", "\"https://accounts.google.com/\"");
private static final int CODE = 401;
public static final int CODE = 401;

private final String authScheme;
private final Map<String, String> params;
Expand Down
Loading