Skip to content

Instantly share code, notes, and snippets.

@bladedancer
Last active December 6, 2018 16:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bladedancer/8064c5a8f23a2064ef82be849607531b to your computer and use it in GitHub Desktop.
Save bladedancer/8064c5a8f23a2064ef82be849607531b to your computer and use it in GitHub Desktop.
API Builder Swagger Plugin Example

Calling Google Cloud Translation service in flow

API Builder is tool that enables developers to rapidly create APIs and microservices with a low-code/no-code approach. API Builder achieves this by enabling you to develop your business logic using Flows. A flow allows you to orchestrate your business logic visually as a graph of connected flow-nodes.

In this post we'll look at one of the default plugins that extends the features available in the flow, the Swagger Plugin. This plugin comes as standard on all API Builder projects. It allows your flow to load an OpenAPI v2/Swagger for a third party service and interact with that service.

For this example we'll create an microservice that integrates with the Google Cloud Translation API.

Enabling access to the Google API

Before starting you will need to configure your Google APIs and enable the Cloud Translation API

Sign in to the Google developer console, and open the Cloud Translation API, https://console.developers.google.com/apis/library/translate.googleapis.com.

Enable the API. If this is your first time using the Google APIs you will need to create a project first.

To access the API from API Builder you need to create a credential.

Click the Create button and for this example we'll create an API Key credential.

Access to your Google API is now configured.

API Builder

The goal here is to create an API for your microservice and implement that API so that it integrates with the Google Cloud Translation API. For this simple example our API will take a string as a parameter and return the French translation of that string.

Creating the API

The first thing to do do is create the API Builder project and a mock of the API.

Create an API Builder project, for more detailed information see the API Builder Getting Started Guide.

npx @axway/api-builder init swagger-demo
cd swagger-demo
npm install --no-optional
npm start

API Builder will now be running and accessible on http://localhost:8080/console.

For this example we will import a very simple API, SwaggerDemoService.json. This API has a single method, Translate, which takes a parameter, text, and returns the translated text.

Open API Doc & Test and click on the +API button. Select the SwaggerDemoService.json and then click Save and mock.

We can look at the automatically generated mock flow, by clicking on the Flow link.

The automatically generated mock flow simply has a static response. We're going to replace this with an integration with the Google Cloud Translation API.

Integrating with Google Cloud Translation API

API Builder's Swagger plugin loads OpenAPI/Swagger 2.0 documents and makes those services available as flow-nodes in the Flow Editor. While Google doesn't provide OpenAPI/Swagger 2.0 documents for its services, they are available from third-party sources. For this example, we obtained the GoogleCloudTranslate.json Swagger from APIs.guru but even if there is none available you can use services like StopLight.io to create bespoke Swagger documents.

Add the connector

First copy the swagger doc for the Google Cloud Translation API GoogleCloudTranslate.json to the swagger folder of your API Builder project. API Builder will brand the nodes in the UI if there is a corresponding image file, so also copy the GoogleCloudTranslate.svg the swagger folder of your API Builder project.

Restart API Builder and open the the Flow Editor at http://localhost:8080/console/project/flows/swaggerDemoService-Translate/edit.

In the Connector section of the Tool panel, there is now a flow-node for Google Cloud Translation.

Building the flow

As mentioned, our Swagger Demo Service has a single method, Translate. For this example we're going to implement that method so that it translates the incoming text parameter to French and returns the result.

For this example the completed is a simple integration with Google Cloud Translation API and will look like this:

The flow is build around the language.translations.list method on the Google Cloud Transloation flow-node. This method does the work of calling https://cloud.google.com/translate/docs/reference/translate.

There inputs to languages.translations.list flow-node are:

Parameter Value Description
q $.params.text This is the text to translate. $.params are the parameters passed to your API. text is the name of the parameter we described in SwaggerDemoService.json.
target fr For this example we will be converting the input text to French.
format text This setting allows you to set whether the string should be HTML encoded or not. For this example we'll just use a plain text response.
Key AIzaSyCVeApzS_dgMqeSlngd3i40kAZR5wp22tg This is the API key you create when adding the credentials on https://console.developers.google.com.

