A simple understanding of WSO2 Micro Gateway

Lakmini Wathsala
7 min readJun 29, 2020

--

Source: https://www.jrebel.com/blog/performance-problems-with-microservices

WSO2 API Microgateway is a lightweight, developer-centric, simplified version of API gateway. This is ideal as a gateway for microservices. From this blog post, I will provide a basic understanding and approach for the general use cases of the MGW.

There are mainly two components for MGW; toolkit and the gateway runtime. The toolkit is to initialize and build MGW projects. When building the project an executable file will be generated and that file will be the input for the gateway runtime in order to expose the API. The toolkit-config.toml file defines the Microgateway toolkit configurations and is located in the <MGW-TK_HOME>/conf directory. The micro-gw.conf file defines the Microgateway runtime configurations and is located in the <MGW-RUNTIME-HOME>/conf directory.

First of all, we need to install and setup both the toolkit and the gateway runtime. For more information please refer to the documentation [1].

So how can we initialize and build a project with APIs?

We can build a project with an Open API definition, by importing an API or group of APIs from the APIM side.

  1. With an Open API definition
  • To initialize the project:
micro-gw init <Project_Name> -f
Ex: micro-gw init petstore -f
  • Copy the swagger file into the <Project_Name>/api_definitions directory. Please refer to the sample swagger in the documentation [2].
cp petstore_swagger3.yaml petstore/api_definitions/
  • Build the project
micro-gw build <Project_Name>
Ex: micro-gw build petstore

Results:

JAVA_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home
Generating sources…[DONE]
…………………………………………………………………………
There are 3 updates available for the product 'wso2am-micro-gw-toolkit-macos-3.1.0'.
…………………………………………………………………………
Compiling source
wso2/petstore:3.1.0
wso2/jms:0.7.0 [central.ballerina.io -> home repo] [==========>] 4634315/4634315
Creating balos
target/balo/petstore-2019r3-java8–3.1.0.balo
Running tests
wso2/petstore:3.1.0
No tests found
Generating executables
target/bin/petstore.jar
BUILD SUCCESSFUL
Target: /Users/lakmini/Documents/petstore/target/petstore.jar
  • Run the project
wso2am-micro-gw-macos-3.1.0/bin/gateway petstore/target/petstore.jar

Results (server started with default ports 9090 HTTP and 9095 HTTPS):

JAVA_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home
[ballerina/http] started HTTP/WS listener 0.0.0.0:9090
2020–06–15 19:59:36,519 INFO [wso2/gateway] - HTTP listener is active on port 9090
[ballerina/http] started HTTPS/WSS listener 0.0.0.0:9095
2020–06–15 19:59:36,521 INFO [wso2/gateway] - HTTPS listener is active on port 9095
[ballerina/http] started HTTPS/WSS listener 0.0.0.0:9096

2. By importing an API from APIM side

micro-gw init <Project_Name> -f
micro-gw import -a <API_NAme -v <API_version> <Project_Name>
micro-gw build <Project_Name>
Ex:
micro-gw init MyProject -f
micro-gw import -a MyTestAPI -v 1.0 MyProject
micro-gw build MyProject
  • Need to upload the valid certificate (or chain of the certificates) of the backend (if existing) to the truststore of the runtime. Please refer to the documentation [4] for more details. Otherwise, there will be errors like below.
2020–06–17 11:34:07,807 ERROR [wso2/marketing] - Error in client response : error {ballerina/http}SslError message=SSL connection failed:unable to find valid certification path to requested target run.mocky.io/46.252.181.104:443

3. By importing a group of APIs from APIM side

  • Create a label from the APIM side and apply that label for the relevant APIs. Please refer to the documentation [3] for more details.
  • Initiate, import APIs and build the project
micro-gw init <Project_Name> -f
micro-gw import -l <Label_Name> <Project_Name>
micro-gw build <Project_Name>
Ex:
micro-gw init marketing -f
micro-gw import -l MARKETING_STORE marketing
micro-gw build marketing

