Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions integrations/skills/spring-boot-data-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ A comprehensive AI-powered skill for building production-ready Spring Boot appli
## Quick Links

- 📚 **[Main Skill Document](SKILL.md)** - Complete step-by-step guide
- 📝 **[Code Templates](templates/)** - Reusable code templates
- 💡 **[Basic Example](examples/basic/)** - Minimal working example
- 📝 **[Code Templates](assets/templates/)** - Reusable code templates
- 💡 **[Basic Example](assets/examples/basic/)** - Minimal working example

## What You'll Learn

Expand All @@ -29,6 +29,26 @@ A comprehensive AI-powered skill for building production-ready Spring Boot appli

30-45 minutes

## Folder Structure

```
spring-boot-data-api/
├── README.md # This file
├── SKILL.md # Main skill guide
├── references/ # Additional reference docs (future)
├── scripts/ # Automation scripts (future)
└── assets/ # Reusable assets
├── templates/ # Code templates
│ ├── Document.java.template
│ ├── Repository.java.template
│ ├── Service.java.template
│ ├── Controller.java.template
│ └── application.yml.template
└── examples/ # Working examples
└── basic/ # Basic example
└── README.md
```

## How to Use This Skill

### With Claude
Expand Down Expand Up @@ -70,7 +90,7 @@ integrations/skills/spring-boot-data-api/SKILL.md
```

2. **Use templates to generate code:**
- Copy templates from `templates/` directory
- Copy templates from `assets/templates/` directory
- Replace placeholders ({{CLASS_NAME}}, {{COLLECTION_NAME}}, etc.)
- Customize for your use case

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Basic Spring Boot with Astra DB Example

This is a minimal working example demonstrating Spring Boot integration with Astra DB.

## What's Included

- Simple Product entity with basic CRUD operations
- Spring Data repository
- REST API endpoints
- Configuration examples

## Quick Start

1. **Set environment variables:**
```bash
export ASTRA_DB_TOKEN="AstraCS:..."
export ASTRA_DB_ENDPOINT="https://your-db-id-region.apps.astra.datastax.com"
```

2. **Run the application:**
```bash
mvn spring-boot:run
```

3. **Test the API:**
```bash
# Create a product
curl -X POST http://localhost:8080/api/products \
-H "Content-Type: application/json" \
-d '{"name":"Laptop","category":"Electronics","price":999.99,"stock":10}'

# List all products
curl http://localhost:8080/api/products