For convenience, update the Default output to be $.error as there are not valid responses expected other than a 200.

In API Builder, the response from a OpenAPI/Swagger 2.0 flow node is wrapped like this:

{
    "statusCode": 200,
    "data": {
        <api response>
    }
}

Looking at Google's documentation for the Translate API we can see the response format will be:

{
   "data": {
       "translations": [
           {
               "detectedSourceLanguage": string,
               "translatedText": string
           }, ...
       ]
   }
}

Combining these, the expected response from calling the language.translations.list method, that is the value that is stored as $.response (which is the output of the flow-node), will be:

{
    "statusCode": 200,
    "data": {
        "data": {
            "translations": [
                {
                    "detectedSourceLanguage": string,
                    "translatedText": string
                }, ...
            ]
        }
    }
}

For this example, we are passing in a single string to translate and so expect a single translation in the response. In our Success HTTP node, rather than return the entire API response, we'll just return the single translation.

Parameter Value Description
status 200 This simple flow only has one outcome - 200.
body $.response.data.data.translations[0] This is the first entry in translations response array, e.g.
{
"detectedSourceLanguage": string,
"translatedText": string
}

Finally, the Error HTTP node handles any error or unexpected response paths..

Parameter Value Description
status 400 Bundling all errors together for this example.
body $.error For this example just returning the error.

Once you completed your flow, you should click Close and then Save and exit to save your flow.

Testing your API

API Builder has a test interface that allows you to invoke the APIs and test that they work. Open the API Doc & Test tab and click on the Swagger Demo Service.

Scrolling down there is a Test API section from which we can invoke the API. In this case the API was invoked with "The monkey is in the tree." The response is the translated text and the detected source language.

{
    "translatedText": "Le singe est dans l'arbre.",
    "detectedSourceLanguage": "en"
}

Summary

Integrating API Builder with a third party service is simply a matter of copying the OpenAPI/Swagger 2.0 document for that service into your project. This gives you the flexibility to integrate with whichever service you need to, without having to sacrifice the low-code/no-code experience API Builder provides.

This simple example showed how to integrate with just one third-party service, however the power of API Builder comes from being able to orchestrate data from multiple REST services, on-premise RDBMS/NoSQL or other custom datasources.

It would be a simple matter to extend this example so that rather than reading text from an input parameter it was instead reading it from a database. You could translate the content on the fly, providing quick and dynamic localization. Then perhaps integrate with Google's Gmail API and deliver the content to a customer via Email.