OK! We build the project. How can we invoke the API?

In order to invoke the API, different security schemes can be used. For example oauth2, API key, JWT, etc. To achieve this purpose, it is needed to update the ‘securitySchemes’ and further update the ‘security’ section of the API resources depending on the requirement like per resource or globally in the API definition file resides under ‘<Project_Name>/gen/api_definitions’ directory after importing the API from APIM side.

Sample configurations:

openapi: 3.0.1
info:
title: Test
version: "1.0"
servers:
- url: /
security:
- default: []

paths:
/*:
get:
responses:
200:
description: OK
security:
- ApiKeyAuth: []

x-auth-type: Application & Application User
x-throttling-tier: Unlimited
x-wso2-application-security:
security-types:
- oauth2
optional: false
put:
responses:
200:
description: OK
security:
- default: []

x-auth-type: Application & Application User
x-throttling-tier: Unlimited
x-wso2-application-security:
security-types:
- oauth2
optional: false
..........components:
securitySchemes:
default:
type: oauth2
flows:
implicit:
authorizationUrl:
https://test.com
ApiKeyAuth: # arbitrary name for the security scheme
type: apiKey
in: header # can be "header" or "query"
name: X-API-KEY # name of the header, query parameter or cookie
appId: # you can define several apikey security schemas
type: apiKey
in: header
name: X-APP-ID
  • Invoke the API with API-Key

If a resource has been configured to use API key as the security schema that resource can be invoked with an API key (GET /* resource as in the above configuration).

TOKEN=$(curl -X get "https://<Hostname>:<Default_9095_port>/apikey" -H "Authorization:Basic <Base64 encoded(username:password)>" -k)curl -X GET "https://<Hostname>:<Default_9095_port>/<base_path_of_the_API>/<Resource_path>" -H "accept: application/xml" -H "api_key:$TOKEN" -kEx: TOKEN=$(curl -X get "https://localhost:9095/apikey" -H "Authorization:Basic YWRtaW46YWRtaW4=" -k)curl -X GET "https://localhost:9095/test/1.0" -H "accept: application/xml" -H "api_key:$TOKEN" -k
  • Invoke the API with oauth2 token

If a resource has been configured to use oauth2 as the security schema that resource can be invoked with an oauth2 token (Let’s say if the above GET /* resource configured for security: — default: [] given that securitySchema section has already configured oauth2 as the default schema).

curl -X GET "https://localhost:9095/test/1.0/*" -H “accept: */*" -H "Authorization: Bearer e27c4a36–8072–3d9c-9b5f-64a9aed08b77" -k

If the configured security schema for the resource and the method used to invoke the API is different, it is not allowed to invoke the API successfully. Sample error:

{"fault":{"code":900917, "message":"Invalid Authentication scheme", "description":"Invalid Authentication scheme. API can not be used with this authentication scheme"}}

Import and invoke API with backend secured basic authentication

Moreover, if it is needed to invoke the API with a basic authenticated backend [5], we have to update the API-definition and start the runtime accordingly.

Sample configuration:

x-wso2-basePath: /testApi/1.0
x-wso2-production-endpoints: "#/x-wso2-endpoints/myEndpoint"
....
x-wso2-endpoints:
- myEndpoint:
urls:
-
http://www.mocky.io/v2/5cfe1b5f320000650045ee70
securityConfig:
type: basic
username: admin

When starting the runtime, it is needed to pass the password value as it is not configured in the API-definition due to security concerns.

wso2am-micro-gw-macos-3.1.0/bin/gateway <Pathe_to_the_executable_file> — <Endpoint_Name>_<Endpoint_Type>_<securityConfig_Type>_password=<Password>Ex: wso2am-micro-gw-macos-3.1.0/bin/gateway MyProject/target/MyProject.jar - myEndpoint_prod_basic_password=admin
  • Enabling Debug logs and Trace logs for troubleshooting purposes:
  • Debug logs
