Developing applications with Momento SDKs
Welcome! This page provides information about common constructs you will need in order to assemble Momento clients in all of our SDKs. This page covers how to provide your Momento credentials (called auth tokens), how to configure your client, and some basic information about error handling and production readiness.
Constructing a Cache Client
The CacheClient
is the main object you will use in your code to interact with Momento services. To instantiate one, you need to pass a CredentialProvider
, a Configuration
, and a default time to live (TTL) value. The default TTL determines how long items using that CacheClient
will be stored in the cache before the cache deletes them. When performing Set
operations, you can override this TTL value unique to that operation. See Expire data with Time-to-Live (TTL) in Momento Cache for more information.
Here is an example of how to construct a CacheClient
:
- JavaScript
- Python
- Java
- Go
- PHP
new CacheClient({
configuration: Configurations.Laptop.v1(),
credentialProvider: CredentialProvider.fromEnvironmentVariable({
environmentVariableName: 'MOMENTO_AUTH_TOKEN',
}),
defaultTtlSeconds: 60,
});
CacheClientAsync(
Configurations.Laptop.latest(),
CredentialProvider.from_environment_variable("MOMENTO_AUTH_TOKEN"),
timedelta(seconds=60)
)
try (CacheClient cacheClient =
CacheClient.builder(
CredentialProvider.fromEnvVar("MOMENTO_AUTH_TOKEN"),
Configurations.Laptop.v1(),
Duration.ofSeconds(60))
.build()) {
// ...
}
context := context.Background()
configuration := config.LaptopLatestWithLogger(logger.NewNoopMomentoLoggerFactory()).WithClientTimeout(15 * time.Second)
credentialProvider, err := auth.NewEnvMomentoTokenProvider("MOMENTO_AUTH_TOKEN")
if err != nil {
panic(err)
}
defaultTtl := time.Duration(9999)
client, err := momento.NewCacheClient(configuration, credentialProvider, defaultTtl)
if err != nil {
panic(err)
}
client.Ping(context)
new CacheClient(
Laptop::latest(),
CredentialProvider::fromEnvironmentVariable("MOMENTO_AUTH_TOKEN"),
60
);
Instantiating credential providers using Momento auth tokens
You need to provide a Momento auth token when instantiating a Momento client. If you don't have one yet, you can get one from the Momento Web Console. Once you have a token, provide it to Momento SDKs when you create an instance of CredentialProvider
. There are convenient factory methods provided to construct a CredentialProvider
object, either from an environment variable or from a String. Below is an example of how to instantiate CredentialProvider
from an environment variable:
- JavaScript
- Python
- Java
- PHP
CredentialProvider.fromEnvironmentVariable({environmentVariableName: 'MOMENTO_AUTH_TOKEN'});
CredentialProvider.from_environment_variable("MOMENTO_AUTH_TOKEN")
CredentialProvider.fromEnvVar("MOMENTO_AUTH_TOKEN");
CredentialProvider::fromEnvironmentVariable("MOMENTO_AUTH_TOKEN");
If you're storing your Momento auth token in a secret manager such as AWS Secret Manager, GCP Secret Manager, or a local config file, you must first retrieve the credentials from there and then instantiate a CredentialProvider
from a string, like this:
- JavaScript
- Java
const authToken = retrieveAuthTokenFromYourSecretsManager();
CredentialProvider.fromString({authToken: authToken});
final String authToken = retrieveAuthTokenFromYourSecretsManager();
CredentialProvider.fromString(authToken);
For an example of how to retrieve credentials from AWS Secrets Manager, see Retrieving a Momento auth token from AWS Secrets Manager.
For general information on creating and refreshing Momento auth tokens, see Momento authentication with expiring tokens.
Client configuration objects
Configuration
objects contain the settings necessary for how a Momento client should connect to Momento services. The Configuration
object controls settings such as timeouts, retries, logging, middleware, and more.
Each SDK contains pre-built Configuration
objects to help get you up and running as quickly as possible. We did the hard work of tuning for various deployment environments so you can focus on the things unique to your business. (We even have a blog series about it! Shockingly simple: Cache clients that do the hard work for you)
Pre-built configurations come with a latest()
version, which will always give you the latest recommended configuration for a given environment. For example,
- JavaScript
Configurations.InRegion.Default.latest();
The latest()
pre-built configuration may change between SDK releases as we continue to test, tune, and deliver better settings. If you would like to ensure your configuration does not change with an SDK upgrade, we provide fixed versions such as v1()
, which are guaranteed to remain static from one release to the next. For example,
- JavaScript
Configurations.InRegion.Default.v1();
If you need a custom configuration, you can build your own Configuration
object. See the examples in the Configurations
namespace in the source code of each SDK to see how they are constructed.
We hope these configurations will meet the needs of most use cases, but if you find them lacking in any way, please open a GitHub issue on that SDK repo, or contact us at support@momentohq.com
. We would love to hear about your use case so we can fix or extend the pre-built configurations to better support you.
Here are some of the pre-built configurations that you might be interested in.
Laptop
Configurations.Laptop
is a development environment, just for poking around on your... laptop :) It has relaxed timeouts and assumes your network latencies might be a bit high.
- JavaScript
- Java
Configurations.Laptop.v1();
Configurations.Laptop.v1();
Browser
Configurations.Browser
is a configuration unique to our web SDK. It has relaxed timeout settings since latencies can be highly variable in individual users' browsers.
InRegion - Default
Configurations.InRegion.Default
is the recommended configuration for most server-side use cases, where you send requests to Momento services from your apps hosted in the same cloud provider Region. It has more aggressive timeouts and retry behavior than the Laptop config, so it will fail faster and allow your application to fall back to your database or other data source more quickly. This helps ensure your applications don't bottleneck on Momento during a network or service interruption.
- JavaScript
Configurations.InRegion.Default.v1();
InRegion - Low Latency
Configurations.InRegion.LowLatency
is a configuration that prioritizes keeping p99.9 latencies as low as possible, potentially sacrificing some throughput to achieve this. It will time out quicker than the InRegion.Default
configuration. Use this configuration if the most critical factor is to ensure that cache unavailability doesn't force unacceptably high latencies for your application, and you want to fall back to application logic or an authoritative data source more quickly if the cache hasn't responded.
- JavaScript
Configurations.InRegion.LowLatency.v1();
Lambda
Configurations.Lambda
is a configuration that is available in some SDKs, and is optimized for the AWS Lambda environment. It has configuration settings designed to pre-warm the client on Lambda cold starts, and to ensure the connection is re-established proactively if a Lambda remains idle for long enough for the connection to time out.
Error Handling / Production Readiness
Each of our SDKs has its own page in this documentation; you can navigate to them by clicking Develop
->SDKs
in the left nav. On each of these pages, you'll find a link for "Taking your code to prod" that provides best practices for production-ready code in that language.
Here are some general notes on error handling in Momento that apply to all SDKs.
Errors which occur in calls to CacheClient
methods (e.g. Get, Set, Increment) are surfaced to developers as part of the return values of the calls, as opposed to throwing exceptions. This makes errors more visible when you're writing your code, and allows your IDE to be more helpful in ensuring you've handled the errors you care about. For more on our philosophy about this, see our blog post on why Exceptions are bugs, and send us any feedback you have!
This also helps to ensure your application doesn't crash at runtime. Momento is a cache, so applications usually have an authoritative data source they retrieve data from if the cache is unavailable. Therefore, Momento SDKs are designed to avoid throwing exceptions so your app won't crash if you forget to add a try/catch block.
Instead, Momento response objects extend from a parent class, have child types such as Hit,
Miss,
and Error,
and are designed to be accessed via pattern matching. (In some languages, this concept is called "sealed classes"; in others, "algebraic data types". It is a flavor of polymorphism.) Your code checks whether the response is a Hit,
a Miss,
or an Error
, and then branches accordingly. Using this approach, you get a type-safe response object in the case of a cache hit, with value
properties that you can be assured at compile-time are not null.
If the cache read results in a Miss
or an Error,
you'll also get a type-safe object that you can use to get more information about what happened (with properties such as errorCode
that aren't present on a Hit
object).
Here's an example of how to do the pattern matching on a Hit
/Miss
/Error
response:
- JavaScript
- Java
const result = await cacheClient.get('test-cache', 'test-key');
if (result instanceof CacheGet.Hit) {
console.log(`Retrieved value for key 'test-key': ${result.valueString()}`);
} else if (result instanceof CacheGet.Miss) {
console.log("Key 'test-key' was not found in cache 'test-cache'");
} else if (result instanceof CacheGet.Error) {
throw new Error(
`An error occurred while attempting to get key 'test-key' from cache 'test-cache': ${result.errorCode()}: ${result.toString()}`
);
}
final GetResponse response = cacheClient.get("test-cache", "test-key").join();
if (response instanceof GetResponse.Hit hit) {
System.out.println("Retrieved value for key 'test-key': " + hit.valueString());
} else if (response instanceof GetResponse.Miss) {
System.out.println("Key 'test-key' was not found in cache 'test-cache'");
} else if (response instanceof GetResponse.Error error) {
throw new RuntimeException(
"An error occurred while attempting to get key 'test-key' from cache 'test-cache': "
+ error.getErrorCode(),
error);
}
Some APIs, such as write APIs (e.g. Set, Delete) only have Success
and Error
responses (as opposed to Hit
/Miss
). Here's an example of handling one of these responses:
- JavaScript
- Java
const result = await cacheClient.set('test-cache', 'test-key', 'test-value');
if (result instanceof CacheSet.Success) {
console.log("Key 'test-key' stored successfully");
} else if (result instanceof CacheSet.Error) {
throw new Error(
`An error occurred while attempting to store key 'test-key' in cache 'test-cache': ${result.errorCode()}: ${result.toString()}`
);
}
final SetResponse response = cacheClient.set("test-cache", "test-key", "test-value").join();
if (response instanceof SetResponse.Success) {
System.out.println("Key 'test-key' stored successfully");
} else if (response instanceof SetResponse.Error error) {
throw new RuntimeException(
"An error occurred while attempting to store key 'test-key' in cache 'test-cache': "
+ error.getErrorCode(),
error);
}
In all cases, your IDE will be able to give you hints as to which types of responses are available for a given API, and what properties/methods are available on each of the response types.
For more information, see our Response Objects page, and the docs for the specific SDK that you are using (under Develop
->SDKs
in the left nav).