Ballerina connector development sample - BallerinaLang

Ballerina is a general purpose, concurrent and strongly typed programming language with both textual and graphical syntaxes, optimized for integration. In this post we will discuss how we can use ballerina swagger connector development tool to develop connector using already designed swagger API.

First download zip file content and unzip it into your local machine. Also you need to download ballerina composer and run time from the ballerinalang web site to try this.


Now we need to start back end for generated connector.
Goto student-msf4j-server directory and build it.
/swagger-connector-demo/student-msf4j-server>> mvn clean install

Now you will see micro service jar file generated. Then run MSF4J service using following command.
/swagger-connector-demo/student-msf4j-server>> java -jar target/swagger-jaxrs-server-1.0.0.jar
starting Micro Services
2017-02-19 21:37:44 INFO  MicroservicesRegistry:55 - Added microservice: io.swagger.api.StudentsApi@25f38edc
2017-02-19 21:37:44 INFO  MicroservicesRegistry:55 - Added microservice: org.wso2.msf4j.internal.swagger.SwaggerDefinitionService@17d99928
2017-02-19 21:37:44 INFO  NettyListener:68 - Starting Netty Http Transport Listener
2017-02-19 21:37:44 INFO  NettyListener:110 - Netty Listener starting on port 8080
2017-02-19 21:37:44 INFO  MicroservicesRunner:163 - Microservices server started in 307ms

Now we can check MSF4J service running or not using CuRL as follows.
curl -v http://127.0.0.1:8080/students
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET /students HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Connection: keep-alive
< Content-Length: 41
< Content-Type: application/json
<
* Connection #0 to host 127.0.0.1 left intact
{"code":4,"type":"ok","message":"magic!"}


Please use following sample swagger definition to generate connector(this is available in zip file attached).

swagger: '2.0'
info:
 version: '1.0.0'
 title: Swagger School (Simple)
 description: A sample API that uses a school as an example to demonstrate features in the swagger-2.0 specification
 termsOfService: http://helloreverb.com/terms/
 contact:
    name: Swagger API team
    email: foo@example.com
    url: http://swagger.io
 license:
    name: MIT
    url: http://opensource.org/licenses/MIT
host: schol.swagger.io
basePath: /api
schemes:
 - http
consumes:
 - application/json
produces:
 - application/json
paths:
 /students:
    get:
     description: Returns all students from the system that the user has access to
     operationId: findstudents
     produces:
       - application/json
       - application/xml
       - text/xml
       - text/html
     parameters:
       - name: limit
         in: query
         description: maximum number of results to return
         required: false
         type: integer
         format: int32
     responses:
       '200':
         description: student response
         schema:
           type: array
           items:
             $ref: '#/definitions/student'
       default:
         description: unexpected error
         schema:
           $ref: '#/definitions/errorModel'
    post:
     description: Creates a new student in the school.  Duplicates are allowed
     operationId: addstudent
     produces:
       - application/json
     parameters:
       - name: student
         in: body
         description: student to add to the school
         required: true
         schema:
           $ref: '#/definitions/newstudent'
     responses:
       '200':
         description: student response
         schema:
           $ref: '#/definitions/student'
       default:
         description: unexpected error
         schema:
           $ref: '#/definitions/errorModel'
 /students/{id}}:
    get:
     description: Returns a user based on a single ID, if the user does not have access to the student
     operationId: findstudentById
     produces:
       - application/json
       - application/xml
       - text/xml
       - text/html
     parameters:
       - name: id
         in: path
         description: ID of student to fetch
         required: true
         type: integer
         format: int64
       - name: ids
         in: query
         description: ID of student to fetch
         required: false
         type: integer
         format: int64
     responses:
       '200':
         description: student response
         schema:
           $ref: '#/definitions/student'
       default:
         description: unexpected error
         schema:
           $ref: '#/definitions/errorModel'
    delete:
     description: deletes a single student based on the ID supplied
     operationId: deletestudent
     parameters:
       - name: id
         in: path
         description: ID of student to delete
         required: true
         type: integer
         format: int64
     responses:
       '204':
         description: student deleted
       default:
         description: unexpected error
         schema:
           $ref: '#/definitions/errorModel'
definitions:
 student:
    type: object
    required:
     - id
     - name
    properties:
     id:
       type: integer
       format: int64
     name:
       type: string
     tag:
       type: string
 newstudent:
    type: object
    required:
     - name
    properties:
     id:
       type: integer
       format: int64
     name:
       type: string
     tag:
       type: string
 errorModel:
    type: object
    required:
     - code
     - textMessage
    properties:
     code:
       type: integer
       format: int32
     textMessage:
       type: string


Generate connector
./ballerina swagger connector /home/sanjeewa/Desktop/sample.yaml  -p org.wso2 -d ./test
Then add connector to composer and expose it as service.