wso2am-micro-gw-macos-3.1.0/bin/gateway petstore/target/petstore.jar — b7a.log.level=DEBUG

Results:

JAVA_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home
2020–06–15 20:46:14,031 DEBUG [ballerina/http/caching] - Created HTTP caching client: object http:HttpCachingClient
2020–06–15 20:46:14,039 DEBUG [ballerina/http/caching] - Created HTTP caching client: object http:HttpCachingClient
2020–06–15 20:46:14,042 DEBUG [ballerina/http/caching] - Created HTTP caching client: object http:HttpCachingClient
  • Trace logs
wso2am-micro-gw-macos-3.1.0/bin/gateway petstore/target/petstore.jar - b7a.http.tracelog.console=true

Results:

JAVA_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home
ballerina: HTTP trace log enabled
[ballerina/http] started HTTP/WS listener 0.0.0.0:9090
2020–06–15 20:46:31,080 INFO [wso2/gateway] - HTTP listener is active on port 9090
[ballerina/http] started HTTPS/WSS listener 0.0.0.0:9095
2020–06–15 20:46:31,082 INFO [wso2/gateway] - HTTPS listener is active on port 9095
[ballerina/http] started HTTPS/WSS listener 0.0.0.0:9096
[2020–06–15 20:46:42,575] TRACE {http.tracelog.downstream} - [id: 0xd2c05b02, L:/127.0.0.1:9095 - R:/127.0.0.1:63431] OUTBOUND SETTINGS: ack=false settings={MAX_HEADER_LIST_SIZE=8192}
[2020–06–15 20:46:42,581] TRACE {http.tracelog.downstream} - [id: 0xd2c05b02, L:/127.0.0.1:9095 - R:/127.0.0.1:63431] INBOUND SETTINGS: ack=false settings={ENABLE_PUSH=0, MAX_CONCURRENT_STREAMS=100, INITIAL_WINDOW_SIZE=1073741824}
[2020–06–15 20:46:42,583] TRACE {http.tracelog.downstream} - [id: 0xd2c05b02, L:/127.0.0.1:9095 - R:/127.0.0.1:63431] OUTBOUND SETTINGS: ack=true
[2020–06–15 20:46:42,584] TRACE {http.tracelog.downstream} - [id: 0xd2c05b02, L:/127.0.0.1:9095 - R:/127.0.0.1:63431] INBOUND WINDOW_UPDATE: streamId=0 windowSizeIncrement=1073676289
[2020–06–15 20:46:42,589] TRACE {http.tracelog.downstream} - [id: 0xd2c05b02, L:/127.0.0.1:9095 - R:/127.0.0.1:63431] INBOUND HEADERS: streamId=1 headers=DefaultHttp2Headers[:method: GET, :path: /petstore/v1/pet/1, :scheme: https, :authority: localhost:9095, user-agent: curl/7.54.0, accept: application/xml, api_key: eyJhbGciOiJSUzI1NiIsICJ0eXAiOiJqd3QiLCAia2lkIjoiYmFsbGVyaW5hIn0.eyJzdWIiOiJhZG1pbiIsICJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo5MDk1L2FwaWtleSIsICJpYXQiOjE1OTIyMzE1ODUsICJqdGkiOiJiMWI3MTMyNy0zZmViLTRjODgtYTE5My05ZTJiZjVkZjQ5NzkiLCAia2V5dHlwZSI6IlBST0RVQ1RJT04iLCAiYWxsb3dlZEFQSXMiOltdfQ.EG7vi9a_fygV_EFBgZazvq1NitxZIRJ_WnM0Vc-9g7285C5On1rMqgMeTm_qS_nYNRIma1yhCqGzRGvUJNJXwtQlXhcg4EyUlsljrTXe6FK8jjqru4c7T3-ilObVtUGBotqirAvpMaqUXI-YFB4gFNdNW-iYj2zFUw-ChMGPVIETQ1Yi8p9uiPr23wykx54bU-dkPVaz6jZUUuZmX9dy0sOoEj5AjDyzLZBGVjUrSqZX2WfVr1b3jnjA-ZU4QPYJCDnEGuRdprs-yjsTTyP9NGe9l6ft8gK0y_CVSNsQeuBZhAGEWySz3D16X4XbPmWplV5w0Yxw4rnskDNLXxlOrw] padding=0 endStream=true
[2020–06–15 20:46:42,625] TRACE {http.tracelog.downstream} - [id: 0xd2c05b02, L:/127.0.0.1:9095 - R:/127.0.0.1:63431] INBOUND SETTINGS: ack=true
[2020–06–15 20:46:44,028] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: n/a, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] DEREGISTER
[2020–06–15 20:46:44,031] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: n/a, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] USER_EVENT: SslHandshakeCompletionEvent(SUCCESS)
[2020–06–15 20:46:44,032] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: n/a, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] READ COMPLETE
[2020–06–15 20:46:44,033] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: n/a, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] UNREGISTERED
[2020–06–15 20:46:44,033] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0] REGISTERED
[2020–06–15 20:46:44,042] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: 0xd2c05b02, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] OUTBOUND: DefaultHttpRequest(decodeResult: success, version: HTTP/1.1)
GET /v2/pet/1 HTTP/1.1
accept: application/xml
api_key: eyJhbGciOiJSUzI1NiIsICJ0eXAiOiJqd3QiLCAia2lkIjoiYmFsbGVyaW5hIn0.eyJzdWIiOiJhZG1pbiIsICJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo5MDk1L2FwaWtleSIsICJpYXQiOjE1OTIyMzE1ODUsICJqdGkiOiJiMWI3MTMyNy0zZmViLTRjODgtYTE5My05ZTJiZjVkZjQ5NzkiLCAia2V5dHlwZSI6IlBST0RVQ1RJT04iLCAiYWxsb3dlZEFQSXMiOltdfQ.EG7vi9a_fygV_EFBgZazvq1NitxZIRJ_WnM0Vc-9g7285C5On1rMqgMeTm_qS_nYNRIma1yhCqGzRGvUJNJXwtQlXhcg4EyUlsljrTXe6FK8jjqru4c7T3-ilObVtUGBotqirAvpMaqUXI-YFB4gFNdNW-iYj2zFUw-ChMGPVIETQ1Yi8p9uiPr23wykx54bU-dkPVaz6jZUUuZmX9dy0sOoEj5AjDyzLZBGVjUrSqZX2WfVr1b3jnjA-ZU4QPYJCDnEGuRdprs-yjsTTyP9NGe9l6ft8gK0y_CVSNsQeuBZhAGEWySz3D16X4XbPmWplV5w0Yxw4rnskDNLXxlOrw
x-http2-stream-id: 1
host: petstore.swagger.io
user-agent: ballerina
connection: keep-alive
[2020–06–15 20:46:44,046] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: 0xd2c05b02, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] OUTBOUND: DefaultLastHttpContent(data: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 0), decoderResult: success), 0B
[2020–06–15 20:46:44,046] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: 0xd2c05b02, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] FLUSH
[2020–06–15 20:46:44,331] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: 0xd2c05b02, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] INBOUND: DefaultHttpResponse(decodeResult: success, version: HTTP/1.1)
HTTP/1.1 200 OK
Access-Control-Allow-Headers: Content-Type, api_key, Authorization
Access-Control-Allow-Methods: GET, POST, DELETE, PUT
Access-Control-Allow-Origin: *
Content-Type: application/xml
Date: Mon, 15 Jun 2020 15:16:44 GMT
Server: Jetty(9.2.9.v20150224)
transfer-encoding: chunked
Connection: keep-alive
[2020–06–15 20:46:44,333] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: 0xd2c05b02, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] INBOUND: DefaultHttpContent(data: PooledSlicedByteBuf(ridx: 0, widx: 274, cap: 274/274, unwrapped: PooledUnsafeDirectByteBuf(ridx: 606, widx: 611, cap: 669)), decoderResult: success), 274B
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Pet><category><id>1</id><name>string</name></category><id>1</id><name>doggie</name><photoUrls><photoUrl>string</photoUrl></photoUrls><status>available</status><tags><tag><id>1</id><name>string</name></tag></tags></Pet>
[2020–06–15 20:46:44,335] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: 0xd2c05b02, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] INBOUND: EmptyLastHttpContent, 0B
[2020–06–15 20:46:44,336] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: 0xd2c05b02, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] READ COMPLETE
[2020–06–15 20:46:44,342] TRACE {http.tracelog.downstream} - [id: 0xd2c05b02, L:/127.0.0.1:9095 - R:/127.0.0.1:63431] OUTBOUND HEADERS: streamId=1 headers=DefaultHttp2Headers[:status: 200, access-control-allow-headers: Content-Type, api_key, Authorization, access-control-allow-methods: GET, POST, DELETE, PUT, access-control-allow-origin: *, content-type: application/xml, date: Mon, 15 Jun 2020 15:16:44 GMT, server: Jetty(9.2.9.v20150224)] streamDependency=0 weight=16 exclusive=false padding=0 endStream=false
[2020–06–15 20:46:44,346] TRACE {http.tracelog.downstream} - [id: 0xd2c05b02, L:/127.0.0.1:9095 - R:/127.0.0.1:63431] OUTBOUND DATA: streamId=1 padding=0 endStream=false length=274 data=274B
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Pet><category><id>1</id><name>string</name></category><id>1</id><name>doggie</name><photoUrls><photoUrl>string</photoUrl></photoUrls><status>available</status><tags><tag><id>1</id><name>string</name></tag></tags></Pet>
[2020–06–15 20:46:44,347] TRACE {http.tracelog.downstream} - [id: 0xd2c05b02, L:/127.0.0.1:9095 - R:/127.0.0.1:63431] OUTBOUND DATA: streamId=1 padding=0 endStream=true length=0 data= 0B
[2020–06–15 20:47:44,578] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: 0xd2c05b02, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] USER_EVENT: SslCloseCompletionEvent(SUCCESS)
[2020–06–15 20:47:44,579] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: 0xd2c05b02, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] READ COMPLETE
[2020–06–15 20:47:44,836] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: 0xd2c05b02, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] READ COMPLETE
[2020–06–15 20:47:44,836] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: 0xd2c05b02, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] INACTIVE
[2020–06–15 20:47:44,837] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: 0xd2c05b02, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] CLOSE
[2020–06–15 20:47:44,838] TRACE {http.tracelog.upstream} - [id: 0x32fc79c0, correlatedSource: 0xd2c05b02, host:/192.168.8.100:63432 - remote:petstore.swagger.io/54.165.222.185:443] UNREGISTERED

Hope you find the blog post useful! As you are now own the basic understanding now you can look into the MGW deeply!!

References:

[1] https://docs.wso2.com/display/MG310/Install+and+Setup

[2] https://github.com/wso2/product-microgateway/blob/master/samples/petstore_swagger3.yaml

[3] https://apim.docs.wso2.com/en/latest/learn/api-microgateway/grouping-apis-with-labels/

[4] https://docs.wso2.com/display/MG310/Importing+Certificates+to+the+API+Microgateway+Truststore

[5] https://apim.docs.wso2.com/en/latest/learn/design-api/endpoints/endpoint-security/basic-auth/#secure-endpoint-with-basic-auth

[6] https://docs.wso2.com/display/MG310/Troubleshooting

[7] https://docs.wso2.com/display/MG310/FAQs

--

--