Shahul Basha
From the archive · 2020

Serverless: AWS Lambda and Spring Cloud Function with the Twitter API

Write a Spring Cloud Function that updates a Twitter profile name with the live follower count, package it, and run it on AWS Lambda.

  • 6 min read
  • AWS Lambda, Spring Cloud, Serverless

Archive note I wrote this in 2020 on my old blog. It moved here in 2026 with the code and diagrams redone; library versions and APIs may have changed since. Original post.

Contents

In this article we’ll build a simple AWS Lambda function with Spring Cloud Function that updates a Twitter profile name automatically. We’ll cover:

  • the Twitter API,
  • Spring Cloud Function with Spring Boot, and
  • deploying it as a serverless AWS Lambda function.

The Twitter API

Twitter’s API is one of the most popular around: you can search tweets, pull data and analyse trends for a location, among other things. To use it, go to developer.twitter.com/apps and create an app, describing what it’s for. You’ll get four keys: an API key, an API secret key, an access token and an access token secret.

To keep things simple, our function will update my Twitter profile name, appending the account’s current follower count:

The profile name before and after the function runs.

Spring Cloud Function

Spring Cloud Function is a project that promotes writing business logic as plain functions. The same code can then run as a web endpoint, a stream processor or a task, and it works well with serverless platforms. A traditional Spring Boot REST API runs in an embedded server on a port; a Spring Cloud Function isn’t tied to any server, so a platform such as AWS Lambda can run it on demand.

Create a Spring Boot starter project and add these dependencies. We’ll use the Twitter4J client to talk to the Twitter API.

pom.xmlXML
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.twitter4j</groupId>
    <artifactId>twitter4j-core</artifactId>
    <version>4.0.7</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-function-adapter-aws</artifactId>
</dependency>
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-lambda-java-events</artifactId>
    <version>2.0.2</version>
</dependency>
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-lambda-java-core</artifactId>
    <version>1.1.0</version>
</dependency>

This doesn’t include an embedded server for testing locally. If you want to run the application on a port and test it, add this dependency too:

pom.xml (optional, for local testing)XML
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-function-web</artifactId>
</dependency>

Next, we create a Twitter client with the keys we got earlier. The keys live in a properties file and are injected. Don’t publish these keys anywhere, or your Twitter account is a goner.

TwitterConfig.javaJava
@Component
public class TwitterConfig {
    @Autowired
    private Environment env;

    public Twitter getTwitterInstance() {
        ConfigurationBuilder cb = new ConfigurationBuilder();
        cb.setDebugEnabled(true)
          .setOAuthConsumerKey(env.getProperty("twitter.api.key"))
          .setOAuthConsumerSecret(env.getProperty("twitter.api.secret"))
          .setOAuthAccessToken(env.getProperty("twitter.api.accessToken"))
          .setOAuthAccessTokenSecret(env.getProperty("twitter.api.accessSecret"));
        TwitterFactory tf = new TwitterFactory(cb.build());
        return tf.getInstance();
    }
}

Next, the service that updates the profile name. It appends the current follower count to the existing name, and returns the new name.

TwitterService.javaJava
@Service
public class TwitterService {

    @Autowired
    TwitterConfig twitterConfig;

    public String updateUsername() {
        Twitter twitter = twitterConfig.getTwitterInstance();
        User user;
        try {
            user = twitter.showUser(twitter.getId());
            User updatedProfile = twitter.updateProfile(
                    user.getName() + " | " + user.getFollowersCount(), null, null, null);
            return updatedProfile.getName();
        } catch (TwitterException e) {}
        return null;
    }
}

Because it appends to the current name, running it twice gives “Shahul | 694 | 695”. To run it on a schedule, strip any old count first. It’s also worth logging the TwitterException rather than swallowing it.

All that’s left is to expose the service. Normally a controller would do that. In Spring Cloud Function, we expose it as a bean of one of Java’s functional interfaces: Supplier, Function or Consumer. Custom functional interfaces need a wrapper, which is beyond the scope of this article.

Here we return a Supplier<String> that supplies the updated profile name. When the web starter is on the classpath, Spring Cloud Function also exposes it as a REST endpoint at /username.

SpringCloudAwsLambdaApplication.javaJava
@SpringBootApplication
public class SpringCloudAwsLambdaApplication {

    @Autowired
    TwitterService service;

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudAwsLambdaApplication.class, args);
    }

    @Bean
    public Supplier<String> username() {
        return () -> service.updateUsername();
    }
}

Finally, to deploy to AWS Lambda we need a handler class, so that Lambda knows how to invoke the application and what the function’s input and output types are. We extend SpringBootRequestHandler with String for both, because the function returns a String. It takes no input in this case, but the input type still has to be declared.

TwitterHandler.javaJava
public class TwitterHandler extends SpringBootRequestHandler<String, String> {}

Here’s how the pieces fit together when Lambda runs the function:

From Lambda invocation to Twitter API call.

Run a Maven build to create the jar we’ll upload.

Serverless with AWS Lambda

Serverless doesn’t mean there’s no server. It means you, the developer, don’t have to set one up or look after it. You write the business logic, as we’ve done, and hand it to a serverless provider to run.

The main advantages:

  • no servers to manage, and
  • you pay only for the time your function runs.

AWS Lambda is Amazon’s service for running and managing serverless functions.

Step 1: create the function

Sign in to the AWS console (you’ll need an account with a credit card on file), search for Lambda, and choose Create function. Pick Author from scratch and fill in:

SettingValue
Function nameTwitterUpdate
RuntimeJava 8 (in 2020; use Java 21 today)
Permissionsthe default execution role, which can write logs to CloudWatch

You could equally upload a Node.js or Python function here. Choose Create function.

Step 2: point Lambda at the handler

Under Edit basic settings, set:

SettingValue
Handlercom.shahul.serverless.TwitterHandler
Memory512 MB
Timeout30 seconds

and save.

Step 3: upload the jar

In the Function code section, choose Actions → Upload a .zip or .jar file, and upload the jar from the Maven build.

Step 4: configure a test event

Next to the Test button, configure a test event. If the function took input, this is where you’d provide it. Ours doesn’t, so the event is just an empty string:

Test event: TwitterTestJSON
""

Step 5: run it

Choose Test. The execution succeeds, the function returns the new profile name, and the Twitter profile updates:

Execution result: succeededOutput
"Shahul | 694"
DurationBilled durationMemory configuredMax memory usedInit duration
15,492.56 ms15,500 ms512 MB162 MB470.11 ms
Log output (start)Output
START RequestId: dc43e665-3d68-4496-9c6b-638c5f258fc3 Version: $LATEST
07:34:15.582 [main] INFO org.springframework.cloud.function.context.AbstractSpringFunctionAdapterInitializer - Initializing: class com.shahul.serverless.SpringCloudAwsLambdaApplication

Most of those 15 seconds are cold-start work. As the log shows, the adapter builds the whole Spring application context inside the first invocation, on the modest CPU share a 512 MB function gets, and only then calls Twitter. Later invocations of a warm function reuse the context and are much faster.

That’s it: our first serverless AWS Lambda function with Spring Cloud Function.

Improving the function

  1. Call it from outside. Put Amazon API Gateway in front of the function so it can be called as a REST API. Be careful: some of these services are billed.
  2. Run it on a schedule. Trigger the function every 30 minutes with an Amazon EventBridge schedule (a cron job), so the follower count on the profile stays up to date. You could also change the profile picture every day of the week, as a fun experiment. The possibilities are endless, and there’s plenty of data analysis you could do too.

Conclusion

This is a getting-started guide, and there’s a lot more to explore.

The project is on GitHub: shahulbasha/serverlessawslambda.

← All writing