Speedy-API

Java Client

The Speedy Java Client provides a fluent, type-safe API for interacting with Speedy-enabled backends. It offers a clean, builder-based interface for making CRUD operations and complex queries.

Features

Maven Dependency


<dependency>
    <groupId>com.github.silentsamurai</groupId>
    <artifactId>speedy-java-client</artifactId>
    <version>3.1.4</version>
</dependency>

Quick Start

Basic Usage

import static com.github.silent.samurai.speedy.api.client.SpeedyQuery.*;

// Create a client
RestTemplate restTemplate = new RestTemplate();
        SpeedyClient<SpeedyResponse> client = SpeedyClient.restTemplate(restTemplate, "http://localhost:8080");

        // Create a new category
        SpeedyResponse response = client.create("Category")
                .addField("name", "cat-client-1")
                .execute();

        // Query categories
        SpeedyQuery query = SpeedyQuery.from("Category")
                .where(condition("name", eq("cat-client-1")))
                .build();

        SpeedyResponse categories = client.query(query).execute();

Testing with MockMvc

import static com.github.silent.samurai.speedy.api.client.SpeedyQuery.*;

@SpringBootTest
@AutoConfigureMockMvc
class CategoryControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void testCreateCategory() {
        SpeedyClient<ResultActions> client = SpeedyClient.mockMvc(mockMvc);

        ResultActions result = client.create("Category")
                .addField("name", "test-category")
                .execute();

        result.andExpect(status().isCreated());
    }
}

Components

SpeedyClient

The main client class that provides CRUD operations and query execution.

SpeedyQuery

A fluent query builder for constructing complex database queries with conditions, ordering, pagination, and entity expansions.

Entity Expansions

The Java client supports both simple and multi-level entity expansions:

// Simple expansion
SpeedyQuery query = SpeedyQuery.from("inventory")
                .expand("Product")
                .expand("Procurement")
                .build();

// Multi-level expansion with dot notation
SpeedyQuery query = SpeedyQuery.from("inventory")
        .expand("Product")
        .expand("Product.Category")
        .expand("Product.Category.Supplier")
        .expand("Procurement")
        .expand("Procurement.Product")
        .build();

// Execute the query
SpeedyResponse response = client.query(query).execute();

For detailed information about multi-level expansions, see Multi-Level Expansions.

GET List Queries

When using get() without a primary key, you can apply field selection, pagination, and expansion via URL query parameters:

Speedy speedy = Speedy.connect("http://localhost:8080");

// Select specific fields
List<Product> products = speedy.get("Product")
        .select("id", "name", "description")
        .execute()
        .list(Product.class);

// Select + pagination + expansion
List<Product> products = speedy.get("Product")
        .select("id", "name")
        .pageSize(20)
        .pageNo(0)
        .expand("category")
        .execute()
        .list(Product.class);

// Count query
SpeedyResult result = speedy.get("Product")
        .select("$count")
        .execute();
long count = result.raw().get("count").asLong();

These methods produce URL query parameters ($select=id,name&$pageSize=20&...) rather than JSON body fields, matching the GET Operation API.

Character Encoding

All transports guarantee UTF-8 encoding for both request and response:

Response bodies are always decoded as UTF-8.

HTTP Client Support

The Java client supports multiple HTTP client implementations:

Client Use Case Factory Method
RestTemplate Production applications SpeedyClient.restTemplate(restTemplate, baseUrl)
MockMvc Unit/integration testing SpeedyClient.mockMvc(mockMvc)
Custom Custom implementations SpeedyClient.from(httpClient)

Best Practices

  1. Use static imports for cleaner code:
    import static com.github.silent.samurai.speedy.api.client.SpeedyQuery.*;
    
  2. Handle responses properly:
    import com.fasterxml.jackson.databind.JsonNode;
    import com.github.silent.samurai.speedy.api.client.models.SpeedyResponse;
       
    SpeedyResponse response = client.get("users").execute();
    JsonNode payload = response.getPayload();
       
    if (payload != null && !payload.isEmpty()) {
        // Process data from payload
        if (payload.isArray()) {
            // Handle array of entities
            for (JsonNode user : payload) {
                // Process each user
            }
        } else if (payload.isObject()) {
            // Handle single entity
            // Process the user object
        }
    } else {
        // Handle empty or null response
        log.warn("No data returned from API");
    }
    
  3. Use appropriate HTTP clients:
    • Use RestTemplate for production
    • Use MockMvc for testing
    • Create custom clients for special requirements
  4. Optimize queries:
    • Select only needed fields
    • Use appropriate page sizes
    • Add proper conditions to reduce data transfer

Error Handling

The client provides comprehensive error handling:

try{
SpeedyResponse response = client.create("users")
        .addField("name", "John Doe")
        .addField("email", "john@example.com")
        .execute();
}catch(
SpeedyClientException e){
        // Handle client-specific errors
        log.

error("Client error: {}",e.getMessage());
        }catch(
Exception e){
        // Handle general errors
        log.

error("Unexpected error: {}",e.getMessage());
        }