I am new to using Swagger Codegen so I assume I am doing something completely wrong. I have a remote swagger.json that I am using to generate a java client. Everything works and looks good but the example usages in the readme are not referencing any API key.
I don't have access to the remote API that I am using just trying to create a nice Java SDK for interfacing with it.
This is what I am using to generate the code.
java -jar C:/Development/codegen/swagger-codegen-cli.jar generate
-a "client_id:XXXXXXXXXX,client_secret:YYYYYYYYYYYYY"
-i https://BLAH/swagger/v1/swagger.json -l java
-o C:/Development/workspace/JavaClient
-c C:/Development/workspace/JavaClient/java-genconfig.json
Then the example that get's generated in the read me looks something like this...
public static void main(String[] args) {
BusinessGroupApi apiInstance = new BusinessGroupApi();
Integer businessGroupId = 56; // Integer | The ID of the business group to fetch.
String apiVersion = "1.0"; // String | The requested API version
try {
BusinessGroup result = apiInstance.getBusinessGroupAsync(businessGroupId, apiVersion);
System.out.println(result);
} catch (ApiException e) {
System.err.println("Exception when calling BusinessGroupApi#getBusinessGroupAsync");
e.printStackTrace();
}
}
Side Note
When I try running the example, I get an error saying
Failed to connect to localhost/0:0:0:0:0:0:0:1:443
Is there some setting that I need to set so it looks for the service at a remote location instead of locally?
EDIT
I realized that I needed to modify their swagger as they might not have everything fleshed out.
Swagger Codegen Version = 2.4.5
swagger.json (Excluded the paths and definitions) I also downloaded thiers locally and added some more info to make it generate more info. I added host, basePath, schemes, consumes, produces, security and securityDefinitions.
{
"swagger": "2.0",
"info": {
"version": "1.0",
"title": "removed"
},
"host": "apitest.removed.com",
"basePath": "/removed/api",
"schemes": [
"https"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"security": [
{
"clientId": []
},
{
"clientSecret": []
}
],
"securityDefinitions": {
"clientId": {
"type": "apiKey",
"in": "header",
"name": "client_id"
},
"clientSecret": {
"type": "apiKey",
"in": "header",
"name": "client_secret"
}
}
}
This actually updated the readme to look how I would expect it to look
ApiClient defaultClient = Configuration.getDefaultApiClient();
// Configure API key authorization: client_id
ApiKeyAuth client_id = (ApiKeyAuth) defaultClient.getAuthentication("client_id");
client_id.setApiKey("YOUR API KEY");
// Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null)
//client_id.setApiKeyPrefix("Token");
// Configure API key authorization: client_secret
ApiKeyAuth client_secret = (ApiKeyAuth) defaultClient.getAuthentication("client_secret");
client_secret.setApiKey("YOUR API KEY");
// Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null)
//client_secret.setApiKeyPrefix("Token");
BusinessGroupApi apiInstance = new BusinessGroupApi();
Integer businessGroupId = 56; // Integer | The ID of the business group to fetch.
String apiVersion = "1.0"; // String | The requested API version
try {
BusinessGroup result = apiInstance.getBusinessGroupAsync(businessGroupId, apiVersion);
System.out.println(result);
} catch (ApiException e) {
System.err.println("Exception when calling BusinessGroupApi#getBusinessGroupAsync");
e.printStackTrace();
}
Yet when I plug in my client_id and client_secret and try to run it I get a Exception in thread "main" java.lang.NullPointerException
at removed.Tester.main(Tester.java:18). I think I might have the security definitions not set up correctly.
It's not OAuth but they require a client_id and client_secret to be passed in the header parameters.
EDIT 2
Exception when calling BusinessGroupApi#getBusinessGroupAsync
package.client.ApiException:
at package.client.ApiClient.handleResponse(ApiClient.java:927)
at package.client.ApiClient.execute(ApiClient.java:843)
at package.client.api.BusinessGroupApi.getBusinessGroupAsyncWithHttpInfo(BusinessGroupApi.java:148)
at package.client.api.BusinessGroupApi.getBusinessGroupAsync(BusinessGroupApi.java:133)
at Tester.main(Tester.java:30)
Line 30 -> BusinessGroup result = apiInstance.getBusinessGroupAsync(businessGroupId, apiVersion);
EDIT 3
I enabled debugging with
defaultClient.setDebugging(true);
It looks like it's working but for some reason doesn't like my client_id and client_secret despite them both being the ones I used in postman.
--> GET <removed>/api/api/businessGroups/56?api-version=1.0 HTTP/1.1
Accept: application/json
client_secret: <removed>
client_id: <removed>
User-Agent: Swagger-Codegen/1.0-SNAPSHOT/java
--> END GET
<-- HTTP/1.1 403 (393ms)
Content-Length: 80
Content-Type: application/json
Date: Mon, 10 Jun 2019 20:05:07 GMT
QL-LB-Appliance: <removed>
QL-LB-Pool: <removed>
QL-LB-Server: <removed>
OkHttp-Sent-Millis: <removed>
OkHttp-Received-Millis: <removed>
{ "error": "invalid_client", "description": "wrong client_id or client_secret" }
<-- END HTTP (80-byte body)
Exception when calling BusinessGroupApi#getBusinessGroupAsync
<removed>.client.ApiException:
at <removed>.client.ApiClient.handleResponse(ApiClient.java:927)
at <removed>.client.ApiClient.execute(ApiClient.java:843)
at <removed>.client.api.BusinessGroupApi.getBusinessGroupAsyncWithHttpInfo(BusinessGroupApi.java:148)
at <removed>.client.api.BusinessGroupApi.getBusinessGroupAsync(BusinessGroupApi.java:133)
at Tester.main(Tester.java:32)
Related
I am using
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-netty</artifactId>
<version>5.11.2</version>
<scope>test</scope>
</dependency>
for integration tests of a REST API. I've started with very basic expectations, to further ellaborate the tests later, once the minimum stuff passes the test. To my surpise, MockServer keeps telling me that no received requests match my expectations.
I am using the Java API, to write tests that use Mockito and PowerMock to deal with static methods. TestNG is the Test Freamework.
This is my code:
#PowerMockIgnore({"javax.xml.parsers.*", "org.apache.logging.log4j.*", "com.sun.org.apache.*", "sun.security.*", "javax.net.ssl.*"})
#PrepareForTest({K8sTarget.class, K8sApi.class})
public class DataAccessImplTest extends PowerMockTestCase {
private static final String HTTP_METHOD_GET = "GET";
private static final String USER_ID= "46756123123";
private static final String USERS_PATH = "/api/v1/users/%s";
private static final String CONTENT_TYPE_APP_JSON = "application/json";
#Mock
Target mockTarget;
#Mock
K8sClient mockK8sClient;
private DataAccessFactory dataAccessFactory;
private DataAccessImpl dataAccessUT;
private MockServerClient mockServer;
AutoCloseable closeable;
#BeforeClass
public void setup() {
// ensure all connection using HTTPS will use the SSL context defined by
// MockServer to allow dynamically generated certificates to be accepted
HttpsURLConnection.setDefaultSSLSocketFactory(
new KeyStoreFactory(new MockServerLogger()).sslContext().getSocketFactory());
this.mockServer = startClientAndServer(PortFactory.findFreePort());
this.closeable = MockitoAnnotations.openMocks(this);
dataAccessFactory = DataAccessFactory.getInstance();
assertNotNull(dataAccessFactory);
PowerMockito.mockStatic(K8sApi.class);
PowerMockito.mockStatic(K8sTarget.class);
PowerMockito.when(K8sApi.getK8sClient()).thenReturn(mockK8sClient);
PowerMockito.when(K8sTarget.of(Mockito.any(K8sClient.class), Mockito.any(Target.class))).thenReturn(mockTarget);
Mockito.when(mockTarget.getName()).thenReturn("localhost");
Mockito.when(mockTarget.getPort()).thenReturn(this.mockServer.getPort().intValue());
dataAccessUT = dataAccessFactory.createDataClient();
}
#BeforeMethod
public void prepareMocks() {
Mockito.when(mockTarget.getName()).thenReturn("localhost");
Mockito.when(mockTarget.getPort()).thenReturn(this.mockServer.getPort().intValue());
}
#AfterClass
public void teardown() throws Exception {
this.closeable.close();
this.mockServer.stop();
}
#Test
public void getUserTest_200_Ok() throws IOException {
dataAccessUT.getUserData(USER_ID);
mockServer.when(request()
.withMethod(HTTP_METHOD_GET)
.withPath(String.format(USERS_PATH, USER_ID))
)
.respond(
response()
.withStatusCode(HttpStatusCode.OK_200.code())
.withHeader(HttpHeaderNames.CONTENT_TYPE.toString(), CONTENT_TYPE_APP_JSON)
.withBody("some_response_body")
);
}
}
and these are the console logs:
10:06:24.067 [nioEventLoopGroup-2-1] DEBUG com.commonlibrary.httpclient.common.HttpConnectionListener:28 - 0.1 HttpConnectionListener::operationComplete: connected to [localhost:58136] from [/127.0.0.1:58204]
10:06:24.285 [MockServer-EventLog0] INFO org.mockserver.log.MockServerEventLog:108 - 58136 received request:
{
"method" : "GET",
"path" : "/api/v1/users/46756123123",
"headers" : {
"authorization" : [ "Bearer token" ],
"accept" : [ "application/json" ],
"host" : [ "localhost:58136" ],
"content-length" : [ "0" ]
},
"keepAlive" : true,
"secure" : false
}
10:06:24.350 [MockServer-EventLog0] INFO org.mockserver.log.MockServerEventLog:108 - 58136 no expectation for:
{
"method" : "GET",
"path" : "/api/v1/users/46756123123",
"headers" : {
"authorization" : [ "Bearer token" ],
"accept" : [ "application/json" ],
"host" : [ "localhost:58136" ],
"content-length" : [ "0" ]
},
"keepAlive" : true,
"secure" : false
}
returning response:
{
"statusCode" : 404,
"reasonPhrase" : "Not Found"
}
10:06:24.483 [MockServer-EventLog0] INFO org.mockserver.log.MockServerEventLog:108 - 58136 stopped for port: 58136
As you can see (unless I am missing something) request should match the expectation, but it doesn'. I have tried several things, all of them without success:
reduce the request expectation to the bare minimum, just calling request() without defining anything else. This shouls match EVERY incoming request. Same result.
introduce Times.exactly(1) in the expectation. Same result.
specify the headers I am sending in the request, even though my understanding is that if they are not set in the expectation, they are not used for matching. Same result.
After 2 days, I am running out of ideas, so any help or hint would be appreciated. Thanks!
Edition after following hint and checking code examples in MockServer site
Following #peter-rowth suggestion, I moved the request sent after creating expectations and it worked.
I am editing this issue also to make clear that it duplicates [https://stackoverflow.com/questions/63843619/mockserver-request-not-found][1], that I found later.
It looks like in your test you are creating the expectations in MockServer after executing the call to your code under test? The fact that your console output from MockServer does not output matched/not matched expectations (the default behavior) indicated to me that there are no expectations setup when the web request is made to MockServer and a 404 is default response by MockServer when there is no expectation for a request.
Try adding that expectation as the first line in your test.
I try to send an email from our java project but every time I have a code error 400. So I take the same request printed in the java console and send it from Postman with the same other elements then it works from Postman and i receive the email but from java I have always the code error 400 bad request and when i turn on the Mailjet debug mode the content is null.
Here the final JSON made by Java and inject from Postman
{
"Messages": [
{
"Variables": {
"objet": " objet",
"body": " body "
},
"From": {
"Email": "no-reply#gmail.com"
},
"To": [
{
"Email": "send#gmail.com",
"Name": ""
}
],
"TemplateID": 111111,
"TemplateLanguage": true,
"Subject": "[[data:objet:\" anything\"]]"
}
]
}
The java code :
/**
* Send a message
* #return MailjetResponse
* #throws MailjetException
* #throws MailjetSocketTimeoutException
*/
public MailjetRequest sendEmailCore() {
return new MailjetRequest(Emailv31.resource)
.property(Emailv31.MESSAGES, new JSONArray()
.put(new JSONObject()
.put(Emailv31.Message.FROM, new JSONObject()
.put("Email", senderMail)
.put("Name", senderName))
.put(Emailv31.Message.TO, getRecipientsJson())
.put(Emailv31.Message.TEMPLATEID, TEMPLATE_ID)
.put(Emailv31.Message.TEMPLATELANGUAGE, true)
.put(Emailv31.Message.SUBJECT, "[[data:objet:\" anything\"]]")
.put(Emailv31.Message.VARIABLES, new JSONObject()
.put("objet", " objet")
.put("mailTitle", mailTitle)
.put("body", body))));
}
private JSONArray getRecipientsJson(){
JSONArray json = new JSONArray();
for (String recipient : recipients) {
json.put(new JSONObject()
.put("Email", recipient)
.put("Name", ""));
}
return json;
}
public MailjetResponse sendLoggedMail() throws Exception {
MailjetClient client = new MailjetClient(API_KEY_PUBLIC, API_KEY_PRIVATE, new ClientOptions("v3.1"));
MailjetRequest request = sendEmailCore();
MailjetResponse response = null;
try {
client.setDebug(MailjetClient.VERBOSE_DEBUG);
log.info(request.getBody());
response = client.post(request);
} catch (final MailjetException | MailjetSocketTimeoutException e) {
log.error("sendLoggedMail", e);
}
return response;
}
The MailJet log :
=== HTTP Request ===
POST https://api.mailjet.com/v3.1/send
Accept-Charset:UTF-8
Accept:application/json
user-agent:mailjet-apiv3-java/v4.5.0
Content-Type:application/json
=== HTTP Response ===
Receive url: https://api.mailjet.com/v3.1/send
Status: 400
date:Tue, 01 Sep 2020 08:59:55 GMT
null:HTTP/1.1 400 Bad Request
content-length:177
x-mj-request-guid:0bb2a0ac-849d-4d80-82ed-a10a792e8d19
content-type:application/json; charset=UTF-8
Content:
null
Thank you for your help.
The default value for the connection timeout is too small in version 4.5.0
You can try to set value in client options like this:
new MailjetClient("public", "secret", new ClientOptions(8000));
or just use the newer version, where the default timeout value is set.
I have the same issue with Java Mailjet Client 4.5.0. Downgrading to v4.4.0 this error isn't there.
I use curl to submit to our Kafka Connect service a JSON request message with information about the connector, it is working successfully.
$ curl -i -X POST -H "Accept:application/json" -H "Content-Type:application/json" localhost:8083/connectors/ -d '{ \"name\": \"inventory-connector\", \"config\": { \"connector.class\": \"io.debezium.connector.mysql.MySqlConnector\", \"tasks.max\": \"1\", \"database.hostname\": \"mysql\", \"database.port\": \"3306\", \"database.user\": \"debezium\", \"database.password\": \"dbz\", \"database.server.id\": \"184054\", \"database.server.name\": \"dbserver1\", \"database.whitelist\": \"inventory\", \"database.history.kafka.bootstrap.servers\": \"kafka:9092\", \"database.history.kafka.topic\": \"dbhistory.inventory\" } }'
now I am using node.js server to send data to kafka connect server.
var body = {
"name": "abc",
"config": {
"connector.class": "io.debezium.connector.mysql.MySqlConnector",
"tasks.max": "1",
"database.hostname": "mysql",
"database.port": "3306",
"database.user": "debezium",
"database.password": "dbz",
"database.server.id": "184054",
"database.server.name": "dbserver1",
"database.whitelist": "inventory",
"database.history.kafka.bootstrap.servers": "kafka:9092",
"database.history.kafka.topic": "schema-changes.inventory"
}
};
var options = {
method: 'PUT',
uri: 'http://localhost/connectors/abc/config',
headers: {
'User-Agent': 'Request-Promise'
},
json: true ,
body: body
};
rp(options)
.then(function (data) {
return res.status(200).json({ 'data': data});
})
.catch(function (err) {
console.log(err);
return res.status(500).json({ error: err});
});
however the code throw out an error: saying
{ StatusCodeError: 500 - {"error_code":500,"message":"Cannot deserialize instance of `java.lang.String` out of START_OBJECT token\n at [Source: (org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream); line: 1, column: 42] (through reference chain: java.util.LinkedHashMap[\"config\"])"}
The API description is from https://docs.confluent.io/current/connect/references/restapi.html
If I read the confluent doc correctly, you did mix up two different API endpoints.
In your code, you use the endpoint /connectors/abc/config, which according to the documentation takes a single config object as toplevel, so like this:
{
"connector.class": "io.debezium.connector.mysql.MySqlConnector",
"tasks.max": "1",
"database.hostname": "mysql",
"database.port": "3306",
"database.user": "debezium",
"database.password": "dbz",
"database.server.id": "184054",
"database.server.name": "dbserver1",
"database.whitelist": "inventory",
"database.history.kafka.bootstrap.servers": "kafka:9092",
"database.history.kafka.topic": "schema-changes.inventory"
}
But your JSON object looks like it was meant for the /connectors endpoint.
Changing either the endpoint or your JSON object to match the endpoint you have chosen may fix the problem.
The Java API of Dropbox returns a list of file owner names via a method like
public List<String> getOwners(DbxClientV2 client, String fileId) {
SharedFileMetadata metadata = client.sharing().getFileMetadata();
return metadata.getOwnerDisplayNames();
}
Is there any way of getting the e-mail addresses, too?
According to Dropbox v2 Documentation, it has endpoint - /get_file_metadata.
Example curl request:
curl -X POST https://api.dropboxapi.com/2/sharing/get_file_metadata \
--header "Authorization: Bearer <access token> " \
--header "Content-Type: application/json" \
--data "{\"file\": \"id:3kmLmQFnf1AAAAAAAAAAAw\",\"actions\": []}"
Parameters:
{
"file": "id:3kmLmQFnf1AAAAAAAAAAAw",
"actions": []
}
Returns:
{
"id": "id:3kmLmQFnf1AAAAAAAAAAAw",
"name": "file.txt",
"policy": {
"acl_update_policy": {
".tag": "owner"
},
"shared_link_policy": {
".tag": "anyone"
},
"member_policy": {
".tag": "anyone"
},
"resolved_member_policy": {
".tag": "team"
}
},
"preview_url": "https://www.dropbox.com/scl/fi/fir9vjelf",
"access_type": {
".tag": "viewer"
},
"owner_display_names": [
"Jane Doe"
],
"owner_team": {
"id": "dbtid:AAFdgehTzw7WlXhZJsbGCLePe8RvQGYDr-I",
"name": "Acme, Inc."
},
"path_display": "/dir/file.txt",
"path_lower": "/dir/file.txt",
"permissions": [],
"time_invited": "2016-01-20T00:00:00Z"
}
owner_display_names List of (String)? The display names of the users that own the file. If the file is part of a team folder, the display names of the team admins are also included. Absent if the owner display names cannot be fetched. This field is optional.
So, there are no information about user's email according to file.
To get the information about the members of a shared file with the Dropbox Java SDK, you should use the listFileMembers* methods. There are a few versions you can choose from, depending on your use case and desired method of batching/pagination:
https://dropbox.github.io/dropbox-sdk-java/api-docs/v3.1.x/com/dropbox/core/v2/sharing/DbxUserSharingRequests.html#listFileMembers-java.lang.String-
https://dropbox.github.io/dropbox-sdk-java/api-docs/v3.1.x/com/dropbox/core/v2/sharing/DbxUserSharingRequests.html#listFileMembersBatch-java.util.List-
https://dropbox.github.io/dropbox-sdk-java/api-docs/v3.1.x/com/dropbox/core/v2/sharing/DbxUserSharingRequests.html#listFileMembersBatch-java.util.List-long-
https://dropbox.github.io/dropbox-sdk-java/api-docs/v3.1.x/com/dropbox/core/v2/sharing/DbxUserSharingRequests.html#listFileMembersBuilder-java.lang.String-
https://dropbox.github.io/dropbox-sdk-java/api-docs/v3.1.x/com/dropbox/core/v2/sharing/DbxUserSharingRequests.html#listFileMembersContinue-java.lang.String-
One way to get the owners is via the collaboration metadata:
public List<String> getOwners(DbxClientV2 client, String fileId) {
SharedFileMetadata metadata = client.sharing().getFileMetadata();
List<UserFileMembershipInfo> users = metadata.getUsers();
List<String> owners = new ArrayList<>();
for (UserFileMembershipInfo user : users)
if (user.getAccessType() == AccessLevel.OWNER) {
owners.add(info.getUser().getDisplayName());
}
return owners;
}
Context : Converting Swagger from current REST documentation in 1.2 spec to 2.0
Environment : Java 8, swagger-maven-plugin 3.0.1, swagger annotations (com.wordnik)
Where I am stuck: I was able to generate the REST API documentation successfully. However, REST APIs need an ApiKey as Query param. In 1.2 spec, this was added using the following snippet in index.html
function addApiKeyAuthorization() {
var key = $('#input_apiKey')[0].value;
log("key: " + key);
if(key && key.trim() != "") {
log("added key " + key);
//window.authorizations.add("api_key", new ApiKeyAuthorization("api_key", key, "query"));
window.authorizations.add("apiKey", new ApiKeyAuthorization("apiKey", key, "header"));
}
}
$('#input_apiKey').change(function() {
addApiKeyAuthorization();
});
// if you have an apiKey you would like to pre-populate on the page for demonstration purposes...
var apiKey = "ABCD";
$('#input_apiKey').val(apiKey);
addApiKeyAuthorization();
However, for 2.0 spec, my search led to the following changes in the yaml file.
securityDefinitions:
UserSecurity:
type: apiKey
in: header
name:myApiKey
The current index.html has the following in window function:
window.onload = function() {
// Build a system
const ui = SwaggerUIBundle({
url: "http://someCoolsite.com/swagger.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
window.ui = ui
}
After further exploration, I have found answer to my question above.
First : My index.html is as below:
<script>
$(function(){
window.onload = function() {
// Build a system
const ui = SwaggerUIBundle({
url: "http://www.webhostingsite.com/swagger.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
window.ui = ui
}
window.onFailure = function(data) {
log("Unable to Load SwaggerUI");
}
function addApiKeyAuthorization() {
var key = $('#input_apiKey')[0].value;
log("key: " + key);
if(key && key.trim() != "") {
log("added key " + key);
//window.authorizations.add("api_key", new ApiKeyAuthorization("api_key", key, "query"));
window.authorizations.add("apiKey", new ApiKeyAuthorization("apiKey", key, "query"));
}
}
$('#input_apiKey').change(function() {
addApiKeyAuthorization();
});
});
Then, I updated my swagger.json to be as below:
{
"swagger" : "2.0",
"securityDefinitions": {
"apiKey": {
"type": "apiKey",
"name": "apiKey",
"in": "query"
}
},
"host" : "<api base path>",
"basePath" : "/v1",
"security": [{"apiKey": []}]", //Global security (applies to all operations)
.......
Third: Hosted index.html and swagger.json on AWS S3 for static web hosting.
The part where I went wrong was, "security": [{"apiKey": []}]".
I was doing "security":{"apiKey":[]} all the while forgetting that value of "security" is a list.
Hope this helps.