25 Days of Serverless – Day 5

The challenge for day 5 was to use sentiment analysis to provide feedback on the contents of letters to Santa – and I set about creating an Azure function in TypeScript/NodeJS. There’s a client library for NodeJS and a quickstart document to go along with it – I ran into issues working with the client library and under a short timeline I switched over to working with the REST API for language detection. Fundamentally, this is the strength of REST APIs. Their universal nature leads them to be more reliable and accessible for developers across a broad range of toolsets.

Fortunately, I was able to get the client library for NodeJS working for language detection when I went back to reproduce the error message so we’re able to see a contract of the REST API implementation and the client library.

After you’ve created your free tier Cognitive services text analytics service in Azure you are presented with a key and an endpoint. That key is really important as you can take it right over to the web console and start testing out the REST API: https://go.microsoft.com/fwlink/?linkid=848379

The Workaround

I was hitting an error with the language detection function and the client library – the language detection service is working great in the web console. The sentiment detection worked immediately from the client library without too much trouble and with a time limit I wanted to move to a different solution structure. Handling HTTP requests in NodeJS can be accomplished succinctly with 2 packages:

npm install request
npm install request-promise-native

By adding the packages request and request-promise-native to our function, we are able to quickly convert the language detection function from using the client library to using the REST API directly. The language_endpoint parameter is our general endpoint ( https://25daysofserverlessday5.cognitiveservices.azure.com ) with “/text/analytics/v2.1/languages” appended.

async function languageDetection(language_endpoint: string, subscription_key: string, document: string):Promise<string> {
    let documentInput = { "documents" : [ { id: "1", text: document } ]};

    var options = {
        uri: language_endpoint,
        headers: {
            'Ocp-Apim-Subscription-Key': subscription_key,
            'Content-Type': 'application/json'
        },
        body: documentInput,
        json: true,
        simple: false
    };
    var languageResult = await rpn.post(options);

    return languageResult.documents[0].detectedLanguages[0].iso6391Name;
}

Working with Client Library

To be honest, I can’t figure out what I had broken before – but it was late at night. I have a hunch that it might be related to installing request into the project, but that’s pure speculation. (hey, I’m a manager, all I do is speculate)

Here’s the language detection function leveraging the NodeJS client for text analytics:

async function languageDetectionClient(client: TextAnalyticsAPIClient.TextAnalyticsClient, document: string): Promise<string> {
    const languageInput = {
        documents: [
            { id: "1", text: document }
        ]
    };

    const languageResult = await client.detectLanguage({
        languageBatchInput: languageInput
    });

    return languageResult.documents[0].detectedLanguages[0].iso6391Name;
}

I Love Types and Classes

The more I work with TypeScript – and occasionally look at JavaScript – I become more reliant and interested in strongly typed code.

In this example, I created a LetterToSanta object where I could handle the attributes. I find structures like these key to long-term project success.

class LetterToSanta {
    public who: string;
    public message: string;
    public language: string;
    public sentiment: number;
constructor(newWho: string, newMessage: string) {
    this.who = newWho;
    this.message = newMessage;
}

}

Imagine a scenario where Santa needs to scale his operation and the Elf CTO sells him on key phrase extraction of the letters to build the gift list. That would be able to tie right into our LetterToSanta class.

class LetterToSanta {
    public who: string;
    public message: string;
    public language: string;
    public sentiment: number;
    public giftList: [string];
constructor(newWho: string, newMessage: string) {
    this.who = newWho;
    this.message = newMessage;
}

}

… and I just realized I might be the Elf CTO.

Resulting Function

Can be found here: https://github.com/dzsquared/25-days-of-serverless-day5