{
"swagger": "2.0",
"schemes": [
"https"
],
"host": "translation.googleapis.com",
"basePath": "/language/translate",
"info": {
"contact": {
"name": "Google",
"url": "https://google.com"
},
"description": "The Google Cloud Translation API lets websites and programs integrate with\n Google Translate programmatically.",
"title": "Google Cloud Translation",
"version": "v2",
"x-apiClientRegistration": {
"url": "https://console.developers.google.com"
},
"x-apisguru-categories": [
"text"
],
"x-logo": {
"url": "https://cloud.google.com/_static/images/new-gcp-logo.png"
},
"x-origin": [
{
"converter": {
"url": "https://github.com/lucybot/api-spec-converter",
"version": "2.6.2"
},
"format": "google",
"url": "https://translation.googleapis.com/$discovery/rest?version=v2",
"version": "v1"
}
],
"x-preferred": true,
"x-providerName": "googleapis.com",
"x-serviceName": "translate"
},
"externalDocs": {
"url": "https://code.google.com/apis/language/translate/v2/getting_started.html"
},
"securityDefinitions": {
"Oauth2": {
"authorizationUrl": "https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&prompt=consent",
"tokenUrl": "https://accounts.google.com/o/oauth2/token",
"description": "Oauth 2.0 authentication",
"flow": "accessCode",
"scopes": {
"https://www.googleapis.com/auth/cloud-platform": "View and manage your data across Google Cloud Platform services",
"https://www.googleapis.com/auth/cloud-translation": "Translate text from one language to another using Google Translate"
},
"type": "oauth2"
}
},
"parameters": {
"$.xgafv": {
"description": "V1 error format.",
"enum": [
"1",
"2"
],
"in": "query",
"name": "$.xgafv",
"type": "string"
},
"access_token": {
"description": "OAuth access token.",
"in": "query",
"name": "access_token",
"type": "string"
},
"alt": {
"default": "json",
"description": "Data format for response.",
"enum": [
"json",
"media",
"proto"
],
"in": "query",
"name": "alt",
"type": "string"
},
"bearer_token": {
"description": "OAuth bearer token.",
"in": "query",
"name": "bearer_token",
"type": "string"
},
"callback": {
"description": "JSONP",
"in": "query",
"name": "callback",
"type": "string"
},
"fields": {
"description": "Selector specifying which fields to include in a partial response.",
"in": "query",
"name": "fields",
"type": "string"
},
"key": {
"description": "API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token.",
"in": "query",
"name": "key",
"type": "string"
},
"oauth_token": {
"description": "OAuth 2.0 token for the current user.",
"in": "query",
"name": "oauth_token",
"type": "string"
},
"pp": {
"default": true,
"description": "Pretty-print response.",
"in": "query",
"name": "pp",
"type": "boolean"
},
"prettyPrint": {
"default": true,
"description": "Returns response with indentations and line breaks.",
"in": "query",
"name": "prettyPrint",
"type": "boolean"
},
"quotaUser": {
"description": "Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Overrides userIp if both are provided.",
"in": "query",
"name": "quotaUser",
"type": "string"
},
"uploadType": {
"description": "Legacy upload protocol for media (e.g. \"media\", \"multipart\").",
"in": "query",
"name": "uploadType",
"type": "string"
},
"upload_protocol": {
"description": "Upload protocol for media (e.g. \"raw\", \"multipart\").",
"in": "query",
"name": "upload_protocol",
"type": "string"
}
},
"tags": [
{
"name": "detections"
},
{
"name": "languages"
},
{
"name": "translations"
}
],
"paths": {
"/v2": {
"get": {
"description": "Translates input text, returning translated text.",
"operationId": "language.translations.list",
"parameters": [
{
"collectionFormat": "multi",
"description": "The customization id for translate",
"in": "query",
"items": {
"type": "string"
},
"name": "cid",
"type": "array"
},
{
"description": "The format of the source text, in either HTML (default) or plain-text. A\nvalue of \"html\" indicates HTML and a value of \"text\" indicates plain-text.",
"enum": [
"html",
"text"
],
"in": "query",
"name": "format",
"type": "string"
},
{
"description": "The `model` type requested for this translation. Valid values are\nlisted in public documentation.",
"in": "query",
"name": "model",
"type": "string"
},
{
"collectionFormat": "multi",
"description": "The input text to translate. Repeat this parameter to perform translation\noperations on multiple text inputs.",
"in": "query",
"items": {
"type": "string"
},
"name": "q",
"required": true,
"type": "array"
},
{
"description": "The language of the source text, set to one of the language codes listed in\nLanguage Support. If the source language is not specified, the API will\nattempt to identify the source language automatically and return it within\nthe response.",
"in": "query",
"name": "source",
"type": "string"
},
{
"description": "The language to use for translation of the input text, set to one of the\nlanguage codes listed in Language Support.",
"in": "query",
"name": "target",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "Successful response",
"schema": {
"$ref": "#/definitions/TranslationsListResponse"
}
}
},
"security": [
{},
{
"Oauth2": [
"https://www.googleapis.com/auth/cloud-translation"
]
},
{
"Oauth2": [
"https://www.googleapis.com/auth/cloud-platform"
]
}
],
"tags": [
"translations"
]
},
"parameters": [
{
"$ref": "#/parameters/$.xgafv"
},
{
"$ref": "#/parameters/access_token"
},
{
"$ref": "#/parameters/alt"
},
{
"$ref": "#/parameters/bearer_token"
},
{
"$ref": "#/parameters/callback"
},
{
"$ref": "#/parameters/fields"
},
{
"$ref": "#/parameters/key"
},
{
"$ref": "#/parameters/oauth_token"
},
{
"$ref": "#/parameters/pp"
},
{
"$ref": "#/parameters/prettyPrint"
},
{
"$ref": "#/parameters/quotaUser"
},
{
"$ref": "#/parameters/uploadType"
},
{
"$ref": "#/parameters/upload_protocol"
}
],
"post": {
"description": "Translates input text, returning translated text.",
"operationId": "language.translations.translate",
"parameters": [
{
"in": "body",
"name": "body",
"schema": {
"$ref": "#/definitions/TranslateTextRequest"
}
}
],
"responses": {
"200": {
"description": "Successful response",
"schema": {
"$ref": "#/definitions/TranslationsListResponse"
}
}
},
"security": [
{},
{
"Oauth2": [
"https://www.googleapis.com/auth/cloud-translation"
]
},
{
"Oauth2": [
"https://www.googleapis.com/auth/cloud-platform"
]
}
],
"tags": [
"translations"
]
}
},
"/v2/detect": {
"get": {
"description": "Detects the language of text within a request.",
"operationId": "language.detections.list",
"parameters": [
{
"collectionFormat": "multi",
"description": "The input text upon which to perform language detection. Repeat this\nparameter to perform language detection on multiple text inputs.",
"in": "query",
"items": {
"type": "string"
},
"name": "q",
"required": true,
"type": "array"
}
],
"responses": {
"200": {
"description": "Successful response",
"schema": {
"$ref": "#/definitions/DetectionsListResponse"
}
}
},
"security": [
{},
{
"Oauth2": [
"https://www.googleapis.com/auth/cloud-translation"
]
},
{
"Oauth2": [
"https://www.googleapis.com/auth/cloud-platform"
]
}
],
"tags": [
"detections"
]
},
"parameters": [
{
"$ref": "#/parameters/$.xgafv"
},
{
"$ref": "#/parameters/access_token"
},
{
"$ref": "#/parameters/alt"
},
{
"$ref": "#/parameters/bearer_token"
},
{
"$ref": "#/parameters/callback"
},
{
"$ref": "#/parameters/fields"
},
{
"$ref": "#/parameters/key"
},
{
"$ref": "#/parameters/oauth_token"
},
{
"$ref": "#/parameters/pp"
},
{
"$ref": "#/parameters/prettyPrint"
},
{
"$ref": "#/parameters/quotaUser"
},
{
"$ref": "#/parameters/uploadType"
},
{
"$ref": "#/parameters/upload_protocol"
}
],
"post": {
"description": "Detects the language of text within a request.",
"operationId": "language.detections.detect",
"parameters": [
{
"in": "body",
"name": "body",
"schema": {
"$ref": "#/definitions/DetectLanguageRequest"
}
}
],
"responses": {
"200": {
"description": "Successful response",
"schema": {
"$ref": "#/definitions/DetectionsListResponse"
}
}
},
"security": [
{},
{
"Oauth2": [
"https://www.googleapis.com/auth/cloud-translation"
]
},
{
"Oauth2": [
"https://www.googleapis.com/auth/cloud-platform"
]
}
],
"tags": [
"detections"
]
}
},
"/v2/languages": {
"get": {
"description": "Returns a list of supported languages for translation.",
"operationId": "language.languages.list",
"parameters": [
{
"description": "The model type for which supported languages should be returned.",
"in": "query",
"name": "model",
"type": "string"
},
{
"description": "The language to use to return localized, human readable names of supported\nlanguages.",
"in": "query",
"name": "target",
"type": "string"
}
],
"responses": {
"200": {
"description": "Successful response",
"schema": {
"$ref": "#/definitions/LanguagesListResponse"
}
}
},
"security": [
{},
{
"Oauth2": [
"https://www.googleapis.com/auth/cloud-translation"
]
},
{
"Oauth2": [
"https://www.googleapis.com/auth/cloud-platform"
]
}
],
"tags": [
"languages"
]
},
"parameters": [
{
"$ref": "#/parameters/$.xgafv"
},
{
"$ref": "#/parameters/access_token"
},
{
"$ref": "#/parameters/alt"
},
{
"$ref": "#/parameters/bearer_token"
},
{
"$ref": "#/parameters/callback"
},
{
"$ref": "#/parameters/fields"
},
{
"$ref": "#/parameters/key"
},
{
"$ref": "#/parameters/oauth_token"
},
{
"$ref": "#/parameters/pp"
},
{
"$ref": "#/parameters/prettyPrint"
},
{
"$ref": "#/parameters/quotaUser"
},
{
"$ref": "#/parameters/uploadType"
},
{
"$ref": "#/parameters/upload_protocol"
}
]
}
},
"definitions": {
"DetectLanguageRequest": {
"description": "The request message for language detection.",
"properties": {
"q": {
"description": "The input text upon which to perform language detection. Repeat this\nparameter to perform language detection on multiple text inputs.",
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"DetectionsListResponse": {
"properties": {
"detections": {
"description": "A detections contains detection results of several text",
"items": {
"$ref": "#/definitions/DetectionsResource"
},
"type": "array"
}
},
"type": "object"
},
"DetectionsResource": {
"description": "An array of languages which we detect for the given text The most likely language list first.",
"items": {
"properties": {
"confidence": {
"description": "The confidence of the detection result of this language.",
"format": "float",
"type": "number"
},
"isReliable": {
"description": "A boolean to indicate is the language detection result reliable.",
"type": "boolean"
},
"language": {
"description": "The language we detected.",
"type": "string"
}
},
"type": "object"
},
"type": "array"
},
"GetSupportedLanguagesRequest": {
"description": "The request message for discovering supported languages.",
"properties": {
"target": {
"description": "The language to use to return localized, human readable names of supported\nlanguages.",
"type": "string"
}
},
"type": "object"
},
"LanguagesListResponse": {
"properties": {
"languages": {
"description": "List of source/target languages supported by the translation API. If target parameter is unspecified, the list is sorted by the ASCII code point order of the language code. If target parameter is specified, the list is sorted by the collation order of the language name in the target language.",
"items": {
"$ref": "#/definitions/LanguagesResource"
},
"type": "array"
}
},
"type": "object"
},
"LanguagesResource": {
"properties": {
"language": {
"description": "Supported language code, generally consisting of its ISO 639-1\nidentifier. (E.g. 'en', 'ja'). In certain cases, BCP-47 codes including\nlanguage + region identifiers are returned (e.g. 'zh-TW' and 'zh-CH')",
"type": "string"
},
"name": {
"description": "Human readable name of the language localized to the target language.",
"type": "string"
}
},
"type": "object"
},
"TranslateTextRequest": {
"description": "The main translation request message for the Cloud Translation API.",
"properties": {
"format": {
"description": "The format of the source text, in either HTML (default) or plain-text. A\nvalue of \"html\" indicates HTML and a value of \"text\" indicates plain-text.",
"type": "string"
},
"model": {
"description": "The `model` type requested for this translation. Valid values are\nlisted in public documentation.",
"type": "string"
},
"q": {
"description": "The input text to translate. Repeat this parameter to perform translation\noperations on multiple text inputs.",
"items": {
"type": "string"
},
"type": "array"
},
"source": {
"description": "The language of the source text, set to one of the language codes listed in\nLanguage Support. If the source language is not specified, the API will\nattempt to identify the source language automatically and return it within\nthe response.",
"type": "string"
},
"target": {
"description": "The language to use for translation of the input text, set to one of the\nlanguage codes listed in Language Support.",
"type": "string"
}
},
"type": "object"
},
"TranslationsListResponse": {
"description": "The main language translation response message.",
"properties": {
"translations": {
"description": "Translations contains list of translation results of given text",
"items": {
"$ref": "#/definitions/TranslationsResource"
},
"type": "array"
}
},
"type": "object"
},
"TranslationsResource": {
"properties": {
"detectedSourceLanguage": {
"description": "The source language of the initial request, detected automatically, if\nno source language was passed within the initial request. If the\nsource language was passed, auto-detection of the language will not\noccur and this field will be empty.",
"type": "string"
},
"model": {
"description": "The `model` type used for this translation. Valid values are\nlisted in public documentation. Can be different from requested `model`.\nPresent only if specific model type was explicitly requested.",
"type": "string"
},
"translatedText": {
"description": "Text translated into the target language.",
"type": "string"
}
},
"type": "object"
}
}
}
Display the source blob
Display the rendered blob
Raw
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1000 1000" style="enable-background:new 0 0 1000 1000;" xml:space="preserve">
<style type="text/css">
.st0{fill:#D9D9D9;}
.st1{fill:#4352B8;}
.st2{fill:#617D8B;}
.st3{fill:#4F8BF5;}
.st4{fill:#FFFFFF;}
.st5{opacity:0.2;fill:#FFFFFF;}
</style>
<path class="st0" d="M933.6,998.5c36.5,0,66.4-29.4,66.4-65.4V266c0-36-29.9-65.4-66.4-65.4H285.5l260.1,797.9H933.6z"/>
<polygon class="st1" points="716.3,810 546.8,998.5 485.1,810 "/>
<path class="st2" d="M937,477v-39H749v-63h-61v63H568v39h238.8c-12.8,45-41,87.5-68.5,120.5c-48.8-57.7-49-76.5-49-76.5h-50.7
c0,0,2.1,28.1,70.5,108.3C686.9,652,670,665.5,670,665.5l15.6,48.7c0,0,23.5-20.2,53-51.5c29.5,32,67.6,70.5,116.9,116.4l32-32
c-52.8-47.9-91.5-85.9-119.9-116.4c38.1-45.1,76.8-101.8,85-153.8H937z"/>
<path class="st3" d="M68.3,0.2C31.8,0.2,1.9,30.1,1.9,66.7v677c0,36.5,29.9,66.4,66.4,66.4h648.1L456.3,0.2H68.3z"/>
<path class="st4" d="M423.9,377.5h-17.3h-56.8H282v58.8h81.7c-7.6,37.4-39.5,58.8-81.7,58.8c-49.8,0-90-40.2-90-90s40.2-90,90-90
c21.5,0,40.8,7.6,56.1,20.1l44.3-44.3c-27-23.5-61.6-38.1-100.4-38.1c-84.5,0-152.3,67.8-152.3,152.3S197.6,557.5,282,557.5
c76.2,0,145.4-55.4,145.4-152.3C427.4,396.2,426,386.5,423.9,377.5z"/>
<path class="st5" d="M536.2,200.6h397.4c36.5,0,66.4,29.4,66.4,65.4v400.2L536.2,200.6z"/>
</svg>
{
"swagger": "2.0",
"info": {
"title": "Swagger Demo Service",
"description": "API for example project using Swagger Plugin.",
"version": "1.0.0"
},
"paths": {
"/translate": {
"get": {
"description": "Translate the text",
"operationId": "Translate",
"parameters": [
{
"description": "The text to translate.",
"in": "query",
"name": "text",
"required": true,
"type": "string"
}
],
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "greeting",
"schema": {
"type": "object",
"properties": {
"translatedText": { "type": "string" },
"detectedSourceLanguage": { "type": "string" }
}
}
},
"400": {
"description": "Bad Request"
},
"500": {
"description": "Server Error"
}
},
"summary": "Swagger Plugin example using",
"tags": [
"helloworld"
]
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment