Deploying Resources
The translation service demonstrated here will require the following resources:
- A function to handle requests, business logic, and communication with the Google Translation API
- At least one environmental variable to handle the private Google API key
- A public HTTP route with a schema for extensibility and documentation
- A table to store translations in a cache to avoid re-invoking Google's metered API
Create a tableβ
Start by opening the Create dialog at the bottom of the left-hand drawer.
Columnsβ
The cache table will be called translation_cache. It will have a simple structure of four columns.
english
β the original text to be translated to a different language- This is the key that will be used to cache for
result
βΒ the resulting translationresult_lang
Β β the language code that the original text was translated to- "es" is the language code for Spanish
created_at
β when was this row inserted, useful for TTL
After clicking Next, the new table will be visible.
Cache exampleβ
Initially, the table will not have any rows. For the sake of an example, here's a preview of what a cache value will look like:
tip
Expand that + speed dial in the top-left of the table to access the Add row button, along with other power functionality.
Create a functionβ
This new function will be called google-translator. The Hello World template is used as a boilerplate because it's the most basic Node environment.
Function parametersβ
Let this new function stack deploy to AWS. Easybase invokes the function that is specified as the default export [as seen in the screenshot below]. This default function provides four parameters, but only two that are essential for this use case:
event
βΒ the AWS API Gateway event. This is essential to capture a request's body and parameters.sql
βΒ An authenticated Postgres instance to the database of your currently selected workspace.
The value that is returned from the exported function is what is sent to the client. This value can be a string, object, array, etc.
info
The first deployment of a new function takes a few minutes, but subsequent deployments will be much faster (<1 minute).
Dependenciesβ
To install dependencies from npm, add a package [and the corresponding version] to package.json
. In this case, a package will be needed called translate
. This will help with communicating with the Google Translate API.
Now that dependencies can now be imported with var translate = require('translate')
in src/handler.js
.
Request body and parametersβ
The first step in the business logic of the translation service is to collect an English string parameter. Since this function will handle POST requests, the event.body
will contain the post data.
In this case, the body attribute to read is english
. This variable will contain the string to translate.
info
event.body
is a string by default, so use JSON.parse
to turn it into a Javascript object.
tip
In a GET request, the query string can be read via event.queryStringParameters
.
Clear the handler functionality and read english
like so:
var translate = require('translate');
module.exports = async (event, sql, next, link) => {
const postBody = JSON.parse(event.body);
const english = postBody.english;
// ...
}
Check cacheβ
Before the Google Translation API is invoked, the cache table is should be checked to make sure the same query has not been computed before.
Here, the sql
parameter is used to select any rows with the provided english
attribute in the translation_cache
table.
var translate = require('translate');
module.exports = async (event, sql, next, link) => {
const postBody = JSON.parse(event.body);
const english = postBody.english;
const cache = await sql`SELECT * FROM translation_cache WHERE english = ${english} LIMIT 1`;
if (cache.length > 0) {
// The cache exists
return cache[0].result;
}
// ...
}
Translateβ
If no cached value exists, the function invokes the Google Translation API via translate
.
That value is returned to the client, after caching it to the translation_cache
table.
var translate = require('translate');
module.exports = async (event, sql, next, link) => {
const postBody = JSON.parse(event.body);
const english = postBody.english;
const cache = await sql`SELECT * FROM translation_cache WHERE english = ${english} LIMIT 1`;
if (cache.length > 0) {
// The cache exists
return cache[0].result;
}
const resultLang = "es";
if (english) {
translate.engine = "google";
translate.key = process.env.GOOGLE_API_KEY; // Set in next step...
const spanishText = await translate(postBody.english, resultLang);
await sql`INSERT INTO translation_cache ${
sql({
english,
result: spanishText,
result_lang: resultLang,
created_at: new Date()
})
}`;
return spanishText;
} else {
return "Missing english body parameter..."
}
}
note
The translate
library requires a Google API Key. In this code snippet, that key is accessible via process.env.GOOGLE_API_KEY
. Setting this environmental variable is very easy and is demonstrated in the next step.
Re-deploy this function with the blue Save button in the top-right.
Environmental variablesβ
All that's left to do is declare the GOOGLE_API_KEY
environmental variable. This is done by expanding the Function drawer and heading to the Variables tab.
note
To get a valid Google Translation API key, log in to Google Cloud and head to APIs & Service, then search for Translation.
Save that and after the re-deployment finishes head to the Test tab.
info
Environmental variables are very important. Two particular reasons are that...
- They can hide sensitive keys, passwords, and phrases while allowing others to pass in their own credentials via Microstack.
- They allow for customization of the functionality.
- Feature flagging
- A/B testing
- User-determined variables
Testingβ
API resultβ
In that Function drawer, head to the test Test and change the request type from GET to POST.
Add the attribute english
to the post body with the value of some English string.
Finally, click Send to invoke the function straight from the browser.
Just like that, the Response area will deliver the translated string!
Cache resultβ
Here's that result cached in the translation_cache
table.
Running the same input of "Hello world." will be much snappier the second time around. This is because the function is using the cached value, rather than re-invoking the Google Translation API.
Endpoint and languagesβ
To find the public API endpoint for a function, click the Deploy tab in the Function drawer.
It is in the view that you can also find some examples of how to invoke your function in various programming languages.
Schemaβ
In the left-hand drawer, click the button titled Schemas. This page provides a high-level overview of the available API routes in the currently selected workspace, along with the corresponding schemas for each API.
Schemas keep your function inputs/outputs organized and documented and can be packaged with your Microstacks so that others know how to properly use the API routes.
Now that all the resources have been created, all that's left to do is package them into a Microstack on the next page.