import ballerina.net.http;
@http:BasePath("/testService")
service echo {
    @http:POST
    resource echo(message m) {
    Default defaultConnector = create Default();
    message response1 = Default.employeeIDGet( defaultConnector, m);
    reply response1;
    }
}
connector Default() {
    http:ClientConnector endpoint = create http:ClientConnector("http://127.0.0.1:8080/students");
    action employeeIDDelete(Default c, message msg)(message ) {
        message response;
        response = http:ClientConnector.delete(endpoint, http:getRequestURL(msg), msg);
        return response;     
    }
     action employeeIDGet(Default c, message msg)(message ) {
        message response;
        response = http:ClientConnector.get(endpoint, http:getRequestURL(msg), msg);
        return response;
    }
     action employeeIDPut(Default c, message msg)(message ) {
        message response;
        response = http:ClientConnector.put(endpoint, http:getRequestURL(msg), msg);
        return response;
    }
     action rootGet(Default c, message msg)(message ) {
        message response;
        response = http:ClientConnector.get(endpoint, http:getRequestURL(msg), msg);
        return response;
    }
     action rootPost(Default c, message msg)(message ) {
        message response;
        response = http:ClientConnector.post(endpoint, http:getRequestURL(msg), msg);
        return response;     
    } 
}

Then you will see relevant files in output directory.

├── test
  └── org
      └── wso2
          ├── default.bal
          ├── LICENSE
          ├── README.md
          └── types.json

Then you can copy generated connector code into composer and start your service development. How its appear in composer source view.

5qHg9h6fB0HmJoB9wQjYa7JMfNGiu3J5vkBS4ybVDkUfdA_tl6_xuXZcE0qz6vDmbZsTG2m9HhHfXwPTlPnTaLeTcyWvafZPCcGJOgU-AqHXtuhOxHDPx0Nz5NYFe31euoTPSQXZ (1160×796)

How its loaded in composer UI.
y3bhSlbBgD1u3cuhfJrBtt4aPZwIFGd-ASSGvPlOvaenekA4RLNVGhXa6WWpkSs1iDRUwFiUqU6ZH9m-b3xrb2UJ55Jvyg7zR_TcBfbjMHE2yHgdmQVJIoTcEwzhDiWDekOCh5Yj (1207×937)
Then run it.
 ./ballerina run service ./testbal.bal

Now invoke ballerina service as follows.

curl -v -X POST http://127.0.0.1:9090/testService

*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 9090 (#0)
> POST /testService HTTP/1.1
> Host: 127.0.0.1:9090
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Connection: keep-alive
< Content-Length: 49
< Content-Type: application/json
<
* Connection #0 to host 127.0.0.1 left intact
{"code":4,"type":"ok","message":"test-ballerina"}

How to use Ballerina code generator tools to generate connector from swagger definition - BallerinaLang

Download samples and resource required for this project from this location.

Goto ballerina distribution   
/ballerina-0.8.0-SNAPSHOT/bin

Then it will generate connector as well.

Then run following command. For this we need to pass swagger input file to generate swagger.
Sample command
Example commands for connector, skeleton and mock service generation is as follows in order.

ballerina swagger connector /tmp/testSwagger.json -d /tmp  -p wso2.carbon.test

ballerina swagger skeleton /tmp/testSwagger.json -d /tmp  -p wso2.carbon.test

ballerina swagger mock /tmp/testSwagger.json -d /tmp  -p wso2.carbon.test


Command:
>>./ballerina swagger connector /home/sanjeewa/Desktop/student.yaml -p org.wso2 -d ./test


Please use following sample swagger definition for this.

swagger: '2.0'
info:
 version: '1.0.0'
 title: Swagger School (Simple)
 description: A sample API that uses a school as an example to demonstrate features in the swagger-2.0 specification
 termsOfService: http://helloreverb.com/terms/
 contact:
    name: Swagger API team
    email: foo@example.com
    url: http://swagger.io
 license:
    name: MIT
    url: http://opensource.org/licenses/MIT
host: schol.swagger.io
basePath: /api
schemes:
 - http
consumes:
 - application/json
produces:
 - application/json
paths:
 /students:
    get:
     description: Returns all students from the system that the user has access to
     operationId: findstudents
     produces:
       - application/json
       - application/xml
       - text/xml
       - text/html
     parameters:
       - name: limit
         in: query
         description: maximum number of results to return
         required: false
         type: integer
         format: int32
     responses:
       '200':
         description: student response
         schema:
           type: array
           items:
             $ref: '#/definitions/student'
       default:
         description: unexpected error
         schema:
           $ref: '#/definitions/errorModel'
    post:
     description: Creates a new student in the school.  Duplicates are allowed
     operationId: addstudent
     produces:
       - application/json
     parameters:
       - name: student
         in: body
         description: student to add to the school
         required: true
         schema:
           $ref: '#/definitions/newstudent'
     responses:
       '200':
         description: student response
         schema:
           $ref: '#/definitions/student'
       default:
         description: unexpected error
         schema:
           $ref: '#/definitions/errorModel'
 /students/{id}}:
    get:
     description: Returns a user based on a single ID, if the user does not have access to the student
     operationId: findstudentById
     produces:
       - application/json
       - application/xml
       - text/xml
       - text/html
     parameters:
       - name: id
         in: path
         description: ID of student to fetch
         required: true
         type: integer
         format: int64
       - name: ids
         in: query
         description: ID of student to fetch
         required: false
         type: integer
         format: int64
     responses:
       '200':
         description: student response
         schema:
           $ref: '#/definitions/student'
       default:
         description: unexpected error
         schema:
           $ref: '#/definitions/errorModel'
    delete:
     description: deletes a single student based on the ID supplied
     operationId: deletestudent
     parameters:
       - name: id
         in: path
         description: ID of student to delete
         required: true
         type: integer
         format: int64
     responses:
       '204':
         description: student deleted
       default:
         description: unexpected error
         schema:
           $ref: '#/definitions/errorModel'
