├── .gitignore ├── .gitpod.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE.md ├── README.md ├── astra.json ├── hero.png ├── img ├── 01.png ├── 02.png ├── 03.png ├── 04.png ├── 05.png └── 06.png ├── pom.xml ├── setup.sh └── src └── main ├── java └── com │ └── datastax │ └── examples │ ├── DataStaxAstraProperties.java │ ├── SpringDataCassandraApplication.java │ └── order │ ├── Order.java │ ├── OrderController.java │ ├── OrderPrimaryKey.java │ ├── OrderRepository.java │ └── ProductNameAndPrice.java └── resources ├── META-INF └── additional-spring-configuration-metadata.json ├── application.yml └── logback.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # eclipse conf file 2 | .settings 3 | .classpath 4 | .project 5 | .cache 6 | 7 | # idea conf files 8 | .idea 9 | *.ipr 10 | *.iws 11 | *.iml 12 | 13 | # building 14 | target 15 | build 16 | tmp 17 | dist 18 | 19 | # misc 20 | .DS_Store 21 | .factorypath 22 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: gitpod/workspace-full 2 | tasks: 3 | - init: mvn package 4 | command: . setup.sh && java -jar target/spring-data-example-1.0.0-SNAPSHOT.jar 5 | ports: 6 | - port: 8081 7 | onOpen: open-browser 8 | github: 9 | prebuilds: 10 | master: true 11 | branches: false 12 | pullRequests: false 13 | pullRequestsFromForks: false 14 | addCheck: false 15 | addComment: false 16 | addBadge: false 17 | addLabel: false 18 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at . All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, 4 | email, or any other method with the owners of this repository before making a change. 5 | 6 | Please note we have a [Code of Conduct](CODE_OF_CONDUCT.md), please follow it in all your interactions with the project. 7 | 8 | ## Found an Issue? 9 | If you find a bug in the source code or a mistake in the documentation, you can help us by 10 | [submitting an issue](#submit-issue) to the GitHub Repository. Even better, you can 11 | [submit a Pull Request](#submit-pr) with a fix. 12 | 13 | ## Want a Feature? 14 | You can *request* a new feature by [submitting an issue](#submit-issue) to the GitHub 15 | Repository. If you would like to *implement* a new feature, please submit an issue with 16 | a proposal for your work first, to be sure that we can use it. 17 | 18 | * **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr). 19 | 20 | ## Contribution Guidelines 21 | 22 | ### Submitting an Issue 23 | Before you submit an issue, search the archive, maybe your question was already answered. 24 | 25 | If your issue appears to be a bug, and hasn't been reported, open a new issue. 26 | Help us to maximize the effort we can spend fixing issues and adding new 27 | features, by not reporting duplicate issues. Providing the following information will increase the 28 | chances of your issue being dealt with quickly: 29 | 30 | * **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps 31 | * **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you 32 | * **Reproduce the Error** - provide a live example or a unambiguous set of steps 33 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be 34 | causing the problem (line of code or commit) 35 | 36 | ### Submitting a Pull Request (PR) 37 | Before you submit your Pull Request (PR) consider the following guidelines: 38 | 39 | * Search the repository (https://github.com/bechbd/[repository-name]/pulls) for an open or closed PR that relates to your submission. You don't want to duplicate effort. 40 | 41 | * Create a fork of the repo 42 | * Navigate to the repo you want to fork 43 | * In the top right corner of the page click **Fork**: 44 | ![](https://help.github.com/assets/images/help/repository/fork_button.jpg) 45 | 46 | * Make your changes in the forked repo 47 | * Commit your changes using a descriptive commit message 48 | * In GitHub, create a pull request: https://help.github.com/en/articles/creating-a-pull-request-from-a-fork 49 | * If we suggest changes then: 50 | * Make the required updates. 51 | * Rebase your fork and force push to your GitHub repository (this will update your Pull Request): 52 | 53 | ```shell 54 | git rebase master -i 55 | git push -f 56 | ``` 57 | 58 | That's it! Thank you for your contribution! -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11.0.7-jre-slim-buster 2 | EXPOSE 8081 3 | EXPOSE 8082 4 | 5 | WORKDIR /app 6 | ARG JAR=spring-data-example-1.0.0-SNAPSHOT.jar 7 | 8 | COPY /target/$JAR /app.jar 9 | ENTRYPOINT ["java","-jar","/app.jar"] -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Spring Data Cassandra REST API 3 | *10 minutes, Beginner, [Start Building](https://github.com/DataStax-Examples/spring-data-starter#prerequisites)* 4 | 5 | This application uses Spring Data Cassandra and DataStax Astra DB to build a REST API for a backend service that interacts with products and orders. 6 | 7 | 8 | ![image](https://user-images.githubusercontent.com/3254549/90944387-439a1f00-e3d3-11ea-9df4-e8a5580c62cd.png) 9 | 10 | ## Objectives 11 | * Run a REST API that connects to DataStax Astra DB 12 | 13 | ## How this works 14 | We're using Spring Data Cassandra and Datastax Astra DB to build a REST API that stores Products and Orders. 15 | 16 | ## Get Started 17 | To build and play with this app, follow the build instructions that are located here: [https://github.com/DataStax-Examples/spring-data-starter](https://github.com/DataStax-Examples/spring-data-starter#prerequisites) 18 | 19 | 20 | # Running Spring Data Cassandra REST API 21 | Follow the instructions below to get started. 22 | 23 | ## Prerequisites 24 | Let's do some initial setup by creating a serverless(!) database. 25 | 26 | ### DataStax Astra 27 | 1. Create a [DataStax Astra account](https://dtsx.io/38HWu73) if you don't already have one: 28 | ![image](img/01.png) 29 | 30 | 2. On the home page. Locate the button **`Create Database`** both vector and non-vector support the Cassandra CQL 31 | ![image](img/02.png) 32 | 33 | 3. Populate the fields and click create database 34 | ![image](img/03.png) 35 | 36 | 4. After your database is provisioned, we need to generate an Application Token for our App. Go to the `Settings` tab in the database home screen. 37 | ![image](img/04.png) 38 | 39 | 5. Generate a token by clicking `Generate Token` and give it a name. 40 | ![image](img/05.png) 41 | 42 | 6. After you have your Application Token, head to the database connect screen and select the driver connection that we need. Go ahead and download the `Secure Bundle` for the driver. 43 | ![image](img/06.png) 44 | 45 | ### Github 46 | 1. Click `Use this template` at the top of the [GitHub Repository](https://github.com/DataStax-Examples/spring-data-starter): 47 | ![image](https://raw.githubusercontent.com/DataStax-Examples/sample-app-template/master/screenshots/github-use-template.png) 48 | 49 | 2. Enter a repository name and click 'Create repository from template': 50 | ![image](https://raw.githubusercontent.com/DataStax-Examples/sample-app-template/master/screenshots/github-create-repository.png) 51 | 52 | 3. Clone the repository: 53 | ![image](https://raw.githubusercontent.com/DataStax-Examples/sample-app-template/master/screenshots/github-clone.png) 54 | 55 | ## 🚀 Getting Started Paths: 56 | *Make sure you've completed the [prerequisites](#prerequisites) before starting this step* 57 | - [Running on Gitpod](#running-on-gitpod) 58 | 59 | ### Running on Gitpod 60 | 1. Click the 'Open in Gitpod' link: 61 | [![Open in IDE](https://gitpod.io/button/open-in-gitpod.svg)](https://dtsx.io/2QjoULs) 62 | 63 | 2. Once your Gitpod workspace has loaded, you'll be asked to paste your service account credentials in the Gitpod terminal at the bottom of the screen: 64 | ![image](https://user-images.githubusercontent.com/3254549/90944321-e900c300-e3d2-11ea-9624-dae5f81b6a0a.png) 65 | 66 | 3. When the app is finished building, click the 'Open Browser' button on the bottom right of the screen: 67 | ![image](https://user-images.githubusercontent.com/3254549/90944371-249b8d00-e3d3-11ea-8305-b7d4fad9742c.png) 68 | 69 | 4. You've successfully build a Spring Data Cassandra application! 70 | ![image](https://user-images.githubusercontent.com/3254549/90944387-439a1f00-e3d3-11ea-9df4-e8a5580c62cd.png) 71 | 72 | -------------------------------------------------------------------------------- /astra.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Spring Data Astra DB REST API", 3 | "description": "This application uses Spring Data Cassandra and DataStax Astra DB to build a REST API for a backend service that interacts with products and orders.", 4 | "duration": "10 minutes", 5 | "skillLevel": "Beginner", 6 | "gitpodUrl": "https://dtsx.io/2QjoULs", 7 | "githubUrl": "https://github.com/DataStax-Examples/spring-data-starter", 8 | "tags": [{ "name": "java" }, { "name": "java driver" }], 9 | "category": "starters", 10 | "priority": 1, 11 | "heroImage": "https://raw.githubusercontent.com/DataStax-Examples/spring-data-starter/master/hero.png" 12 | } 13 | -------------------------------------------------------------------------------- /hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataStax-Examples/spring-data-starter/331017bb6cc6c6a3ad4ea088c08f3800a57c13ba/hero.png -------------------------------------------------------------------------------- /img/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataStax-Examples/spring-data-starter/331017bb6cc6c6a3ad4ea088c08f3800a57c13ba/img/01.png -------------------------------------------------------------------------------- /img/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataStax-Examples/spring-data-starter/331017bb6cc6c6a3ad4ea088c08f3800a57c13ba/img/02.png -------------------------------------------------------------------------------- /img/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataStax-Examples/spring-data-starter/331017bb6cc6c6a3ad4ea088c08f3800a57c13ba/img/03.png -------------------------------------------------------------------------------- /img/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataStax-Examples/spring-data-starter/331017bb6cc6c6a3ad4ea088c08f3800a57c13ba/img/04.png -------------------------------------------------------------------------------- /img/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataStax-Examples/spring-data-starter/331017bb6cc6c6a3ad4ea088c08f3800a57c13ba/img/05.png -------------------------------------------------------------------------------- /img/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataStax-Examples/spring-data-starter/331017bb6cc6c6a3ad4ea088c08f3800a57c13ba/img/06.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.datastax.examples 8 | spring-data-example 9 | 1.0.0-SNAPSHOT 10 | Spring Boot & Spring Data Example 11 | Demo project for using Spring Boot, Spring Data Cassandra with DataStax Astra 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-parent 16 | 3.3.0 17 | 18 | 19 | 20 | 21 | 22 | UTF-8 23 | 21 24 | 25 | 26 | 4.17.0 27 | 1.4.11 28 | 1.8.0 29 | 30 | 31 | 3.0.0 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-data-cassandra 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-data-rest 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-web 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-configuration-processor 53 | true 54 | 55 | 56 | org.springdoc 57 | springdoc-openapi-starter-webmvc-ui 58 | 2.5.0 59 | 60 | 61 | org.projectlombok 62 | lombok 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | org.apache.maven.plugins 71 | maven-compiler-plugin 72 | 73 | ${java.version} 74 | ${java.version} 75 | ${java.version} 76 | false 77 | 78 | 79 | 80 | org.springframework.boot 81 | spring-boot-maven-plugin 82 | 83 | 84 | 85 | org.springframework.boot 86 | spring-boot-configuration-processor 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | echo "🚀 Go to https://astra.datastax.com/org/?create_service_account 2 | If you have not created a service account for your org click Actions -> Add Service Account. Then, click the copy icon and paste your service account credentials here: " 3 | read -r SERVICE_ACCOUNT 4 | export SERVICE_ACCOUNT="${SERVICE_ACCOUNT}" 5 | 6 | echo "Getting your Astra DevOps API token..." 7 | DEVOPS_TOKEN=$(curl -s --request POST \ 8 | --url "https://api.astra.datastax.com/v2/authenticateServiceAccount" \ 9 | --header 'content-type: application/json' \ 10 | --data "$SERVICE_ACCOUNT" | jq -r '.token') 11 | 12 | echo "Getting databases..." 13 | DBS=$(curl -s --request GET \ 14 | --url "https://api.astra.datastax.com/v2/databases?include=nonterminated&provider=all&limit=25" \ 15 | --header "authorization: Bearer ${DEVOPS_TOKEN}" \ 16 | --header 'content-type: application/json') 17 | 18 | # TODO: Allow the user to select the DB 19 | NUM_DBS=$(echo "${DBS}" | jq -c 'length') 20 | FIRST_DB_ID=$(echo "${DBS}" | jq -c '.[0].id') 21 | FIRST_DB_REGION=$(echo "${DBS}" | jq -c '.[0].info.region') 22 | FIRST_DB_USER=$(echo "${DBS}" | jq -c '.[0].info.user') 23 | 24 | # TODO: Allow the user to select a keyspace 25 | FIRST_DB_KEYSPACE=$(echo "${DBS}" | jq -c '.[0].info.keyspaces[0]') 26 | FIRST_DB_SECURE_BUNDLE_URL=$(echo "${DBS}" | jq -c '.[0].info.datacenters[0].secureBundleUrl') 27 | 28 | export ASTRA_SECURE_BUNDLE_URL=${FIRST_DB_SECURE_BUNDLE_URL} 29 | gp env ASTRA_SECURE_BUNDLE_URL=${FIRST_DB_SECURE_BUNDLE_URL} &>/dev/null 30 | 31 | # Download the secure connect bundle 32 | curl -s -L $(echo $FIRST_DB_SECURE_BUNDLE_URL | sed "s/\"//g") -o astra-creds.zip 33 | 34 | export ASTRA_DB_BUNDLE="astra-creds.zip" 35 | gp env ASTRA_DB_BUNDLE="astra-creds.zip" &>/dev/null 36 | 37 | export ASTRA_DB_USERNAME=$(echo ${FIRST_DB_USER} | sed "s/\"//g") 38 | gp env ASTRA_DB_USERNAME=$(echo ${FIRST_DB_USER} | sed "s/\"//g") &>/dev/null 39 | 40 | export ASTRA_DB_KEYSPACE=$(echo ${FIRST_DB_KEYSPACE} | sed "s/\"//g") 41 | gp env ASTRA_DB_KEYSPACE=$(echo ${FIRST_DB_KEYSPACE} | sed "s/\"//g") &>/dev/null 42 | 43 | export ASTRA_DB_ID=$(echo ${FIRST_DB_ID} | sed "s/\"//g") 44 | gp env ASTRA_DB_ID=$(echo ${FIRST_DB_ID} | sed "s/\"//g") &>/dev/null 45 | 46 | export ASTRA_DB_REGION=$(echo ${FIRST_DB_REGION} | sed "s/\"//g") 47 | gp env ASTRA_DB_REGION=$(echo ${FIRST_DB_REGION} | sed "s/\"//g") &>/dev/null 48 | 49 | 50 | echo "What is your Astra DB password? 🔒" 51 | read -s ASTRA_DB_PASSWORD 52 | export ASTRA_DB_PASSWORD=${ASTRA_DB_PASSWORD} 53 | gp env ASTRA_DB_PASSWORD=${ASTRA_DB_PASSWORD} &>/dev/null 54 | 55 | echo "You're all set 👌" 56 | -------------------------------------------------------------------------------- /src/main/java/com/datastax/examples/DataStaxAstraProperties.java: -------------------------------------------------------------------------------- 1 | package com.datastax.examples; 2 | 3 | import java.io.File; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import org.springframework.boot.context.properties.ConfigurationProperties; 7 | 8 | @ConfigurationProperties(prefix = "datastax.astra") 9 | @Getter 10 | @Setter 11 | public class DataStaxAstraProperties { 12 | 13 | private File secureConnectBundle; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/datastax/examples/SpringDataCassandraApplication.java: -------------------------------------------------------------------------------- 1 | package com.datastax.examples; 2 | 3 | import java.nio.file.Path; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.autoconfigure.cassandra.CqlSessionBuilderCustomizer; 7 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | @SpringBootApplication 11 | @EnableConfigurationProperties(DataStaxAstraProperties.class) 12 | public class SpringDataCassandraApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(SpringDataCassandraApplication.class, args); 16 | } 17 | 18 | @Bean 19 | public CqlSessionBuilderCustomizer sessionBuilderCustomizer(DataStaxAstraProperties astraProperties) { 20 | Path bundle = astraProperties.getSecureConnectBundle().toPath(); 21 | return builder -> builder.withCloudSecureConnectBundle(bundle); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/datastax/examples/order/Order.java: -------------------------------------------------------------------------------- 1 | package com.datastax.examples.order; 2 | 3 | import lombok.Data; 4 | import org.springframework.data.cassandra.core.mapping.*; 5 | 6 | import java.io.Serializable; 7 | import java.time.Instant; 8 | 9 | @Table(value = "starter_orders") 10 | @Data 11 | public class Order implements Serializable { 12 | 13 | @PrimaryKey 14 | private OrderPrimaryKey key; 15 | 16 | @Column("product_quantity") 17 | @CassandraType(type = CassandraType.Name.INT) 18 | private Integer productQuantity; 19 | 20 | @Column("product_name") 21 | @CassandraType(type = CassandraType.Name.TEXT) 22 | private String productName; 23 | 24 | @CassandraType(type = CassandraType.Name.DECIMAL) 25 | @Column("product_price") 26 | private Float productPrice; 27 | 28 | @CassandraType(type = CassandraType.Name.TIMESTAMP) 29 | @Column("added_to_order_at") 30 | private Instant addedToOrderTimestamp; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/datastax/examples/order/OrderController.java: -------------------------------------------------------------------------------- 1 | package com.datastax.examples.order; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.data.rest.webmvc.BasePathAwareController; 5 | import org.springframework.web.bind.annotation.*; 6 | import org.springframework.web.servlet.ModelAndView; 7 | 8 | import java.util.List; 9 | import java.util.UUID; 10 | 11 | @RestController 12 | public class OrderController { 13 | 14 | @Autowired 15 | private OrderRepository orderRepository; 16 | 17 | @RequestMapping(value = "/", method = RequestMethod.GET) 18 | public ModelAndView root() { 19 | return new ModelAndView("redirect:/swagger-ui.html"); 20 | } 21 | 22 | // CREATE 23 | 24 | @PostMapping("orders") 25 | public Order createOrder(@RequestBody Order order) { 26 | return orderRepository.save(order); 27 | } 28 | 29 | // UPDATE 30 | 31 | @PutMapping("orders/{oid}/{pid}") 32 | public Order updateOrder(@PathVariable("oid") UUID oid, @PathVariable("pid") UUID pid, @RequestBody Order order) { 33 | order.getKey().setOrderId(oid); 34 | order.getKey().setProductId(pid); 35 | return orderRepository.save(order); 36 | } 37 | 38 | // DELETE 39 | 40 | @DeleteMapping("orders/{oid}/{pid}") 41 | public void deleteOrder(@PathVariable("oid") UUID oid, @PathVariable("pid") UUID pid) { 42 | orderRepository.deleteByKeyOrderIdAndKeyProductId(oid, pid); 43 | } 44 | 45 | @DeleteMapping("orders/{oid}") 46 | public void deleteOrders(@PathVariable("oid") UUID oid) { 47 | orderRepository.deleteByKeyOrderId(oid); 48 | } 49 | 50 | // FIND 51 | 52 | @GetMapping("orders/{oid}/{pid}") 53 | public ProductNameAndPrice findOrder(@PathVariable("oid") UUID oid, @PathVariable("pid") UUID pid) { 54 | return orderRepository.findByKeyOrderIdAndKeyProductId(oid, pid); 55 | } 56 | 57 | @GetMapping("orders/{oid}") 58 | public List findOrders(@PathVariable("oid") UUID oid) { 59 | return orderRepository.findByKeyOrderId(oid); 60 | } 61 | 62 | @GetMapping("orders") 63 | public List findAll() { 64 | return orderRepository.findAllProjectedBy(); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/datastax/examples/order/OrderPrimaryKey.java: -------------------------------------------------------------------------------- 1 | package com.datastax.examples.order; 2 | 3 | import lombok.Data; 4 | import org.springframework.data.cassandra.core.cql.PrimaryKeyType; 5 | import org.springframework.data.cassandra.core.mapping.PrimaryKeyClass; 6 | import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn; 7 | 8 | import java.io.Serializable; 9 | import java.util.UUID; 10 | 11 | @PrimaryKeyClass 12 | @Data 13 | public class OrderPrimaryKey implements Serializable { 14 | 15 | @PrimaryKeyColumn(name = "order_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED) 16 | private UUID orderId; 17 | 18 | @PrimaryKeyColumn(name = "product_id", ordinal = 1, type = PrimaryKeyType.CLUSTERED) 19 | private UUID productId; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/datastax/examples/order/OrderRepository.java: -------------------------------------------------------------------------------- 1 | package com.datastax.examples.order; 2 | 3 | import org.springframework.data.cassandra.repository.CassandraRepository; 4 | import org.springframework.data.rest.core.annotation.RestResource; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | import java.util.UUID; 9 | 10 | @Repository 11 | @RestResource(exported = false) 12 | public interface OrderRepository extends CassandraRepository { 13 | 14 | // DELETE 15 | 16 | void deleteByKeyOrderId(UUID orderId); 17 | 18 | void deleteByKeyOrderIdAndKeyProductId(UUID orderId, UUID productId); 19 | 20 | // FIND (all projected) 21 | 22 | ProductNameAndPrice findByKeyOrderIdAndKeyProductId(UUID orderId, UUID productId); 23 | 24 | List findByKeyOrderId(UUID orderId); 25 | 26 | List findAllProjectedBy(); 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/main/java/com/datastax/examples/order/ProductNameAndPrice.java: -------------------------------------------------------------------------------- 1 | package com.datastax.examples.order; 2 | 3 | import org.springframework.data.rest.core.config.Projection; 4 | 5 | @Projection(name = "product-name-and-price", types = { Order.class }) 6 | public interface ProductNameAndPrice { 7 | String getProductName(); 8 | Float getProductPrice(); 9 | } 10 | -------------------------------------------------------------------------------- /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 | ] } -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: spring-data-service 4 | cassandra: 5 | username: token 6 | password: ${ASTRA_DB_PASSWORD} 7 | keyspace-name: ${ASTRA_DB_KEYSPACE} 8 | schema-action: CREATE_IF_NOT_EXISTS 9 | request: 10 | timeout: 10s 11 | connection: 12 | connect-timeout: 10s 13 | init-query-timeout: 10s 14 | 15 | server.port: 8081 16 | 17 | springdoc.swagger-ui.path: /swagger-ui.html 18 | 19 | datastax.astra: 20 | secure-connect-bundle: ${ASTRA_DB_BUNDLE} -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{HH:mm:ss.SSS} %magenta(%-5level) %cyan(%-50logger) : %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | --------------------------------------------------------------------------------