Tuesday, November 18, 2014

Troubleshooting Swagger issues in WSO2 API Manager

WSO2 API Manager provides this functionality through the integration of Swagger (https://developers.helloreverb.com/swagger). Swagger-based interactive documentation allows you to try out APIs from the documentation itself which is available as the "API Console" in API Store. 

There are certain requirements that need to be satisfied in order to swagger Try-it functionality to work. First requirement is to enable CORS in API Mananger Store. This documentation describes how that should be done. 

But most of them face many issues in getting the swagger Try-it into work. So this blog post describes common issues faced by users with Swagger and how to troubleshoot them.  

Issue-1

API Console keeps on loading the response for ever as below.

Cause -1

API resource not supporting OPTIONS HTTP verb. 

Solution

Add OPTIONS HTTP verb for API resources as below. Then Save the API and Try again. 



Cause -2 

Backend endpoint not supporting OPTIONS HTTP verb. 

Note: You can verify this by directly invoking the backend for OPTIONS verb. If backend is not supporting OPTIONS verb, "403 HTTP method not allowed" will be returned. 

Solution

If you have control over the Backend service/api, enable OPTIONS HTTP verb. 

Note: You can verify this by directly invoking the backend for OPTIONS verb. If backend is supporting OPTIONS verb, 200/202/204 success response should be returned.


If you can't enable OPTIONS HTTP verb in the backend, then what you can do is modify the API synapse sequence of the API, which returns back without sending the request to the backend if it is an OPTIONS request. 

Issue-2

API Console completes request execution, but no response is returned. 


Cause-1

Authentication Type enabled for OPTIONS HTTP verb is not 'None'. 


If this is the cause below error message will be shown in the wso2carbon.log.

org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException: Required OAuth credentials not provided
at org.wso2.carbon.apimgt.gateway.handlers.security.oauth.OAuthAuthenticator.authenticate(OAuthAuthenticator.java:122)
at org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler.handleRequest(APIAuthenticationHandler.java:92)
at org.apache.synapse.rest.API.process(API.java:285)
at org.apache.synapse.rest.RESTRequestHandler.dispatchToAPI(RESTRequestHandler.java:83)
at org.apache.synapse.rest.RESTRequestHandler.process(RESTRequestHandler.java:64)
at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:220)
at org.apache.synapse.core.axis2.SynapseMessageReceiver.receive(SynapseMessageReceiver.java:83)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180)
at org.apache.synapse.transport.passthru.ServerWorker.processNonEntityEnclosingRESTHandler(ServerWorker.java:344)
at org.apache.synapse.transport.passthru.ServerWorker.run(ServerWorker.java:168)
at org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)

Solution

Make the Auth Type as none for OPTIONS HTTP verb as below. Then Save & Publish the API.



Note: If you are seeing the Issue -2 , even though Authentication type is shown as none for OPTIONS, then please re-select the authentication type as 'none' as above. Then Save & Publish the API. There is an UI bug in API Manager 1.7.0, where although you have set some other authentication type other than 'None' for OPTIONS verb, UI shows it as none. 

Cause-2

API Store domain/port which you are currently trying swagger API Console, is not included in the CORS Access-Control-Allow-Origin configuration. For example, in below CORS configuration, only localhost domain addresses are allowed for API Store. But API Console is accessed using IP address. 




Solution

Include domain/port in the CORS Access-Control-Allow-Origin configuration. For above example, we have to include IP address as below.  Then restart the server and try API Console again. 


Issue-3

API Console keeps on loading the response for ever as below when API Store is accessed as HTTPs, while HTTP is working properly. 

Cause-1

Browser blocking the request due to accessing the API Gateway in HTTP from HTTPs. 

Solution

Go to API Publisher and edit "Swagger API Definition" of the API and change the basePath with https gateway address as below. The Save the "Swagger API Definition" and try again. 


Cause-2 

If you are still getting the issue, even after applying the above then, cause can be that the security certificate issued by the server is not trusted by your browser.

Solution

Access the HTTPS gateway endpoint directly from your browser and accept the security certificate. Then try again. 


Saturday, November 1, 2014

Customizing workflows in WSO2 API Manager

In WSO2 API Manager, Workflow extensions allow you to attach a custom workflow to various operations in the API Manager for

  • User Signup
  • Application Creation
  • Application Registration
  • Subscription


By default, the API Manager workflows have Simple Workflow Executor engaged in them. The Simple Workflow Executor carries out an operation without any intervention by a workflow admin. For example, when the user creates an application, the Simple Workflow Executor allows the application to be created without the need for an admin to approve the creation process.

In order to enforce intervention by a workflow admin, you can engage the WS Workflow Executor. It invokes an external Web service when executing a workflow and the process completes based on the output of the Web service. For example, when the user creates an application, the request goes into an intermediary state where it remains until authorized by a workflow admin.

You can try out the default workflow extensions provided by WSO2 API Manager to engage business processes with API management operations as described in here

There are two extension points exposed with WSO2 API Manager to customize workflows.

Customizing the Workflow Executor
  • When you need to change the workflow logic
  • When you need to change the Data Formats


Customizing the Business Process
  • When you are happy with the Data Formats and need to change only the business flow
This blog post will provide a sample on how we can customize workflow executors and change the workflow logic.

First let's look at WorkflowExecutor class which each WS workflow executor is extended from.

/**
 * This is the class that should be extended by each workflow executor implementation.
 */
public abstract class WorkflowExecutor {

/**
 * The Application Registration Web Service Executor.
 */
public class ApplicationRegistrationWSWorkflowExecutor extends WorkflowExecutor{

//Logic to execute the workflow
public void execute(WorkflowDTO workflowDTO) { }

//Logic to complete the workflow
public void complete(WorkflowDTO workflowDTO) { }

//Returns the workflow type - ex: WF_TYPE_AM_USER_SIGNUP
public String getWorkflowType() { }

//Used to get workflow details
public List getWorkflowDetails(String workflowStatus) { }

}


As the example scenario, let's consider the Application registration workflow of WSO2 API manager.
After an application is created, you can subscribe to available APIs, but you get the consumer key/secret and access tokens only after registering the application. There are two types of registrations that can be done to an application: production and sandbox. You change the default application registration workflow in situations such as the following:


  • To issue only sandbox keys when creating production keys is deferred until testing is complete.
  • To restrict untrusted applications from creating production keys. You allow only the creation of sandbox keys.
  • To make API subscribers go through an approval process before creating any type of access token.
Find step by step instructions on how we can configure Application Registration Workflow from here




Sending an email to Administrator upon Application Registration

As the extension of this Application Registration workflow, we are going customize the workflow executor and send an email to Administrator once the workflow is triggered

1. First write a new executor extending ApplicationRegistrationWSWorkflowExecutor

public class AppRegistrationEmailSender extends 
ApplicationRegistrationWSWorkflowExecutor {

2. Add private String attributes and public getters and setters for email properties (adminEmail, emailAddress, emailPassword)

        
        private String adminEmail;
 private String emailAddress;
 private String emailPassword;
        public String getAdminEmail() {
  return adminEmail;
 }

 public void setAdminEmail(String adminEmail) {
  this.adminEmail = adminEmail;
 }

 public String getEmailAddress() {
  return emailAddress;
 }

 public void setEmailAddress(String emailAddress) {
  this.emailAddress = emailAddress;
 }

 public String getEmailPassword() {
  return emailPassword;
 }

 public void setEmailPassword(String emailPassword) {
  this.emailPassword = emailPassword;
 }

3. Override execute(WorkflowDTO workflowDTO) method and implement email sending logic. Finally invoke super.execute(workflowDTO).

        @Override
 public void execute(WorkflowDTO workflowDTO) throws WorkflowException {
   
  ApplicationRegistrationWorkflowDTO appDTO = (ApplicationRegistrationWorkflowDTO) workflowDTO;
  
  String emailSubject = appDTO.getKeyType() + "Application Registration";

  String emailText = "Appplication " + appDTO.getApplication().getName() + " is registered for " + 
    appDTO.getKeyType() + " key by user " + appDTO.getUserName();
  
  try {
   EmailSender.sendEmail(emailAddress, emailPassword, adminEmail, emailSubject, emailText);
  } catch (MessagingException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  
  //SEND EMAIL
  super.execute(workflowDTO);
  
 }


Find the complete source code of custom workflow executor. 
 
package org.wso2.sample.workflow;

import javax.mail.MessagingException;

import org.wso2.carbon.apimgt.impl.dto.ApplicationRegistrationWorkflowDTO;
import org.wso2.carbon.apimgt.impl.dto.WorkflowDTO;
import org.wso2.carbon.apimgt.impl.workflow.ApplicationRegistrationWSWorkflowExecutor;
import org.wso2.carbon.apimgt.impl.workflow.WorkflowException;

public class AppRegistrationEmailSender extends ApplicationRegistrationWSWorkflowExecutor {
 
 private String adminEmail;
 private String emailAddress;
 private String emailPassword;
 

 @Override
 public void execute(WorkflowDTO workflowDTO) throws WorkflowException {
   
  ApplicationRegistrationWorkflowDTO appDTO = (ApplicationRegistrationWorkflowDTO) workflowDTO;
  
  String emailSubject = appDTO.getKeyType() + "Application Registration";

  String emailText = "Appplication " + appDTO.getApplication().getName() + " is registered for " + 
    appDTO.getKeyType() + " key by user " + appDTO.getUserName();
  
  try {
   EmailSender.sendEmail(emailAddress, emailPassword, adminEmail, emailSubject, emailText);
  } catch (MessagingException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  
  //SEND EMAIL
  super.execute(workflowDTO);
  
 }
    
 public String getAdminEmail() {
  return adminEmail;
 }

 public void setAdminEmail(String adminEmail) {
  this.adminEmail = adminEmail;
 }

 public String getEmailAddress() {
  return emailAddress;
 }

 public void setEmailAddress(String emailAddress) {
  this.emailAddress = emailAddress;
 }

 public String getEmailPassword() {
  return emailPassword;
 }

 public void setEmailPassword(String emailPassword) {
  this.emailPassword = emailPassword;
 }

}

Now modify the existing ProductionApplicationRegistration as below.
 

        admin@wso2.com
        admin@gmail.com  
        admin123
        http://localhost:9765/services/ApplicationRegistrationWorkFlowProcess/
        admin
        admin
        https://localhost:8248/services/WorkflowCallbackService


You can do the same modification to SandboxApplicationRegistration workflow as below.
 

        admin@wso2.com
        admin@gmail.com  
        admin123
        http://localhost:9765/services/ApplicationRegistrationWorkFlowProcess/
        admin
        admin
        https://localhost:8248/services/WorkflowCallbackService


With this change, Application Registration workflows will trigger the workflows through AppRegistrationEmailSender which will send an email to adminEmail email address. Then it will invoke the default ApplicationRegistrationWSWorkflowExecutor.