├── src └── main │ ├── resources │ ├── application.properties │ ├── META-INF │ │ └── additional-spring-configuration-metadata.json │ ├── application.conf │ └── logback.xml │ └── java │ └── com │ └── datastax │ └── workshop │ ├── TodoListDataApiApplication.java │ ├── todo │ ├── collection │ │ ├── Todo.java │ │ ├── TodoCollectionRepository.java │ │ └── TodoCollectionRestController.java │ └── table │ │ ├── Todo.java │ │ ├── TodoTableRepository.java │ │ └── TodoTableRestController.java │ └── conf │ └── AstraDbDataApiConfig.java ├── .gitignore ├── pom.xml └── README.md /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | datastax.astra.token= 2 | datastax.astra.endpoint= 3 | datastax.astra.keyspace=default_keyspace 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": [ 3 | { 4 | "name": "datastax.astra.secure-connect-bundle", 5 | "type": "java.lang.String", 6 | "description": "An absolute path to the Astra secure connect bundle to use." 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /src/main/resources/application.conf: -------------------------------------------------------------------------------- 1 | datastax-java-driver { 2 | basic { 3 | request { 4 | timeout = 8 seconds 5 | consistency = LOCAL_QUORUM 6 | page-size = 5000 7 | } 8 | } 9 | advanced { 10 | connection { 11 | init-query-timeout = 10 seconds 12 | set-keyspace-timeout = 10 seconds 13 | } 14 | control-connection.timeout = 10 seconds 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/java/com/datastax/workshop/TodoListDataApiApplication.java: -------------------------------------------------------------------------------- 1 | package com.datastax.workshop; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class TodoListDataApiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(TodoListDataApiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | astra-sdk-java.wiki/ 2 | .env 3 | .astrarc 4 | sec 5 | 6 | 7 | # eclipse conf file 8 | .settings 9 | .classpath 10 | .project 11 | .cache 12 | 13 | # idea conf files 14 | .idea 15 | *.ipr 16 | *.iws 17 | *.iml 18 | 19 | # building 20 | target 21 | build 22 | tmp 23 | releases 24 | 25 | # misc 26 | .DS_Store 27 | 28 | .factorypath 29 | .sts4-cache 30 | *.log 31 | 32 | release.properties 33 | pom.xml.releaseBackup 34 | dependency-reduced-pom* -------------------------------------------------------------------------------- /src/main/java/com/datastax/workshop/todo/collection/Todo.java: -------------------------------------------------------------------------------- 1 | package com.datastax.workshop.todo.collection; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.UUID; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | public class Todo { 14 | @JsonProperty("_id") 15 | UUID uid; 16 | String title; 17 | Boolean completed = false; 18 | Integer offset = 0; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{HH:mm:ss.SSS} %magenta(%-5level) %cyan(%-45logger) : %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/java/com/datastax/workshop/todo/table/Todo.java: -------------------------------------------------------------------------------- 1 | package com.datastax.workshop.todo.table; 2 | 3 | import com.datastax.astra.client.tables.mapping.EntityTable; 4 | import com.datastax.astra.client.tables.mapping.PartitionBy; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.util.UUID; 10 | 11 | @Data 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | @EntityTable("todos") 15 | public class Todo { 16 | @PartitionBy(0) 17 | UUID uid; 18 | String title; 19 | Boolean completed = false; 20 | Integer offset = 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/datastax/workshop/conf/AstraDbDataApiConfig.java: -------------------------------------------------------------------------------- 1 | package com.datastax.workshop.conf; 2 | 3 | import com.datastax.astra.client.DataAPIClient; 4 | import com.datastax.astra.client.databases.Database; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | public class AstraDbDataApiConfig { 11 | 12 | @Value("${datastax.astra.token}") 13 | private String token; 14 | 15 | @Value("${datastax.astra.keyspace}") 16 | private String keyspace; 17 | 18 | @Value("${datastax.astra.endpoint}") 19 | private String endpoint; 20 | 21 | @Bean 22 | public DataAPIClient createDataApiClient() { 23 | return new DataAPIClient(token); 24 | } 25 | 26 | @Bean 27 | public Database createDatabase(DataAPIClient client) { 28 | return new DataAPIClient(token).getDatabase(endpoint, keyspace); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/datastax/workshop/todo/table/TodoTableRepository.java: -------------------------------------------------------------------------------- 1 | package com.datastax.workshop.todo.table; 2 | 3 | import com.datastax.astra.client.collections.Collection; 4 | import com.datastax.astra.client.core.query.Filters; 5 | import com.datastax.astra.client.databases.Database; 6 | import com.datastax.astra.client.tables.Table; 7 | import com.datastax.workshop.todo.table.Todo; 8 | import jakarta.annotation.PostConstruct; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Repository; 11 | 12 | import java.util.List; 13 | import java.util.Optional; 14 | import java.util.UUID; 15 | 16 | import static com.datastax.astra.client.core.query.Filters.eq; 17 | 18 | @Repository 19 | public class TodoTableRepository { 20 | 21 | @Autowired 22 | private Database db; 23 | 24 | private Table table; 25 | 26 | @PostConstruct 27 | private void init() { 28 | table = db.createTable(Todo.class); 29 | } 30 | 31 | public List findAll() { 32 | return table.findAll().toList(); 33 | } 34 | 35 | public Optional findById(UUID id) { 36 | return table.findOne(eq("_id", id)); 37 | } 38 | 39 | public void save(Todo todo) { 40 | table.insertOne(todo); 41 | } 42 | 43 | public boolean existsById(UUID id) { 44 | return findById(id).isPresent(); 45 | } 46 | 47 | public void deleteById(UUID todoId) { 48 | table.deleteOne(Filters.eq("_id", todoId)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.datastax.samples 6 | spring-boot-astra-data-api 7 | 0.0.1-SNAPSHOT 8 | 9 | org.springframework.boot 10 | spring-boot-starter-parent 11 | 3.4.2 12 | 13 | 14 | 15 | 16 | 21 17 | 2.0.0-PREVIEW1 18 | 19 | 20 | 21 | 22 | 23 | com.datastax.astra 24 | astra-db-java 25 | ${astra-db-java.version} 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-web 31 | 32 | 33 | org.projectlombok 34 | lombok 35 | 36 | 37 | 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-maven-plugin 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Installation 2 | 3 | - Clone the repository 4 | 5 | ```console 6 | git@github.com:datastaxdevs/spring-boot-astra-spring-data-cassandra.git 7 | ``` 8 | 9 | - 1. Create an account in Astra DB for free 10 | https://astra.datastax.com/ 11 | 12 | - 2. Create a Database 13 | https://docs.datastax.com/en/astra-db-serverless/databases/create-database.html 14 | 15 | - 3. Create an Application token 16 | https://docs.datastax.com/en/astra-db-serverless/administration/manage-application-tokens.html 17 | 18 | ## Setup 19 | 20 | - Open `application.propoerties` and change `datastax.astra.token` with your token and `datastax.astra.endpoint` with the endpoint of your database 21 | 22 | ```ini 23 | datastax.astra.token= 24 | datastax.astra.endpoint= 25 | ``` 26 | 27 | ## use the application 28 | 29 | - Start the application (first start could take up a few seconds as the table is created for you) 30 | 31 | ```bash 32 | mvn spring-boot:run 33 | ``` 34 | 35 | - List your todos (or in your browser [http://localhost:8080/tables/todos](http://localhost:8080/todos)) 36 | 37 | ```bash 38 | curl -X GET http://localhost:8080/collections/todos 39 | curl -X GET http://localhost:8080/tables/todos 40 | ``` 41 | 42 | - Create a todo 43 | 44 | ```bash 45 | curl -X POST http://localhost:8080/collections/todos \ 46 | -H "Content-Type: application/json" \ 47 | -d '{"title": "New Todo", "description": "Todo details", "completed": false}' 48 | 49 | curl -X POST http://localhost:8080/tables/todos \ 50 | -H "Content-Type: application/json" \ 51 | -d '{"title": "New Todo", "description": "Todo details", "completed": false}' 52 | ``` 53 | 54 | - You can go data explorer: 55 | ![Screenshot 2025-02-17 at 15 06 28](https://github.com/user-attachments/assets/403d8553-05f0-4b9e-900a-226072464a91) 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/main/java/com/datastax/workshop/todo/collection/TodoCollectionRepository.java: -------------------------------------------------------------------------------- 1 | package com.datastax.workshop.todo.collection; 2 | 3 | import com.datastax.astra.client.collections.Collection; 4 | import com.datastax.astra.client.collections.CollectionOptions; 5 | import com.datastax.astra.client.collections.commands.results.CollectionInsertOneResult; 6 | import com.datastax.astra.client.collections.definition.CollectionDefaultIdTypes; 7 | import com.datastax.astra.client.collections.definition.CollectionDefinition; 8 | import com.datastax.astra.client.core.query.Filters; 9 | import com.datastax.astra.client.databases.Database; 10 | import jakarta.annotation.PostConstruct; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Repository; 13 | 14 | import java.util.List; 15 | import java.util.Optional; 16 | import java.util.UUID; 17 | 18 | import static com.datastax.astra.client.core.query.Filters.eq; 19 | 20 | @Repository 21 | public class TodoCollectionRepository { 22 | 23 | public static final String COLLECTION_NAME = "todos_collection"; 24 | 25 | @Autowired 26 | private Database db; 27 | 28 | private Collection collection; 29 | 30 | @PostConstruct 31 | private void init() { 32 | collection = db.createCollection(COLLECTION_NAME, 33 | new CollectionDefinition().defaultId(CollectionDefaultIdTypes.UUID), 34 | Todo.class); 35 | } 36 | 37 | public List findAll() { 38 | return collection.findAll().toList(); 39 | } 40 | 41 | public Optional findById(UUID id) { 42 | return collection.findById(id); 43 | } 44 | 45 | public void create(Todo todo) { 46 | collection.insertOne(todo); 47 | } 48 | 49 | public void update(Todo todo) { 50 | collection.findOneAndReplace(eq("_id", todo.getUid()), todo); 51 | } 52 | 53 | public boolean existsById(UUID id) { 54 | return collection.findOne(eq("_id", id)).isPresent(); 55 | } 56 | 57 | public void deleteById(UUID todoId) { 58 | collection.deleteOne(Filters.eq("_id", todoId)); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/datastax/workshop/todo/table/TodoTableRestController.java: -------------------------------------------------------------------------------- 1 | package com.datastax.workshop.todo.table; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import org.springframework.http.HttpStatus; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.web.bind.annotation.DeleteMapping; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.PostMapping; 10 | import org.springframework.web.bind.annotation.PutMapping; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import java.net.URI; 16 | import java.net.URISyntaxException; 17 | import java.util.UUID; 18 | import java.util.stream.Stream; 19 | 20 | @RestController 21 | @RequestMapping("/tables/todos") 22 | public class TodoTableRestController { 23 | 24 | private TodoTableRepository repo; 25 | 26 | public TodoTableRestController(TodoTableRepository todoRepo) { 27 | this.repo = todoRepo; 28 | } 29 | 30 | @GetMapping 31 | public Stream findAll() { 32 | return repo.findAll().stream(); 33 | } 34 | 35 | @GetMapping("/{uid}") 36 | public ResponseEntity findById(@PathVariable(value = "uid") String uid) { 37 | return repo 38 | .findById(UUID.fromString(uid)) 39 | .map(ResponseEntity::ok) 40 | .orElse(ResponseEntity.notFound().build()); 41 | } 42 | 43 | @PostMapping 44 | public ResponseEntity create(HttpServletRequest req, @RequestBody Todo todoReq) 45 | throws URISyntaxException { 46 | repo.save(todoReq); 47 | return ResponseEntity 48 | .created(new URI(req.getRequestURI() + "/" + todoReq.getUid())) 49 | .body(todoReq); 50 | } 51 | 52 | @PutMapping("/{uid}") 53 | public ResponseEntity update(@PathVariable String uid, @RequestBody Todo todo) { 54 | UUID todoId = UUID.fromString(uid); 55 | if (!repo.existsById(todoId)) { 56 | return ResponseEntity.notFound().build(); 57 | } 58 | todo.setUid(todoId); 59 | repo.save(todo); 60 | return ResponseEntity.ok(todo); 61 | } 62 | 63 | @DeleteMapping("{uid}") 64 | public ResponseEntity deleteById(@PathVariable(value = "uid") String uid) { 65 | UUID todoId = UUID.fromString(uid); 66 | if (!repo.existsById(todoId)) return ResponseEntity.notFound().build(); 67 | repo.deleteById(todoId); 68 | return new ResponseEntity<>(HttpStatus.NO_CONTENT); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/datastax/workshop/todo/collection/TodoCollectionRestController.java: -------------------------------------------------------------------------------- 1 | package com.datastax.workshop.todo.collection; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import org.springframework.http.HttpStatus; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.web.bind.annotation.DeleteMapping; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.PostMapping; 10 | import org.springframework.web.bind.annotation.PutMapping; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RestController; 14 | import java.net.URI; 15 | import java.net.URISyntaxException; 16 | import java.util.UUID; 17 | import java.util.stream.Stream; 18 | 19 | @RestController 20 | @RequestMapping("/collections/todos") 21 | public class TodoCollectionRestController { 22 | 23 | private TodoCollectionRepository repo; 24 | 25 | public TodoCollectionRestController(TodoCollectionRepository collectionRepository) { 26 | this.repo = collectionRepository; 27 | } 28 | 29 | @GetMapping 30 | public Stream findAll() { 31 | return repo.findAll().stream(); 32 | } 33 | 34 | @GetMapping("/{uid}") 35 | public ResponseEntity findById(@PathVariable(value = "uid") UUID uid) { 36 | return repo 37 | .findById(uid) 38 | .map(ResponseEntity::ok) 39 | .orElse(ResponseEntity.notFound().build()); 40 | } 41 | 42 | @PostMapping 43 | public ResponseEntity create(HttpServletRequest req, @RequestBody Todo todoReq) 44 | throws URISyntaxException { 45 | if (todoReq.getUid() == null) { 46 | todoReq.setUid(UUID.randomUUID()); 47 | } 48 | repo.create(todoReq); 49 | return ResponseEntity 50 | .created(new URI(req.getRequestURI() + "/" + todoReq.getUid())) 51 | .body(todoReq); 52 | } 53 | 54 | @PutMapping("/{uid}") 55 | public ResponseEntity update(@PathVariable String uid, @RequestBody Todo todo) { 56 | UUID todoId = UUID.fromString(uid); 57 | if (!repo.existsById(todoId)) { 58 | return ResponseEntity.notFound().build(); 59 | } 60 | todo.setUid(todoId); 61 | repo.update(todo); 62 | return ResponseEntity.ok(todo); 63 | } 64 | 65 | @DeleteMapping("{uid}") 66 | public ResponseEntity deleteById(@PathVariable(value = "uid") String uid) { 67 | UUID todoId = UUID.fromString(uid); 68 | if (!repo.existsById(todoId)) return ResponseEntity.notFound().build(); 69 | repo.deleteById(todoId); 70 | return new ResponseEntity<>(HttpStatus.NO_CONTENT); 71 | } 72 | 73 | } 74 | --------------------------------------------------------------------------------