# Get by ID
curl http://localhost:8080/api/products/{id}
```

## Project Structure

```
src/
├── main/
│ ├── java/
│ │ └── com/example/demo/
│ │ ├── DemoApplication.java
│ │ ├── model/
│ │ │ └── Product.java
│ │ ├── repository/
│ │ │ └── ProductRepository.java
│ │ ├── service/
│ │ │ └── ProductService.java
│ │ └── controller/
│ │ └── ProductController.java
│ └── resources/
│ └── application.yml
└── test/
└── java/
└── com/example/demo/
└── ProductServiceTest.java
```

## Next Steps

- Add vector search capabilities
- Implement pagination
- Add validation
- Create integration tests
- Deploy to production

See the main [SKILL.md](../../SKILL.md) for detailed guidance.
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.example.demo.controller;

import com.example.demo.model.{{CLASS_NAME}};
import com.example.demo.service.{{CLASS_NAME}}Service;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
* REST controller for {{CLASS_NAME}} endpoints.
*/
@RestController
@RequestMapping("/api/{{RESOURCE_PATH}}")
@RequiredArgsConstructor
public class {{CLASS_NAME}}Controller {

private final {{CLASS_NAME}}Service service;

/**
* List all entities.
*/
@GetMapping
public List<{{CLASS_NAME}}> list() {
return service.findAll();
}

/**
* List entities with pagination.
*/
@GetMapping("/paginated")
public Page<{{CLASS_NAME}}> listPaginated(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(defaultValue = "id") String sortBy) {
return service.findAllPaginated(page, size, sortBy);
}

/**
* Get entity by ID.
*/
@GetMapping("/{id}")
public {{CLASS_NAME}} get(@PathVariable String id) {
return service.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Entity not found"));
}

/**
* Create new entity.
*/
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public {{CLASS_NAME}} create(@Valid @RequestBody {{CLASS_NAME}} entity) {
return service.create(entity);
}

/**
* Update existing entity.
*/
@PutMapping("/{id}")
public {{CLASS_NAME}} update(
@PathVariable String id,
@Valid @RequestBody {{CLASS_NAME}} entity) {
return service.update(id, entity);
}

/**
* Delete entity.
*/
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(@PathVariable String id) {
service.delete(id);
}

/**
* Search entities.
*/
@GetMapping("/search")
public List<{{CLASS_NAME}}> search(
@RequestParam String field,
@RequestParam String value) {
return service.search(field, value);
}
}

class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.example.demo.model;

import com.datastax.astra.client.collections.mapping.*;
import com.datastax.astra.client.core.vector.SimilarityMetric;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.experimental.Accessors;

import java.time.Instant;

/**
* Document class template for Astra DB collections.
*
* Replace {{COLLECTION_NAME}} with your collection name.
* Customize fields, validation, and indexing as needed.
*/
@Data
@Accessors(chain = true)
@DataApiCollection(
name = "{{COLLECTION_NAME}}",
// Optional: Vector search configuration
// vectorDimension = 1536,
// vectorSimilarity = SimilarityMetric.COSINE,
// vectorizeProvider = "openai",
// vectorizeModel = "text-embedding-ada-002",
// vectorizeSharedSecret = "OPENAI_API_KEY",

// Optional: Full-text search
// lexicalEnabled = true,
// lexicalAnalyzer = AnalyzerTypes.ENGLISH,

// Optional: Indexing optimization
indexingDeny = {"internal_field"}
)
public class {{CLASS_NAME}} {

@DocumentId
private String id;

@NotBlank(message = "Field is required")
private String field1;

@NotNull(message = "Field is required")
private String field2;

// Optional: Auto-vectorization
// @Vectorize
// private String vectorizeField;

// Optional: Full-text search
// @Lexical
// private String searchableText;

@JsonProperty("created_at")
private Instant createdAt;

@JsonProperty("updated_at")
private Instant updatedAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.example.demo.repository;

import com.datastax.astra.spring.DataApiCollectionCrudRepository;
import com.example.demo.model.{{CLASS_NAME}};
import org.springframework.stereotype.Repository;

/**
* Spring Data repository for {{CLASS_NAME}}.
*
* Provides CRUD operations and query capabilities:
* - save(entity)
* - findById(id)
* - findAll()
* - deleteById(id)
* - count()
* - Query by Example
* - Data API filters
*/
@Repository
public interface {{CLASS_NAME}}Repository
extends DataApiCollectionCrudRepository<{{CLASS_NAME}}, String> {

// Custom query methods can be added here
// Spring Data will automatically implement them
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.example.demo.service;

import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.core.query.Filters;
import com.example.demo.model.{{CLASS_NAME}};
import com.example.demo.repository.{{CLASS_NAME}}Repository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.List;
import java.util.Optional;

/**
* Service layer for {{CLASS_NAME}} business logic.
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class {{CLASS_NAME}}Service {

private final {{CLASS_NAME}}Repository repository;

/**
* Create a new entity.
*/
public {{CLASS_NAME}} create({{CLASS_NAME}} entity) {
entity.setCreatedAt(Instant.now());
entity.setUpdatedAt(Instant.now());
log.info("Creating entity: {}", entity);
return repository.save(entity);
}

/**
* Find entity by ID.
*/
public Optional<{{CLASS_NAME}}> findById(String id) {
return repository.findById(id);
}

/**
* Find all entities.
*/
public List<{{CLASS_NAME}}> findAll() {
return (List<{{CLASS_NAME}}>) repository.findAll();
}

/**
* Update an existing entity.
*/
public {{CLASS_NAME}} update(String id, {{CLASS_NAME}} updates) {
{{CLASS_NAME}} entity = repository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Entity not found: " + id));

// Update fields
// entity.setField1(updates.getField1());
// entity.setField2(updates.getField2());
entity.setUpdatedAt(Instant.now());

return repository.save(entity);
}

/**
* Delete entity by ID.
*/
public void delete(String id) {
repository.deleteById(id);
}

/**
* Find entities with pagination.
*/
public Page<{{CLASS_NAME}}> findAllPaginated(int page, int size, String sortBy) {
Pageable pageable = PageRequest.of(page, size, Sort.by(sortBy));
return repository.findAll(Example.of(new {{CLASS_NAME}}()), pageable);
}

/**
* Search entities using Data API filters.
*/
public List<{{CLASS_NAME}}> search(String field, String value) {
Filter filter = Filters.eq(field, value);
return (List<{{CLASS_NAME}}>) repository.findAll(filter);
}
}

class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
Loading