Take the community feedback survey now.

Retrieving stored synonyms in Optimizely Graph

Vote:
 

Hi,

I’m currently implementing synonyms for our search functionality, following the Optimizely Graph documentation on synonyms. Everything works as expected — I can add synonyms and confirm they’re applied correctly in search results.

However, I’d like to enable some of our editors to manage these synonyms themselves, without requiring direct API knowledge. To do this, I need a way to retrieve the currently stored synonyms, but I haven’t been able to find any API endpoint that supports a GET operation for them.

I have found an API reference https://docs.developers.optimizely.com/platform-optimizely/reference/upsert-synonymhandler which supports PUT and DELETE.


Has anyone come across a method or workaround for fetching stored synonyms? Any insights would be appreciated.

#340145
Aug 29, 2025 11:31
Vote:
 

Hi Mats,

Unfortunately there isn't a way to be able to query the currently stored synonyms using the API endpoint, something I feel there should be... so the best way of managing these in my opinion is to set them up in a global site settings page in your site, and then create an initializable module that hooks into the PublishedContent event and calls a SynonymsUpload service if the page being published is of type SiteSettings page.

See example code below:

SynonymsInitializationModule

/// <summary>
/// On publish of the site settings page check for synonyms and updates graph
/// </summary>
[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public sealed class SynonymsInitializationModule : IConfigurableModule
{
    private ISynonymsUploadService? _synonymsUploadService;

    private ILogger<SynonymsInitializationModule>? _logger;

    public void Initialize(InitializationEngine context)
    {
        _synonymsUploadService = context.Locate.Advanced.GetInstance<ISynonymsUploadService>() ??
                                 throw new ArgumentNullException(nameof(_synonymsUploadService));

        _logger = context.Locate.Advanced.GetInstance<ILogger<SynonymsInitializationModule>>();

        var events = context.Locate.Advanced.GetInstance<IContentEvents>();
        events.PublishedContent += OnPagePublished;
    }

    public void Uninitialize(InitializationEngine context)
    {
        var events = context.Locate.Advanced.GetInstance<IContentEvents>();
        events.PublishedContent -= OnPagePublished;
    }

    private async void OnPagePublished(object? sender, ContentEventArgs e)
    {
        try
        {
            if (e.Content is not SiteSettingsPage { Synonyms: { Count: > 0 } searchSynonyms })
                return;

            var language = (e.Content as ILocale)?.Language.Name;

            if (_synonymsUploadService != null)
            {
                await _synonymsUploadService.UploadSynonyms(searchSynonyms, language);
            }

        }
        catch (Exception ex)
        {
            _logger?.LogError("Error uploading synonyms: {0}", ex);
        }
    }

    public void ConfigureContainer(ServiceConfigurationContext context)
    {
    }
}

SynonymsUploadService

public sealed class SynonymsUploadService(
    ILogger<SynonymsUploadService> logger,
    HttpClient httpClient,
    IOptions<ContentGraphOptions> options)
    : ISynonymsUploadService
{
    private readonly string? _graphUrl = options.Value.GatewayAddress;

    private readonly string? _authenticationHeader = (options.Value.AppKey + ":" + options.Value.Secret).Base64Encode();

    public async Task UploadSynonyms(IEnumerable<SynonymsBlock> searchSynonyms, string? language) =>
        await UploadSynonyms(searchSynonyms, language, CancellationToken.None);

    public async Task UploadSynonyms(IEnumerable<SynonymsBlock> searchSynonyms, string? language, CancellationToken cancellationToken)
    {
        try
        {
            var request = new HttpRequestMessage(HttpMethod.Put,
                $"{_graphUrl}/resources/synonyms?synonym_slot=one&language_routing={language}");
            request.Headers.Authorization =
                new AuthenticationHeaderValue("Basic", _authenticationHeader);

            var synonyms = GetSynonyms(searchSynonyms);

            request.Content = new StringContent(synonyms, Encoding.UTF8, "text/plain");

            using var response = await httpClient.SendAsync(request, cancellationToken);

            response.EnsureSuccessStatusCode();
        }
        catch (OperationCanceledException ex)
        {
            logger.LogWarning("The operation was canceled: " + ex.Message);
        }
        catch (HttpRequestException ex)
        {
            logger.LogError("HTTP request failed: " + ex.Message);
        }
        catch (Exception ex) when (ex is not OperationCanceledException)
        {
            logger.LogError(ex, "");
        }
    }

    private static string GetSynonyms(IEnumerable<SynonymsBlock> searchSynonyms)
    {
        var synonymList = new StringBuilder();

        foreach (var synonyms in searchSynonyms)
        {
            if (synonyms.Synonyms is not { Count: > 0 })
                continue;

            var synonymsText = string.Join(", ", synonyms.Synonyms);

            synonymList.AppendLine(synonymsText);
        }

        return synonymList.ToString();
    }
}

Following this method, you can use the CMS as the data source for the synonyms and have them easily updated by an editor.

Thanks,

Graham

#340179
Sep 01, 2025 19:31
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.