definitions:
 student:
    type: object
    required:
     - id
     - name
    properties:
     id:
       type: integer
       format: int64
     name:
       type: string
     tag:
       type: string
 newstudent:
    type: object
    required:
     - name
    properties:
     id:
       type: integer
       format: int64
     name:
       type: string
     tag:
       type: string
 errorModel:
    type: object
    required:
     - code
     - textMessage
    properties:
     code:
       type: integer
       format: int32
     textMessage:
       type: string


Then you will see relevant files in output directory.

├── test
  └── org
      └── wso2
          ├── default.bal
          ├── LICENSE
          ├── README.md
          └── types.json


Now copy this connector content to ballerina editor and load it as connector. Please see below image.

import ballerina.lang.messages;
import ballerina.lang.system;
import ballerina.net.http;
import ballerina.lang.jsonutils;
import ballerina.lang.exceptions;
import ballerina.lang.arrays;
connector Default(string text) {
   action Addstudent(string msg, string auth)(message ) {
      http:ClientConnector rmEP = create http:ClientConnector("http://127.0.0.1:8080");
      message request = {};
      message requestH;
      message response;
      requestH = authHeader(request, auth);
      response = http:ClientConnector.post(rmEP, "/students", requestH);
      return response;
     
   }
    action Findstudents(string msg, string auth)(message ) {
      http:ClientConnector rmEP = create http:ClientConnector("http://127.0.0.1:8080");
      message request = {};
      message requestH;
      message response;
      requestH = authHeader(request, auth);
      response = http:ClientConnector.get(rmEP, "/students", requestH);
      return response;
     
   }
   
}

Screenshot from 2017-02-19 22-16-06.png

Then goto editor view and see loaded ballerina connector.

Screenshot from 2017-02-19 22-17-12.png

Then we can see it's loaded as follows.


Now we can start writing our service by using generated connector. We can add following sample service definition which calls connector and get output. Connect your service with generated connector as follows.


@http:BasePath("/connector-test")
service testService {
   
   @http:POST
   @http:Path("/student")
   resource getIssueFromID(message m) {
      StudentConnector studentConnector = create StudentConnector("test");
      message response = {};
      response = studentConnector.Findstudents(studentConnector, "");
      json complexJson = messages:getJsonPayload(response);
      json rootJson = `{"root":"someValue"}`;
      jsonutils:set(rootJson, "$.root", complexJson);
      string tests = jsonutils:toString(rootJson);
      system:println(tests);
      reply response;
     
   }
   
}


Please see how it's loaded in editor.
Screenshot from 2017-02-19 22-24-36.png



Now we need to start back end for generated connector.
Goto student-msf4j-server directory and build it.
/swagger-connector-demo/student-msf4j-server>> mvn clean install

Now you will see micro service jar file generated. Then run MSF4J service using following command.
/swagger-connector-demo/student-msf4j-server>> java -jar target/swagger-jaxrs-server-1.0.0.jar
starting Micro Services
2017-02-19 21:37:44 INFO  MicroservicesRegistry:55 - Added microservice: io.swagger.api.StudentsApi@25f38edc
2017-02-19 21:37:44 INFO  MicroservicesRegistry:55 - Added microservice: org.wso2.msf4j.internal.swagger.SwaggerDefinitionService@17d99928
2017-02-19 21:37:44 INFO  NettyListener:68 - Starting Netty Http Transport Listener
2017-02-19 21:37:44 INFO  NettyListener:110 - Netty Listener starting on port 8080
2017-02-19 21:37:44 INFO  MicroservicesRunner:163 - Microservices server started in 307ms

Now we can check MSF4J service running or not using CuRL as follows.
curl -v http://127.0.0.1:8080/students
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET /students HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Connection: keep-alive
< Content-Length: 41
< Content-Type: application/json
<
* Connection #0 to host 127.0.0.1 left intact
{"code":4,"type":"ok","message":"magic!"}


Now we have MSF4J service for student service up and running. We also have connector pointed to that and service which use that connector. So we can start ballerina service with final ballerina file. Then invoke student service as follows.
curl -v http://127.0.0.1:/connector-test/student

Empowering the Future of API Management: Unveiling the Journey of WSO2 API Platform for Kubernetes (APK) Project and the Anticipated Alpha Release

  Introduction In the ever-evolving realm of API management, our journey embarked on the APK project eight months ago, and now, with great a...