Spring REST Client
The Spring Boot starter provides a type-safe REST client for interacting with Memory Service. The client is automatically configured when you include the starter.
Setup
The REST client is included in the starter:
<dependency>
<groupId>io.github.chirino.memory-service</groupId>
<artifactId>memory-service-spring-boot-starter</artifactId>
<version>999-SNAPSHOT</version>
</dependency>
Injecting the Client
The starter auto-configures an ApiClient bean. You can inject it and create API instances:
import io.github.chirino.memoryservice.client.api.ConversationsApi;
import io.github.chirino.memoryservice.client.api.UserConversationsApi;
import io.github.chirino.memoryservice.client.api.SearchApi;
import io.github.chirino.memoryservice.client.invoker.ApiClient;
import org.springframework.stereotype.Service;
@Service
public class MyService {
private final ConversationsApi conversationsApi;
private final UserConversationsApi userConversationsApi;
private final SearchApi searchApi;
public MyService(ApiClient apiClient) {
this.conversationsApi = new ConversationsApi(apiClient);
this.userConversationsApi = new UserConversationsApi(apiClient);
this.searchApi = new SearchApi(apiClient);
}
}
Alternatively, you can use MemoryServiceClients.createApiClient() to create a custom client with specific configuration:
import io.github.chirino.memoryservice.client.MemoryServiceClients;
import io.github.chirino.memoryservice.client.MemoryServiceClientProperties;
import org.springframework.web.reactive.function.client.WebClient;
ApiClient apiClient = MemoryServiceClients.createApiClient(
properties,
WebClient.builder(),
null // OAuth2AuthorizedClientManager if needed
);
Calling as an asserted user
An API-key client listed in the server’s MEMORY_SERVICE_TRUSTED_USER_ID_CLIENTS can attach X-User-ID to normal user API calls. Build a request-specific client rather than modifying the shared auto-configured ApiClient:
MemoryServiceClientProperties requestProperties = new MemoryServiceClientProperties();
requestProperties.setUrl("http://memory-service:8080");
requestProperties.setApiKey(serviceApiKey);
requestProperties.getDefaultHeaders().put("X-User-ID", userId);
ApiClient requestClient = MemoryServiceClients.createApiClient(
requestProperties,
webClientBuilder.clone(),
null);
ConversationsApi conversationsForUser = new ConversationsApi(requestClient);
X-User-ID is effective-user context, not a credential. Untrusted assertions are ignored, invalid credentials are rejected, and admin/system APIs retain the authenticated principal. See Trusted Client User Identity Assertion for API-key, OIDC, and mixed-mode configuration.
API Overview
The REST client provides several API classes:
ConversationsApi- CRUD operations for conversationsUserConversationsApi- User-scoped conversation operationsSearchApi- Semantic search across conversationsSystemApi- System health and status
Conversations API
List Conversations
import io.github.chirino.memoryservice.client.api.ConversationsApi;
import io.github.chirino.memoryservice.client.model.ListConversations200Response;
import reactor.core.publisher.Mono;
Mono<ListConversations200Response> response = conversationsApi.listConversations(
null, // mode
"all", // ancestry
null, // afterCursor
20, // limit
null, // query
"exclude", // archived
null // metadata
);
response.block().getData().forEach(conversation -> {
System.out.println(conversation.getId());
});
Or use MemoryServiceProxy to filter by metadata (up to 5 predicates, combined with AND):
import io.github.chirino.memoryservice.client.MemoryServiceProxy;
import java.util.List;
import org.springframework.http.ResponseEntity;
ResponseEntity<?> filtered = proxy.listConversations(
"all", // mode
null, // afterCursor
20, // limit
null, // query
"exclude", // archived
List.of("status=waiting", "agent-id!=worker-2") // metadata filters
);
Get Conversation
Mono<Conversation> conversation = conversationsApi.getConversation("conversation-id");
Conversation conv = conversation.block();
System.out.println(conv.getTitle());
Create Conversation
import io.github.chirino.memoryservice.client.model.CreateConversationRequest;
CreateConversationRequest request = new CreateConversationRequest();
request.setId("my-conversation");
request.setMetadata(Map.of("topic", "support"));
Mono<Conversation> conversation = conversationsApi.createConversation(request);
Conversation conv = conversation.block();
Update Conversation
import io.github.chirino.memoryservice.client.model.UpdateConversationRequest;
UpdateConversationRequest request = new UpdateConversationRequest();
request.setMetadata(Map.of("status", "resolved"));
Mono<Conversation> conversation = conversationsApi.updateConversation(
"conversation-id",
request
);
Delete Conversation
Mono<Void> result = conversationsApi.deleteConversation("conversation-id");
result.block();
Messages API
List Messages
import io.github.chirino.memoryservice.client.model.MessageChannel;
Mono<MessagesResponse> response = conversationsApi.listConversationMessages(
"conversation-id",
null, // after
100, // limit
MessageChannel.HISTORY, // channel
null // actor
);
response.block().getData().forEach(message -> {
System.out.println(message.getType() + ": " + message.getContent());
});
Add Message
import io.github.chirino.memoryservice.client.model.AddMessageRequest;
import io.github.chirino.memoryservice.client.model.MessageType;
AddMessageRequest request = new AddMessageRequest();
request.setType(MessageType.USER);
request.setContent("Hello, how can you help?");
request.setMetadata(Map.of("client", "web"));
Mono<Message> message = conversationsApi.addMessage("conversation-id", request);
User Conversations API
The UserConversationsApi provides user-scoped operations that automatically use the authenticated user’s context:
List User Conversations
import io.github.chirino.memoryservice.client.api.UserConversationsApi;
Mono<ConversationsResponse> response = userConversationsApi.listConversations(
null, // mode
null, // after
20, // limit
null // query
);
Get User Conversation
Mono<Conversation> conversation = userConversationsApi.getConversation("conversation-id");
Search API
Semantic Search
import io.github.chirino.memoryservice.client.api.SearchApi;
import io.github.chirino.memoryservice.client.model.SearchRequest;
SearchRequest request = new SearchRequest();
request.setQuery("How do I configure authentication?");
request.setLimit(10);
request.setMinScore(0.7);
Mono<SearchResponse> response = searchApi.search(request);
response.block().getData().forEach(result -> {
System.out.println(result.getScore() + ": " + result.getContent());
});
Filtered Search
SearchRequest request = new SearchRequest();
request.setQuery("error handling");
request.setConversationIds(List.of("conv-1", "conv-2"));
request.setMessageTypes(List.of(MessageType.AI));
// request.setAfter(Instant.parse("2024-01-01T00:00:00Z"));
Mono<SearchResponse> response = searchApi.search(request);
Error Handling
The client uses reactive types (Mono), so errors are propagated through the reactive chain:
try {
Conversation conv = conversationsApi.getConversation("unknown-id").block();
} catch (WebClientResponseException e) {
if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
// Conversation not found
} else {
// Other API error
System.err.println("Error: " + e.getStatusCode() + " - " + e.getMessage());
}
}
Configuration Properties
Configure the REST client in application.properties:
# Memory Service URL
memory-service.client.url=${MEMORY_SERVICE_URL:http://localhost:8082}
# API Key for agent authentication
memory-service.client.api-key=${MEMORY_SERVICE_API_KEY:}
# Bearer token (alternative to OAuth2)
memory-service.client.bearer-token=${MEMORY_SERVICE_BEARER_TOKEN:}
# Request logging
memory-service.client.log-requests=true
# Timeout
memory-service.client.timeout=30s
# OIDC client registration (for OAuth2)
memory-service.client.oidc-client-registration=memory-service-client
Using with OAuth2
When using OAuth2, the client can automatically obtain tokens. Configure OAuth2 in application.properties:
spring.security.oauth2.client.registration.memory-service-client.client-id=memory-service-client
spring.security.oauth2.client.registration.memory-service-client.client-secret=change-me
spring.security.oauth2.client.registration.memory-service-client.scope=openid,profile,email
spring.security.oauth2.client.provider.memory-service-client.issuer-uri=http://localhost:8081/realms/memory-service
memory-service.client.oidc-client-registration=memory-service-client
The client will automatically use OAuth2 tokens when making requests.
Next Steps
- gRPC Client - For streaming and high-performance use cases
- Conversation Forking - Branch conversations to explore alternative paths
- Response Recording and Resumption - Streaming responses with resume and cancel support