Merge remote-tracking branch 'origin/master' into 2.3.0

This commit is contained in:
wing328
2017-05-30 00:12:34 +08:00
155 changed files with 3626 additions and 1128 deletions

View File

@@ -2560,7 +2560,9 @@ public class DefaultCodegen {
name = getAlias(name);
if (typeMapping.containsKey(name)) {
name = typeMapping.get(name);
p.baseType = name;
} else {
p.baseType = name;
name = toModelName(name);
if (defaultIncludes.contains(name)) {
imports.add(name);
@@ -2569,7 +2571,6 @@ public class DefaultCodegen {
name = getTypeDeclaration(name);
}
p.dataType = name;
p.baseType = name;
}
}
p.paramName = toParamName(bp.getName());

View File

@@ -959,8 +959,11 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
@Override
public String toEnumValue(String value, String datatype) {
if ("Integer".equals(datatype) || "Long".equals(datatype) ||
"Float".equals(datatype) || "Double".equals(datatype)) {
"Double".equals(datatype)) {
return value;
} else if ("Float".equals(datatype)) {
// add f to number, e.g. 3.14 => 3.14f
return value + "f";
} else {
return "\"" + escapeText(value) + "\"";
}

View File

@@ -560,7 +560,7 @@ public abstract class AbstractPhpCodegen extends DefaultCodegen implements Codeg
example = "new \\DateTime(\"" + escapeText(example) + "\")";
} else if (!languageSpecificPrimitives.contains(type)) {
// type is a model class, e.g. User
example = "new " + type + "()";
example = "new " + getTypeDeclaration(type) + "()";
} else {
LOGGER.warn("Type " + type + " not handled properly in setParameterExampleValue");
}

View File

@@ -17,21 +17,27 @@ public class ApexClientCodegen extends AbstractJavaCodegen {
private static final String CLASS_PREFIX = "classPrefix";
private static final String API_VERSION = "apiVersion";
private static final String BUILD_METHOD = "buildMethod";
private static final String NAMED_CREDENTIAL = "namedCredential";
private static final Logger LOGGER = LoggerFactory.getLogger(ApexClientCodegen.class);
private String classPrefix = "Swag";
private String apiVersion = "39.0";
private String buildMethod = "sfdx";
private String namedCredential = classPrefix;
private String srcPath = "force-app/main/default/";
public ApexClientCodegen() {
super();
importMapping.clear();
testFolder = sourceFolder = srcPath;
embeddedTemplateDir = templateDir = "apex";
outputFolder = "generated-code" + File.separator + "apex";
testFolder = sourceFolder = "deploy";
apiPackage = "classes";
modelPackage = "classes";
testPackage = "deploy.classes";
testPackage = "force-app.main.default.classes";
modelNamePrefix = classPrefix;
dateLibrary = "";
@@ -46,22 +52,15 @@ public class ApexClientCodegen extends AbstractJavaCodegen {
cliOptions.add(CliOption.newString(CLASS_PREFIX, "Prefix for generated classes. Set this to avoid overwriting existing classes in your org."));
cliOptions.add(CliOption.newString(API_VERSION, "The Metadata API version number to use for components in this package."));
cliOptions.add(CliOption.newString(BUILD_METHOD, "The build method for this package."));
cliOptions.add(CliOption.newString(NAMED_CREDENTIAL, "The named credential name for the HTTP callouts"));
supportingFiles.add(new SupportingFile("package.mustache", "deploy", "package.xml"));
supportingFiles.add(new SupportingFile("package.mustache", "undeploy", "destructiveChanges.xml"));
supportingFiles.add(new SupportingFile("build.mustache", "build.xml"));
supportingFiles.add(new SupportingFile("build.properties", "build.properties"));
supportingFiles.add(new SupportingFile("remove.package.mustache", "undeploy", "package.xml"));
supportingFiles.add(new SupportingFile("Swagger.cls", "deploy/classes", "Swagger.cls"));
supportingFiles.add(new SupportingFile("cls-meta.mustache", "deploy/classes", "Swagger.cls-meta.xml"));
supportingFiles.add(new SupportingFile("SwaggerTest.cls", "deploy/classes", "SwaggerTest.cls"));
supportingFiles.add(new SupportingFile("cls-meta.mustache", "deploy/classes", "SwaggerTest.cls-meta.xml"));
supportingFiles.add(new SupportingFile("SwaggerResponseMock.cls", "deploy/classes", "SwaggerResponseMock.cls"));
supportingFiles.add(new SupportingFile("cls-meta.mustache", "deploy/classes", "SwaggerResponseMock.cls-meta.xml"));
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
writeOptional(outputFolder, new SupportingFile("README.mustache", "README.md"));
supportingFiles.add(new SupportingFile("Swagger.cls", srcPath + "classes", "Swagger.cls"));
supportingFiles.add(new SupportingFile("cls-meta.mustache", srcPath + "classes", "Swagger.cls-meta.xml"));
supportingFiles.add(new SupportingFile("SwaggerTest.cls", srcPath + "classes", "SwaggerTest.cls"));
supportingFiles.add(new SupportingFile("cls-meta.mustache", srcPath + "classes", "SwaggerTest.cls-meta.xml"));
supportingFiles.add(new SupportingFile("SwaggerResponseMock.cls", srcPath + "classes", "SwaggerResponseMock.cls"));
supportingFiles.add(new SupportingFile("cls-meta.mustache", srcPath + "classes", "SwaggerResponseMock.cls-meta.xml"));
typeMapping.put("BigDecimal", "Double");
typeMapping.put("binary", "String");
@@ -114,6 +113,16 @@ public class ApexClientCodegen extends AbstractJavaCodegen {
}
additionalProperties.put(API_VERSION, apiVersion);
if (additionalProperties.containsKey(BUILD_METHOD)) {
setBuildMethod((String)additionalProperties.get(BUILD_METHOD));
}
additionalProperties.put(BUILD_METHOD, buildMethod);
if (additionalProperties.containsKey(NAMED_CREDENTIAL)) {
setNamedCredential((String)additionalProperties.get(NAMED_CREDENTIAL));
}
additionalProperties.put(NAMED_CREDENTIAL, namedCredential);
postProcessOpts();
}
@@ -232,18 +241,20 @@ public class ApexClientCodegen extends AbstractJavaCodegen {
@Override
public void preprocessSwagger(Swagger swagger) {
Info info = swagger.getInfo();
String description = info.getDescription();
String sanitized = sanitizeName(info.getTitle());
additionalProperties.put("sanitizedName", sanitized);
supportingFiles.add(new SupportingFile("remoteSite.mustache", "deploy/remoteSiteSettings",
sanitized + ".remoteSite"
String calloutLabel = info.getTitle();
additionalProperties.put("calloutLabel", calloutLabel);
String sanitized = sanitizeName(calloutLabel);
additionalProperties.put("calloutName", sanitized);
supportingFiles.add(new SupportingFile("namedCredential.mustache", srcPath + "/namedCredentials",
sanitized + ".namedCredential"
));
// max length for description for a Remote Site setting
if (description != null && description.length() > 255) {
description = description.substring(0, 255);
if (additionalProperties.get(BUILD_METHOD).equals("sfdx")) {
generateSfdxSupportingFiles();
} else if (additionalProperties.get(BUILD_METHOD).equals("ant")) {
generateAntSupportingFiles();
}
additionalProperties.put("shortDescription", description);
}
@Override
@@ -289,6 +300,20 @@ public class ApexClientCodegen extends AbstractJavaCodegen {
return input.replace("'", "\\'");
}
public void setBuildMethod(String buildMethod) {
if (buildMethod.equals("ant")) {
this.srcPath = "deploy/";
} else {
this.srcPath = "src/";
}
testFolder = sourceFolder = srcPath;
this.buildMethod = buildMethod;
}
public void setNamedCredential(String namedCredential) {
this.namedCredential = namedCredential;
}
public void setClassPrefix(String classPrefix) {
// the best thing we can do without namespacing in Apex
modelNamePrefix = classPrefix;
@@ -310,8 +335,8 @@ public class ApexClientCodegen extends AbstractJavaCodegen {
private void postProcessOpts() {
supportingFiles.add(
new SupportingFile("client.mustache", "deploy/classes", classPrefix + "Client.cls"));
supportingFiles.add(new SupportingFile("cls-meta.mustache", "deploy/classes",
new SupportingFile("client.mustache", srcPath + "classes", classPrefix + "Client.cls"));
supportingFiles.add(new SupportingFile("cls-meta.mustache", srcPath + "classes",
classPrefix + "Client.cls-meta.xml"
));
}
@@ -451,4 +476,28 @@ public class ApexClientCodegen extends AbstractJavaCodegen {
public String getHelp() {
return "Generates an Apex API client library (beta).";
}
private void generateAntSupportingFiles() {
supportingFiles.add(new SupportingFile("package.mustache", "deploy", "package.xml"));
supportingFiles.add(new SupportingFile("package.mustache", "undeploy", "destructiveChanges.xml"));
supportingFiles.add(new SupportingFile("build.mustache", "build.xml"));
supportingFiles.add(new SupportingFile("build.properties", "build.properties"));
supportingFiles.add(new SupportingFile("remove.package.mustache", "undeploy", "package.xml"));
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
writeOptional(outputFolder, new SupportingFile("README_ant.mustache", "README.md"));
}
private void generateSfdxSupportingFiles() {
supportingFiles.add(new SupportingFile("sfdx.mustache", "", "sfdx-oss-manifest.json"));
writeOptional(outputFolder, new SupportingFile("README_sfdx.mustache", "README.md"));
}
}

View File

@@ -560,6 +560,9 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
if ("int?".equalsIgnoreCase(datatype) || "long?".equalsIgnoreCase(datatype) ||
"double?".equalsIgnoreCase(datatype) || "float?".equalsIgnoreCase(datatype)) {
return value;
} else if ("float?".equalsIgnoreCase(datatype)) {
// for float in C#, append "f". e.g. 3.14 => 3.14f
return value + "f";
} else {
return "\"" + escapeText(value) + "\"";
}

View File

@@ -615,19 +615,19 @@ public class PhpClientCodegen extends DefaultCodegen implements CodegenConfig {
example = "/path/to/file";
}
example = "\"" + escapeText(example) + "\"";
} else if ("Date".equalsIgnoreCase(type)) {
} else if ("\\Date".equalsIgnoreCase(type)) {
if (example == null) {
example = "2013-10-20";
}
example = "new \\DateTime(\"" + escapeText(example) + "\")";
} else if ("DateTime".equalsIgnoreCase(type)) {
} else if ("\\DateTime".equalsIgnoreCase(type)) {
if (example == null) {
example = "2013-10-20T19:20:30+01:00";
}
example = "new \\DateTime(\"" + escapeText(example) + "\")";
} else if (!languageSpecificPrimitives.contains(type)) {
// type is a model class, e.g. User
example = "new " + type + "()";
example = "new " + getTypeDeclaration(type) + "()";
} else {
LOGGER.warn("Type " + type + " not handled properly in setParameterExampleValue");
}

View File

@@ -0,0 +1,114 @@
# {{appName}} API Client
{{#appDescription}}
{{{appDescription}}}
{{/appDescription}}
## Requirements
- [Salesforce DX](https://www.salesforce.com/products/platform/products/salesforce-dx/)
If everything is set correctly:
- Running `sfdx version` in a command prompt should output something like:
```bash
sfdx-cli/5.7.5-05549de (darwin-amd64) go1.7.5 sfdxstable
```
## Installation
1. Copy the output into your Salesforce DX folder - or alternatively deploy the output directly into the workspace.
2. Deploy the code via Salesforce DX to your Scratch Org
```bash
$ sfdx force:source:push
```
3. If the API needs authentication update the Named Credential in Setup.
4. Run your Apex tests using
```bash
$ sfdx sfdx force:apex:test:run
```
5. Retrieve the job id from the console and check the test results.
```bash
$ sfdx force:apex:test:report -i theJobId
```
## Getting Started
Please follow the [installation](#installation) instruction and execute the following Apex code:
```java{{#apiInfo}}{{#apis}}{{#-first}}{{#operations}}{{#operation}}{{#-first}}
{{classname}} api = new {{classname}}();
{{#hasAuthMethods}}
{{classPrefix}}Client client = api.getClient();
{{#isApiKey}}
// Configure API key authorization: {{{name}}}
ApiKeyAuth {{{name}}} = (ApiKeyAuth) client.getAuthentication('{{{name}}}');
{{{name}}}.setApiKey('YOUR API KEY');{{/isApiKey}}
{{/hasAuthMethods}}
{{#hasParams}}
Map<String, Object> params = new Map<String, Object>{
{{#allParams}}
'{{{paramName}}}' => {{{example}}}{{#hasMore}},{{/hasMore}}
{{/allParams}}
};
{{/hasParams}}
try {
// cross your fingers
{{#returnType}}{{{returnType}}} result = {{/returnType}}api.{{{operationId}}}({{#hasParams}}params{{/hasParams}});
{{#returnType}}
System.debug(result);
{{/returnType}}
} catch (Swagger.ApiException e) {
// ...handle your exceptions
}{{/-first}}{{/operation}}{{/operations}}{{/-first}}{{/apis}}{{/apiInfo}}
```
## Documentation for API Endpoints
All URIs are relative to *{{basePath}}*
Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}}
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
## Documentation for Models
{{#models}}{{#model}} - [{{classname}}]({{modelDocPath}}{{classname}}.md)
{{/model}}{{/models}}
## Documentation for Authorization
{{^authMethods}}All endpoints do not require authorization.
{{/authMethods}}Authentication schemes defined for the API:
{{#authMethods}}### {{name}}
{{#isApiKey}}- **Type**: API key
- **API key parameter name**: {{keyParamName}}
- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}}
{{/isApiKey}}
{{#isBasic}}- **Type**: HTTP basic authentication
{{/isBasic}}
{{#isOAuth}}- **Type**: OAuth
- **Flow**: {{flow}}
- **Authorizatoin URL**: {{authorizationUrl}}
- **Scopes**: {{^scopes}}N/A{{/scopes}}
{{#scopes}} - {{scope}}: {{description}}
{{/scopes}}
{{/isOAuth}}
{{/authMethods}}
## Author
{{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}}
{{/hasMore}}{{/apis}}{{/apiInfo}}

View File

@@ -65,50 +65,7 @@ public class Swagger {
}
}
public class HttpBasicAuth implements Authentication {
private String username = '';
private String password = '';
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setCredentials(String username, String password) {
setUsername(username);
setPassword(password);
}
@TestVisible
private String getHeaderValue() {
return 'Basic ' + EncodingUtil.base64Encode(Blob.valueOf(username + ':' + password));
}
public void apply(Map<String, Object> headers, List<Param> query) {
headers.put('Authorization', getHeaderValue());
}
}
public class OAuth2 implements Authentication {
private String accessToken = '';
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
@TestVisible
private String getHeaderValue() {
return 'Bearer ' + accessToken;
}
public void apply(Map<String, Object> headers, List<Param> query) {
headers.put('Authorization', getHeaderValue());
}
}
public class ApiException extends Exception {
private final Integer code;
private final String status;
@@ -144,6 +101,7 @@ public class Swagger {
protected String preferredContentType = 'application/json';
protected String preferredAccept = 'application/json';
protected final String basePath;
protected final String calloutName;
@TestVisible
protected final Map<String, Authentication> authentications = new Map<String, Authentication>();
@@ -152,36 +110,6 @@ public class Swagger {
return authentications.get(authName);
}
public virtual void setUsername(String username) {
for (Authentication auth : authentications.values()) {
if (auth instanceof HttpBasicAuth) {
((HttpBasicAuth) auth).setUsername(username);
return;
}
}
throw new NoSuchElementException('No HTTP basic authentication configured!');
}
public virtual void setPassword(String password) {
for (Authentication auth : authentications.values()) {
if (auth instanceof HttpBasicAuth) {
((HttpBasicAuth) auth).setPassword(password);
return;
}
}
throw new NoSuchElementException('No HTTP basic authentication configured!');
}
public virtual void setCredentials(String username, String password) {
for (Authentication auth : authentications.values()) {
if (auth instanceof HttpBasicAuth) {
((HttpBasicAuth) auth).setCredentials(username, password);
return;
}
}
throw new NoSuchElementException('No HTTP basic authentication configured!');
}
public virtual void setApiKey(String apiKey) {
for (Authentication auth : authentications.values()) {
if (auth instanceof ApiKeyAuth) {
@@ -192,16 +120,6 @@ public class Swagger {
throw new NoSuchElementException('No API key authentication configured!');
}
public virtual void setAccessToken(String accessToken) {
for (Authentication auth : authentications.values()) {
if (auth instanceof OAuth2) {
((OAuth2) auth).setAccessToken(accessToken);
return;
}
}
throw new NoSuchElementException('No OAuth2 authentication configured!');
}
public List<Param> makeParams(String name, List<Object> values) {
List<Param> pairs = new List<Param>();
for (Object value : new List<Object>(values)) {
@@ -380,7 +298,7 @@ public class Swagger {
protected virtual String toEndpoint(String path, Map<String, Object> params,
List<Param> queryParams) {
String query = '?' + paramsToString(queryParams);
return basePath + toPath(path, params) + query.removeEnd('?');
return '"callout:' + calloutName + toPath(path, params) + query.removeEnd('?') + '""';
}
@TestVisible

View File

@@ -35,217 +35,17 @@ private class SwaggerTest {
System.assertEquals('auth_token=foo-bar-api-key', query.get(0).toString());
}
@isTest
private static void HttpBasicAuth_base64EncodeCredentials() {
Map<String, Object> headers = new Map<String, String>();
List<Swagger.Param> query = new List<Swagger.Param>();
Swagger.HttpBasicAuth auth = new Swagger.HttpBasicAuth();
auth.setCredentials('username', 'password');
auth.apply(headers, query);
System.assert(query.isEmpty());
System.assertEquals(1, headers.size());
System.assertEquals('Basic dXNlcm5hbWU6cGFzc3dvcmQ=', headers.get('Authorization'));
}
@isTest
private static void HttpBasicAuth_base64EncodeUsernamePassword() {
Map<String, Object> headers = new Map<String, String>();
List<Swagger.Param> query = new List<Swagger.Param>();
Swagger.HttpBasicAuth auth = new Swagger.HttpBasicAuth();
auth.setUsername('username');
auth.setPassword('password');
auth.apply(headers, query);
System.assert(query.isEmpty());
System.assertEquals(1, headers.size());
System.assertEquals('Basic dXNlcm5hbWU6cGFzc3dvcmQ=', headers.get('Authorization'));
}
@isTest
private static void OAuth2_tokenInAuthorizationHeaderWithBearerPrefix() {
Map<String, Object> headers = new Map<String, String>();
List<Swagger.Param> query = new List<Swagger.Param>();
Swagger.OAuth2 auth = new Swagger.OAuth2();
auth.setAccessToken('foo-bar-api-key');
auth.apply(headers, query);
System.assert(query.isEmpty());
System.assertEquals(1, headers.size());
System.assertEquals('Bearer foo-bar-api-key', headers.get('Authorization'));
}
@isTest
private static void ApiClient_returnAuthenticationMatchingInput() {
MockApiClient client = new MockApiClient();
Swagger.ApiKeyHeaderAuth auth1 = new Swagger.ApiKeyHeaderAuth('foo');
Swagger.ApiKeyQueryAuth auth2 = new Swagger.ApiKeyQueryAuth('foo');
Swagger.HttpBasicAuth auth3 = new Swagger.HttpBasicAuth();
Swagger.OAuth2 auth4 = new Swagger.OAuth2();
client.authentications.put('auth1', auth1);
client.authentications.put('auth2', auth2);
client.authentications.put('auth3', auth3);
client.authentications.put('auth4', auth4);
System.assertEquals(auth1, client.getAuthentication('auth1'));
System.assertEquals(auth2, client.getAuthentication('auth2'));
System.assertEquals(auth3, client.getAuthentication('auth3'));
System.assertEquals(auth4, client.getAuthentication('auth4'));
}
@isTest
private static void ApiClient_noAuthenticationsMatchInputReturnNull() {
MockApiClient client = new MockApiClient();
Swagger.OAuth2 auth = new Swagger.OAuth2();
client.authentications.put('auth', auth);
System.assertEquals(auth, client.getAuthentication('auth'));
System.assertEquals(null, client.getAuthentication('no-auth'));
}
@isTest
private static void ApiClient_setUsernamePasswordFirstBasicAuthOnly() {
MockApiClient client = new MockApiClient();
Swagger.OAuth2 auth1 = new Swagger.OAuth2();
Swagger.ApiKeyQueryAuth auth2 = new Swagger.ApiKeyQueryAuth('auth2');
Swagger.ApiKeyHeaderAuth auth3 = new Swagger.ApiKeyHeaderAuth('auth3');
Swagger.HttpBasicAuth auth4 = new Swagger.HttpBasicAuth();
Swagger.HttpBasicAuth auth5 = new Swagger.HttpBasicAuth();
client.authentications.put('auth1', auth1);
client.authentications.put('auth2', auth2);
client.authentications.put('auth3', auth3);
client.authentications.put('auth4', auth4);
client.authentications.put('auth5', auth5);
client.setUsername('username');
client.setPassword('password');
System.assertEquals('Bearer ', auth1.getHeaderValue());
System.assertEquals('', auth2.getApiKey());
System.assertEquals('', auth3.getApiKey());
System.assertEquals('Basic dXNlcm5hbWU6cGFzc3dvcmQ=', auth4.getHeaderValue());
System.assertEquals('Basic Og==', auth5.getHeaderValue());
}
@isTest
private static void ApiClient_setUsernameExceptionNoBasicAuth() {
Swagger.ApiClient client = new Swagger.ApiClient();
try {
client.setUsername('username');
} catch (NoSuchElementException e) {
return;
}
System.assert(false);
}
@isTest
private static void ApiClient_setPasswordExceptionNoBasicAuth() {
Swagger.ApiClient client = new Swagger.ApiClient();
try {
client.setPassword('password');
} catch (NoSuchElementException e) {
return;
}
System.assert(false);
}
@isTest
private static void ApiClient_setCredentialsFirstBasicAuthOnly() {
MockApiClient client = new MockApiClient();
Swagger.OAuth2 auth1 = new Swagger.OAuth2();
Swagger.ApiKeyQueryAuth auth2 = new Swagger.ApiKeyQueryAuth('auth2');
Swagger.ApiKeyHeaderAuth auth3 = new Swagger.ApiKeyHeaderAuth('auth3');
Swagger.HttpBasicAuth auth4 = new Swagger.HttpBasicAuth();
Swagger.HttpBasicAuth auth5 = new Swagger.HttpBasicAuth();
client.authentications.put('auth1', auth1);
client.authentications.put('auth2', auth2);
client.authentications.put('auth3', auth3);
client.authentications.put('auth4', auth4);
client.authentications.put('auth5', auth5);
client.setCredentials('username', 'password');
System.assertEquals('Bearer ', auth1.getHeaderValue());
System.assertEquals('', auth2.getApiKey());
System.assertEquals('', auth3.getApiKey());
System.assertEquals('Basic dXNlcm5hbWU6cGFzc3dvcmQ=', auth4.getHeaderValue());
System.assertEquals('Basic Og==', auth5.getHeaderValue());
}
@isTest
private static void ApiClient_setCredentialsExceptionNoBasicAuth() {
Swagger.ApiClient client = new Swagger.ApiClient();
try {
client.setCredentials('username', 'password');
} catch (NoSuchElementException e) {
return;
}
System.assert(false);
}
@isTest
private static void ApiClient_setApiKeyFirstKeyAuthOnly() {
MockApiClient client = new MockApiClient();
Swagger.OAuth2 auth1 = new Swagger.OAuth2();
Swagger.HttpBasicAuth auth2 = new Swagger.HttpBasicAuth();
Swagger.HttpBasicAuth auth3 = new Swagger.HttpBasicAuth();
Swagger.ApiKeyQueryAuth auth4 = new Swagger.ApiKeyQueryAuth('auth4');
Swagger.ApiKeyHeaderAuth auth5 = new Swagger.ApiKeyHeaderAuth('auth5');
client.authentications.put('auth1', auth1);
client.authentications.put('auth2', auth2);
client.authentications.put('auth3', auth3);
client.authentications.put('auth4', auth4);
client.authentications.put('auth5', auth5);
client.setApiKey('foo-bar-api-key');
System.assertEquals('Bearer ', auth1.getHeaderValue());
System.assertEquals('Basic Og==', auth2.getHeaderValue());
System.assertEquals('Basic Og==', auth3.getHeaderValue());
System.assertEquals('foo-bar-api-key', auth4.getApiKey());
System.assertEquals('', auth5.getApiKey());
}
@isTest
private static void ApiClient_setApiKeyExceptionNoKeyAuth() {
Swagger.ApiClient client = new Swagger.ApiClient();
try {
client.setApiKey('foo-bar-api-key');
} catch (NoSuchElementException e) {
return;
}
System.assert(false);
}
@isTest
private static void ApiClient_setAccessTokenFirstOauthOnly() {
MockApiClient client = new MockApiClient();
Swagger.HttpBasicAuth auth1 = new Swagger.HttpBasicAuth();
Swagger.ApiKeyQueryAuth auth2 = new Swagger.ApiKeyQueryAuth('auth2');
Swagger.ApiKeyHeaderAuth auth3 = new Swagger.ApiKeyHeaderAuth('auth3');
Swagger.OAuth2 auth4 = new Swagger.OAuth2();
Swagger.OAuth2 auth5 = new Swagger.OAuth2();
client.authentications.put('auth1', auth1);
client.authentications.put('auth2', auth2);
client.authentications.put('auth3', auth3);
client.authentications.put('auth4', auth4);
client.authentications.put('auth5', auth5);
client.setAccessToken('foo-bar-api-key');
System.assertEquals('Basic Og==', auth1.getHeaderValue());
System.assertEquals('', auth2.getApiKey());
System.assertEquals('', auth3.getApiKey());
System.assertEquals('Bearer foo-bar-api-key', auth4.getHeaderValue());
System.assertEquals('Bearer ', auth5.getHeaderValue());
}
@isTest
private static void ApiClient_setAccessTokenExceptionNoOAuth() {
Swagger.ApiClient client = new Swagger.ApiClient();
try {
client.setAccessToken('foo-bar-api-key');
} catch (NoSuchElementException e) {
return;
}
System.assert(false);
}
@isTest
@@ -483,22 +283,6 @@ private class SwaggerTest {
System.assert(headers3.isEmpty());
}
@isTest
private static void ApiClient_applyOnlyGivenAuthMethodsToParams() {
MockApiClient client = new MockApiClient();
Map<String, Object> headers = new Map<String, Object>();
Swagger.OAuth2 auth1 = new Swagger.OAuth2();
Swagger.ApiKeyHeaderAuth auth2 = new Swagger.ApiKeyHeaderAuth('X-Authentication-Token');
auth1.setAccessToken('boo-bat-api-key');
auth2.setApiKey('foo-bar-api-key');
client.authentications.put('auth1', auth1);
client.authentications.put('auth2', auth2);
client.applyAuthentication(new List<String>{'auth2'}, headers, new List<Swagger.Param>());
System.assertEquals(1, headers.size());
System.assertEquals('foo-bar-api-key', headers.get('X-Authentication-Token'));
}
@isTest
private static void ApiClient_formUrlWithQueryParamsPathParams() {
MockApiClient client = new MockApiClient();
@@ -513,206 +297,6 @@ private class SwaggerTest {
System.assertEquals(expected, actual);
}
@isTest
private static void ApiClient_setupRequestWithBody() {
MockApiClient client = new MockApiClient();
HttpResponse res = new HttpResponse();
SwaggerResponseMock mock = new SwaggerResponseMock(res);
Swagger.OAuth2 auth = new Swagger.OAuth2();
auth.setAccessToken('foo-bar-access-token');
client.authentications.put('oauth_method', auth);
Test.setMock(HttpCalloutMock.class, mock);
HttpResponse returned = client.getResponse(
'PUT', '/courses/{course}/assignments/{assignmentId}',
new Map<String, Object> {
'title' => 'Chapter 4 quiz',
'timed' => true,
'time' => 60,
'points' => 20.5,
'due' => Datetime.newInstanceGmt(2016, 5, 10, 23, 59, 59),
'description' => ''
},
new List<Swagger.Param>(),
new List<Swagger.Param>(),
new Map<String, Object>{
'course' => 'acc321',
'assignmentId' => 5
},
new Map<String, Object>{
'X-Session' => 'foo-bar-444'
},
new List<String>{'application/json', 'application/xml'},
new List<String>{'application/json', 'application/xml'},
new List<String>{'oauth_method'}
);
HttpRequest req = mock.getRequest();
String expectedUrl = 'https://www.mccombs.utexas.edu/courses/acc321/assignments/5';
Set<String> body = new Set<String>(req
.getBody()
.removeStart('{')
.removeEnd('}')
.split(',')
);
System.assertEquals(res, returned);
System.assertEquals(expectedUrl, req.getEndpoint());
System.assertEquals(6, body.size());
System.assert(body.contains('"title":"Chapter 4 quiz"'));
System.assert(body.contains('"timed":true'));
System.assert(body.contains('"time":60'));
System.assert(body.contains('"points":20.5'));
System.assert(body.contains('"due":"2016-05-10T23:59:59.000Z"'));
System.assert(body.contains('"description":""'));
System.assertEquals('PUT', req.getMethod());
System.assertEquals('Bearer foo-bar-access-token', req.getHeader('Authorization'));
System.assertEquals('foo-bar-444', req.getHeader('X-Session'));
System.assertEquals('application/json', req.getHeader('Accept'));
System.assertEquals('application/json', req.getHeader('Content-Type'));
}
@isTest
private static void ApiClient_setupRequestWithForm() {
MockApiClient client = new MockApiClient();
HttpResponse res = new HttpResponse();
SwaggerResponseMock mock = new SwaggerResponseMock(res);
Swagger.OAuth2 auth = new Swagger.OAuth2();
auth.setAccessToken('foo-bar-access-token');
client.authentications.put('oauth_method', auth);
Test.setMock(HttpCalloutMock.class, mock);
HttpResponse returned = client.getResponse(
'PUT', '/courses/{course}/assignments/{assignmentId}', '',
new List<Swagger.Param>(),
new List<Swagger.Param>{
new Swagger.Param('title', 'Chapter 4 quiz'),
new Swagger.Param('timed', 'true'),
new Swagger.Param('time', '60'),
new Swagger.Param('points', '20.5'),
new Swagger.Param('due', '2016-05-10 18:59:59'),
new Swagger.Param('description', 'complete & upload \'section1: advanced\'')
},
new Map<String, Object>{
'course' => 'acc321',
'assignmentId' => 5
},
new Map<String, Object>{
'X-Session' => 'foo-bar-444'
},
new List<String>{'text/html', 'application/xml'},
new List<String>{'application/x-www-form-urlencoded'},
new List<String>{'oauth_method'}
);
HttpRequest req = mock.getRequest();
String expectedUrl = 'https://www.mccombs.utexas.edu/courses/acc321/assignments/5';
Set<String> body = new Set<String>(req.getBody().split('&'));
System.assertEquals(res, returned);
System.assertEquals(expectedUrl, req.getEndpoint());
System.assertEquals(6, body.size());
System.assert(body.contains('title=Chapter+4+quiz'));
System.assert(body.contains('timed=true'));
System.assert(body.contains('time=60'));
System.assert(body.contains('points=20.5'));
System.assert(body.contains('due=2016-05-10+18%3A59%3A59'));
System.assert(body.contains('description=complete+%26+upload+%27section1%3A+advanced%27'));
System.assertEquals('PUT', req.getMethod());
System.assertEquals('Bearer foo-bar-access-token', req.getHeader('Authorization'));
System.assertEquals('foo-bar-444', req.getHeader('X-Session'));
System.assertEquals('text/html,application/xml', req.getHeader('Accept'));
System.assertEquals('application/x-www-form-urlencoded', req.getHeader('Content-Type'));
}
@isTest
private static void ApiClient_setupRequestWithQuery() {
MockApiClient client = new MockApiClient();
HttpResponse res = new HttpResponse();
SwaggerResponseMock mock = new SwaggerResponseMock(res);
Swagger.OAuth2 auth = new Swagger.OAuth2();
auth.setAccessToken('foo-bar-access-token');
client.authentications.put('oauth_method', auth);
Test.setMock(HttpCalloutMock.class, mock);
HttpResponse returned = client.getResponse(
'GET', '/courses/{course}/assignments', '',
new List<Swagger.Param>{
new Swagger.Param('title', '#chapter1:section2'),
new Swagger.Param('due', '2016-05-10 18:59:59')
},
new List<Swagger.Param>(),
new Map<String, Object>{
'course' => 'acc321'
},
new Map<String, Object>(),
new List<String>{'application/xml'},
new List<String>{'text/plain'},
new List<String>{'oauth_method'}
);
HttpRequest req = mock.getRequest();
List<String> splitUrl = req.getEndpoint().split('\\?');
String expectedUrl = 'https://www.mccombs.utexas.edu/courses/acc321/assignments';
Set<String> query = new Set<String>(splitUrl.get(1).split('&'));
System.assertEquals(res, returned);
System.assertEquals(expectedUrl, splitUrl.get(0));
System.assertEquals(2, query.size());
System.assert(query.contains('title=%23chapter1%3Asection2'));
System.assert(query.contains('due=2016-05-10+18%3A59%3A59'));
System.assertEquals('GET', req.getMethod());
System.assertEquals('Bearer foo-bar-access-token', req.getHeader('Authorization'));
System.assertEquals('application/xml', req.getHeader('Accept'));
System.assertEquals('text/plain', req.getHeader('Content-Type'));
}
@isTest
private static void ApiClient_nonSuccessfulStatusCodeException() {
MockApiClient client = new MockApiClient();
HttpResponse res = new HttpResponse();
SwaggerResponseMock mock = new SwaggerResponseMock(res);
Swagger.OAuth2 auth = new Swagger.OAuth2();
auth.setAccessToken('foo-bar-access-token');
client.authentications.put('oauth_method', auth);
Test.setMock(HttpCalloutMock.class, mock);
res.setStatus('Not Found');
res.setStatusCode(404);
res.setHeader('X-Request-ID', '1234567890');
res.setHeader('Content-Type', 'application/json');
res.setBody('{"error":"the specified course does not exist"}');
try {
client.invoke(
'GET', '/courses/{course}', '',
new List<Swagger.Param>(),
new List<Swagger.Param>(),
new Map<String, Object>{
'course' => 'acc321'
},
new Map<String, Object>(),
new List<String>{'application/json'},
new List<String>{'text/plain'},
new List<String>{'oauth_method'},
null
);
} catch (Swagger.ApiException e) {
Map<String, String> headers = e.getHeaders();
System.assertEquals('API returned HTTP 404: Not Found', e.getMessage());
System.assertEquals(404, e.getStatusCode());
System.assertEquals('Not Found', e.getStatus());
System.assertEquals('{"error":"the specified course does not exist"}', e.getBody());
System.assertEquals(2, headers.size());
System.assertEquals('1234567890', headers.get('X-Request-ID'));
System.assertEquals('application/json', headers.get('Content-Type'));
return;
}
System.assert(false);
}
@isTest
private static void ApiClient_returnParsedBody() {
MockApiClient client = new MockApiClient();

View File

@@ -37,18 +37,10 @@ private class {{classname}}Test {
{{#authMethods}}
client = new {{classPrefix}}Client();
api = new {{classname}}(client);{{#isBasic}}
((Swagger.HttpBasicAuth){{/isBasic}}{{#isOAuth}}
((Swagger.OAuth2){{/isOAuth}}{{#isApiKey}}
((Swagger.ApiKeyAuth){{/isApiKey}} client.getAuthentication('{{name}}'))
{{#isBasic}}
.setCredentials('username', 'password');
{{/isBasic}}
{{#isOAuth}}
.setAccessToken('foo-bar-access-token');
{{/isOAuth}}
api = new {{classname}}(client);{{#isApiKey}}
((Swagger.ApiKeyAuth){{/isApiKey}} client.getAuthentication('{{name}}');
{{#isApiKey}}
.setApiKey('foo-bar-api-key');
client.setApiKey('foo-bar-api-key');
{{/isApiKey}}
{{#examples}}

View File

@@ -2,6 +2,7 @@ public class {{classPrefix}}Client extends Swagger.ApiClient {
{{#hasAuthMethods}}
public {{classPrefix}}Client() {
basePath = '{{basePath}}';
calloutName = '{{calloutName}}';
{{#authMethods}}
{{#isApiKey}}
{{#isKeyInQuery}}
@@ -11,20 +12,13 @@ public class {{classPrefix}}Client extends Swagger.ApiClient {
authentications.put('{{name}}', new Swagger.ApiKeyHeaderAuth('{{keyParamName}}'));
{{/isKeyInQuery}}
{{/isApiKey}}
{{^isApiKey}}
{{#isBasic}}
authentications.put('{{name}}', new Swagger.HttpBasicAuth());
{{/isBasic}}
{{^isBasic}}
authentications.put('{{name}}', new Swagger.OAuth2());
{{/isBasic}}
{{/isApiKey}}
{{/authMethods}}
}
{{/hasAuthMethods}}
{{^hasAuthMethods}}
public {{classPrefix}}Client() {
basePath = '{{basePath}}';
calloutName = '{{calloutName}}';
}
{{/hasAuthMethods}}
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<NamedCredential xmlns="http://soap.sforce.com/2006/04/metadata">
<endpoint>{{basePath}}</endpoint>
<principalType>Anonymous</principalType>
<protocol>NoAuthentication</protocol>
<label>{{calloutName}}</label>
</NamedCredential>

View File

@@ -25,7 +25,7 @@ Generated with Swagger Codegen (github.com/swagger-api/swagger-codegen)</descrip
</types>
<types>
<members>{{sanitizedName}}</members>
<name>RemoteSiteSetting</name>
<name>NamedCredential</name>
</types>
<version>{{apiVersion}}</version>
</Package>

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<RemoteSiteSetting xmlns="http://soap.sforce.com/2006/04/metadata">{{#shortDescription}}
<description>{{{shortDescription}}}</description>{{/shortDescription}}
<disableProtocolSecurity>false</disableProtocolSecurity>
<isActive>true</isActive>
<url>{{basePath}}</url>
</RemoteSiteSetting>

View File

@@ -0,0 +1,10 @@
{
"sfdxSource": true,
"version": "1.0.0",
"sourceFolder": "src/",
"folders": [
"src/classes"
],
"files": [
]
}

View File

@@ -4,5 +4,5 @@
:license {:name "<&projectLicenseName>"<#projectLicenseUrl>
:url "<&projectLicenseUrl>"</projectLicenseUrl>}</projectLicenseName>
:dependencies [[org.clojure/clojure "1.7.0"]
[clj-http "2.0.0"]
[clj-http "3.6.0"]
[cheshire "5.5.0"]])

View File

@@ -102,18 +102,27 @@ namespace Example
{
public void main()
{
{{#apiInfo}}{{#apis}}{{#-first}}{{#operations}}{{#operation}}{{#-first}}{{#hasAuthMethods}}{{#authMethods}}{{#isBasic}}
{{#apiInfo}}{{#apis}}{{#-first}}{{#operations}}{{#operation}}{{#-first}}
{{#hasAuthMethods}}
{{#authMethods}}
{{#isBasic}}
// Configure HTTP basic authorization: {{{name}}}
Configuration.Default.Username = "YOUR_USERNAME";
Configuration.Default.Password = "YOUR_PASSWORD";{{/isBasic}}{{#isApiKey}}
Configuration.Default.Password = "YOUR_PASSWORD";
{{/isBasic}}
{{#isApiKey}}
// Configure API key authorization: {{{name}}}
Configuration.Default.ApiKey.Add("{{{keyParamName}}}", "YOUR_API_KEY");
// Uncomment below to setup prefix (e.g. Bearer) for API key, if needed
// Configuration.Default.ApiKeyPrefix.Add("{{{keyParamName}}}", "Bearer");{{/isApiKey}}{{#isOAuth}}
// Configuration.Default.ApiKeyPrefix.Add("{{{keyParamName}}}", "Bearer");
{{/isApiKey}}
{{#isOAuth}}
// Configure OAuth2 access token for authorization: {{{name}}}
Configuration.Default.AccessToken = "YOUR_ACCESS_TOKEN";{{/isOAuth}}{{/authMethods}}
{{/hasAuthMethods}}
Configuration.Default.AccessToken = "YOUR_ACCESS_TOKEN";
{{/isOAuth}}
{{/authMethods}}
{{/hasAuthMethods}}
var apiInstance = new {{classname}}();
{{#allParams}}
{{#isPrimitiveType}}
@@ -136,9 +145,10 @@ namespace Example
{
Debug.Print("Exception when calling {{classname}}.{{operationId}}: " + e.Message );
}
{{/-first}}{{/operation}}{{/operations}}{{/-first}}{{/apis}}{{/apiInfo}}
}
}
}{{/-first}}{{/operation}}{{/operations}}{{/-first}}{{/apis}}{{/apiInfo}}
}
```
<a name="documentation-for-api-endpoints"></a>

View File

@@ -32,18 +32,26 @@ namespace Example
{
public void main()
{
{{#hasAuthMethods}}{{#authMethods}}{{#isBasic}}
{{#hasAuthMethods}}
{{#authMethods}}
{{#isBasic}}
// Configure HTTP basic authorization: {{{name}}}
Configuration.Default.Username = "YOUR_USERNAME";
Configuration.Default.Password = "YOUR_PASSWORD";{{/isBasic}}{{#isApiKey}}
Configuration.Default.Password = "YOUR_PASSWORD";
{{/isBasic}}
{{#isApiKey}}
// Configure API key authorization: {{{name}}}
Configuration.Default.ApiKey.Add("{{{keyParamName}}}", "YOUR_API_KEY");
// Uncomment below to setup prefix (e.g. Bearer) for API key, if needed
// Configuration.Default.ApiKeyPrefix.Add("{{{keyParamName}}}", "Bearer");{{/isApiKey}}{{#isOAuth}}
// Configuration.Default.ApiKeyPrefix.Add("{{{keyParamName}}}", "Bearer");
{{/isApiKey}}
{{#isOAuth}}
// Configure OAuth2 access token for authorization: {{{name}}}
Configuration.Default.AccessToken = "YOUR_ACCESS_TOKEN";{{/isOAuth}}{{/authMethods}}
{{/hasAuthMethods}}
Configuration.Default.AccessToken = "YOUR_ACCESS_TOKEN";
{{/isOAuth}}
{{/authMethods}}
{{/hasAuthMethods}}
var apiInstance = new {{classname}}();
{{#allParams}}
{{#isPrimitiveType}}
@@ -75,7 +83,7 @@ namespace Example
{{^allParams}}This endpoint does not need any parameter.{{/allParams}}{{#allParams}}{{#-last}}
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------{{/-last}}{{/allParams}}
{{#allParams}} **{{paramName}}** | {{#isFile}}**{{dataType}}**{{/isFile}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isFile}}[**{{dataType}}**]({{baseType}}.md){{/isFile}}{{/isPrimitiveType}}| {{description}} | {{^required}}[optional] {{/required}}{{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}}
{{#allParams}} **{{paramName}}** | {{#isFile}}**{{dataType}}**{{/isFile}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isFile}}[**{{dataType}}**]({{#isContainer}}{{baseType}}{{/isContainer}}{{^isContainer}}{{dataType}}{{/isContainer}}.md){{/isFile}}{{/isPrimitiveType}}| {{description}} | {{^required}}[optional] {{/required}}{{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}}
{{/allParams}}
### Return type

View File

@@ -117,7 +117,9 @@ module {{moduleName}}
end
end
Typhoeus::Request.new(url, req_opts)
request = Typhoeus::Request.new(url, req_opts)
download_file(request) if opts[:return_type] == 'File'
request
end
# Check if the given MIME is a JSON MIME.
@@ -138,14 +140,16 @@ module {{moduleName}}
# @param [String] return_type some examples: "User", "Array[User]", "Hash[String,Integer]"
def deserialize(response, return_type)
body = response.body
# handle file downloading - return the File instance processed in request callbacks
# note that response body is empty when the file is written in chunks in request on_body callback
return @tempfile if return_type == 'File'
return nil if body.nil? || body.empty?
# return response body directly for String return type
return body if return_type == 'String'
# handle file downloading - save response body into a tmp file and return the File instance
return download_file(response) if return_type == 'File'
# ensuring a default content type
content_type = response.headers['Content-Type'] || 'application/json'
@@ -208,30 +212,38 @@ module {{moduleName}}
# Save response body into a file in (the defined) temporary folder, using the filename
# from the "Content-Disposition" header if provided, otherwise a random filename.
# The response body is written to the file in chunks in order to handle files which
# size is larger than maximum Ruby String or even larger than the maximum memory a Ruby
# process can use.
#
# @see Configuration#temp_folder_path
# @return [Tempfile] the file downloaded
def download_file(response)
content_disposition = response.headers['Content-Disposition']
if content_disposition and content_disposition =~ /filename=/i
filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1]
prefix = sanitize_filename(filename)
else
prefix = 'download-'
end
prefix = prefix + '-' unless prefix.end_with?('-')
def download_file(request)
tempfile = nil
encoding = response.body.encoding
Tempfile.open(prefix, @config.temp_folder_path, encoding: encoding) do |file|
file.write(response.body)
tempfile = file
encoding = nil
request.on_headers do |response|
content_disposition = response.headers['Content-Disposition']
if content_disposition and content_disposition =~ /filename=/i
filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1]
prefix = sanitize_filename(filename)
else
prefix = 'download-'
end
prefix = prefix + '-' unless prefix.end_with?('-')
encoding = response.body.encoding
tempfile = Tempfile.open(prefix, @config.temp_folder_path, encoding: encoding)
@tempfile = tempfile
end
request.on_body do |chunk|
chunk.force_encoding(encoding)
tempfile.write(chunk)
end
request.on_complete do |response|
tempfile.close
@config.logger.info "Temp file written to #{tempfile.path}, please copy the file to a proper folder "\
"with e.g. `FileUtils.cp(tempfile.path, '/new/file/path')` otherwise the temp file "\
"will be deleted automatically with GC. It's also recommended to delete the temp file "\
"explicitly with `tempfile.delete`"
end
@config.logger.info "Temp file written to #{tempfile.path}, please copy the file to a proper folder "\
"with e.g. `FileUtils.cp(tempfile.path, '/new/file/path')` otherwise the temp file "\
"will be deleted automatically with GC. It's also recommended to delete the temp file "\
"explicitly with `tempfile.delete`"
tempfile
end
# Sanitize filename by removing path.