Skip to content

Commit b42ecd5

Browse files
committed
added oprtional parameters and examples, description + readme changes + api endpoints refactoring similar to python
1 parent c84ef25 commit b42ecd5

File tree

7 files changed

+183
-94
lines changed

7 files changed

+183
-94
lines changed

README.md

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
Often, the first step developers take after creating their database is to create a REST API that can perform Create, Read, Update, and Delete (CRUD) operations for that database. This repo is designed to teach you and give you a starter project (in Java using Spring Data) to generate such a REST API. After you have installed the travel-sample bucket in your database, you can run this application which is a REST API with Swagger documentation so that you can learn:
66

77
1. How to create, read, update, and delete documents using Key-Value[ operations](https://docs.couchbase.com/java-sdk/current/howtos/kv-operations.html) (KV operations). KV operations are unique to Couchbase and provide super fast (think microseconds) queries.
8-
2. How to write simple parametrized [N1QL queries](https://docs.couchbase.com/java-sdk/current/howtos/n1ql-queries-with-sdk.html) using the built-in travel-sample bucket.
8+
2. How to write simple parametrized [SQL++ Queries](https://docs.couchbase.com/java-sdk/current/howtos/n1ql-queries-with-sdk.html) using the built-in travel-sample bucket.
99

1010
Full documentation for the tutorial can be found on the [Couchbase Developer Portal](https://developer.couchbase.com/tutorial-quickstart-spring-data-java/).
1111

@@ -17,11 +17,10 @@ To run this prebuilt project, you will need:
1717
- To run this tutorial using a self-managed Couchbase cluster, please refer to the [appendix](#running-self-managed-couchbase-cluster).
1818
- [Java 17 or higher](https://www.oracle.com/java/technologies/javase-downloads.html)
1919
- Ensure that the Java version is compatible with the Couchbase SDK.
20-
- Loading Travel Sample Bucket
21-
If travel-sample is not loaded in your Capella cluster, you can load it by following the instructions for your Capella Cluster:
22-
- [Load travel-sample bucket in Couchbase Capella](https://docs.couchbase.com/cloud/clusters/data-service/import-data-documents.html#import-sample-data)
23-
- Gradle
24-
- You can install Gradle using the [instructions](https://gradle.org/install/).
20+
- [Loading Travel Sample Bucket](https://docs.couchbase.com/cloud/clusters/data-service/import-data-documents.html#import-sample-data)
21+
- If `travel-sample` is not loaded in your Capella cluster, you can load it by following the instructions for your Capella Cluster
22+
- [Gradle 8.6 or higher](https://gradle.org/releases/)
23+
2524
## App Setup
2625

2726
We will walk through the different steps required to get the application running.
@@ -55,22 +54,33 @@ Specifically, you need to do the following:
5554

5655
All configuration for communication with the database is read from the environment variables. We have provided a convenience feature in this quickstart to read the environment variables from a local file, `application.properties` in the `src/main/resources` folder.
5756

57+
You can also set the environment variables directly in your environment such as:
58+
59+
```sh
60+
export DB_CONN_STR=couchbases://<cluster-url>
61+
export DB_USERNAME=Administrator
62+
export DB_PASSWORD=password
63+
```
64+
65+
The `application.properties` file should look like this:
66+
5867
```properties
59-
server.use-forward-headers=true
6068
server.forward-headers-strategy=framework
6169
spring.couchbase.bootstrap-hosts=DB_CONN_STR
6270
spring.couchbase.bucket.name=travel-sample
6371
spring.couchbase.bucket.user=DB_USERNAME
6472
spring.couchbase.bucket.password=DB_PASSWORD
6573
spring.couchbase.scope.name=inventory
66-
spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER
6774
```
68-
Instead of DB_CONN_STR, DB_USERNAME, and DB_PASSWORD, you should replace these with the connection string, username, and password for your Couchbase cluster. The connection string is the URL of your cluster. For example, if you are using Capella, the connection string will look like `couchbases://cb.jnym5s9gv4ealbe.cloud.couchbase.com`. If you are using a local cluster, the connection string will be `localhost`.
6975

70-
> Note: The connection string expects the `couchbases://` or `couchbase://` part.
76+
You can specify the connection string, username, and password using environment variables. The application will read these environment variables and use them to connect to the database.
77+
78+
Additionally, you can specify the connection string, username, and password directly in the `application.properties` file.
7179

80+
> Note: The connection string expects the `couchbases://` or `couchbase://` part.
7281
7382
## Cluster Connection Configuration
83+
7484
Spring Data couchbase connector can be configured by providing a `@Configuration` [bean](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-definition) that extends [`AbstractCouchbaseConfiguration`](https://docs.spring.io/spring-data/couchbase/docs/current/api/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.html).
7585

7686
```java
@@ -144,7 +154,8 @@ public class CouchbaseConfiguration extends AbstractCouchbaseConfiguration {
144154

145155
}
146156
```
147-
> *from config/CouchbaseConfiguration.java*
157+
158+
> _from config/CouchbaseConfiguration.java_
148159
149160
This default configuration assumes that you have a locally running Couchbae server and uses standard administrative login and password for demonstration purpose.
150161
Applications deployed to production or staging environments should use less privileged credentials created using [Role-Based Access Control](https://docs.couchbase.com/go-sdk/current/concept-docs/rbac.html).
@@ -212,10 +223,11 @@ For this quickstart, we use three collections, `airport`, `airline` and `routes`
212223

213224
If you would like to add another entity to the APIs, these are the steps to follow:
214225

215-
- Create the new entity (collection) in the Couchbase bucket. You can create the collection using the [SDK](https://docs.couchbase.com/sdk-api/couchbase-java-client-3.5.2/com/couchbase/client/java/Collection.html#createScope-java.lang.String-) or via the [Couchbase Server interface](https://docs.couchbase.com/cloud/n1ql/n1ql-language-reference/createcollection.html).
216-
- Define the routes in a new file in the `controllers` folder similar to the existing routes like `AirportController.java`.
217-
- Define the service in a new file in the `services` folder similar to the existing services like `AirportService.java`.
218-
- Define the repository in a new file in the `repositories` folder similar to the existing repositories like `AirportRepository.java`.
226+
- You can create the collection using the [SDK](https://docs.couchbase.com/sdk-api/couchbase-java-client-3.5.2/com/couchbase/client/java/Collection.html#createScope-java.lang.String-) or via the [Couchbase Server interface](https://docs.couchbase.com/cloud/n1ql/n1ql-language-reference/createcollection.html).
227+
- Create a new entity class in the `models` package similar to the existing entity classes like `Airport.java`.
228+
- Define the controller in a new file in the `controllers` folder similar to the existing classes like `AirportController.java`.
229+
- Define the service in a new file in the `services` folder similar to the existing classes like `AirportService.java`.
230+
- Define the repository in a new file in the `repositories` folder similar to the existing classes like `AirportRepository.java`.
219231

220232
### Running Self-Managed Couchbase Cluster
221233

src/main/java/org/couchbase/quickstart/springdata/controller/AirlineController.java

Lines changed: 54 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
import java.util.Optional;
44

5-
import jakarta.validation.Valid;
6-
75
import org.couchbase.quickstart.springdata.models.Airline;
86
import org.couchbase.quickstart.springdata.services.AirlineService;
97
import org.springframework.dao.DataRetrievalFailureException;
@@ -25,6 +23,10 @@
2523
import com.couchbase.client.core.error.DocumentNotFoundException;
2624

2725
import io.swagger.v3.oas.annotations.Operation;
26+
import io.swagger.v3.oas.annotations.Parameter;
27+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
28+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
29+
import jakarta.validation.Valid;
2830
import lombok.extern.slf4j.Slf4j;
2931

3032
@Slf4j
@@ -43,8 +45,14 @@ public AirlineController(AirlineService airlineService) {
4345
private static final String DOCUMENT_NOT_FOUND = "Document not found";
4446
private static final String DOCUMENT_ALREADY_EXISTS = "Document already exists";
4547

46-
@Operation(summary = "Get an airline by ID")
4748
@GetMapping("/{id}")
49+
@Operation(summary = "Get an airline by ID", description = "Get Airline by specified ID.\n\nThis provides an example of using Key Value operations in Couchbase to retrieve a document with a specified ID. \n\n Code: [`controllers/AirlineController.java`](https://github.com/couchbase-examples/java-springdata-quickstart/blob/main/src/main/java/org/couchbase/quickstart/springdata/controllers/AirlineController.java) \n File: `AirlineController.java` \n Method: `getAirline`", tags = {
50+
"Airline" })
51+
@ApiResponses(value = {
52+
@ApiResponse(responseCode = "200", description = "Airline found"),
53+
@ApiResponse(responseCode = "404", description = "Airline not found"),
54+
@ApiResponse(responseCode = "500", description = "Internal server error") })
55+
@Parameter(name = "id", description = "Airline ID", required = true, example = "airline_10")
4856
public ResponseEntity<Airline> getAirline(@PathVariable String id) {
4957
try {
5058
Optional<Airline> airline = airlineService.getAirlineById(id);
@@ -59,8 +67,14 @@ public ResponseEntity<Airline> getAirline(@PathVariable String id) {
5967
}
6068
}
6169

62-
@Operation(summary = "Create an airline")
6370
@PostMapping("/{id}")
71+
@Operation(summary = "Create an airline", description = "Create an airline with the specified ID.\n\nThis provides an example of using Key Value operations in Couchbase to create a document with a specified ID. \n\n Code: [`controllers/AirlineController.java`](https://github.com/couchbase-examples/java-springdata-quickstart/blob/main/src/main/java/org/couchbase/quickstart/springdata/controllers/AirlineController.java) \n File: `AirlineController.java` \n Method: `createAirline`", tags = {
72+
"Airline" })
73+
@ApiResponses(value = {
74+
@ApiResponse(responseCode = "201", description = "Airline created"),
75+
@ApiResponse(responseCode = "409", description = "Airline already exists"),
76+
@ApiResponse(responseCode = "500", description = "Internal server error") })
77+
@Parameter(name = "id", description = "Airline ID", required = true, example = "airline_10")
6478
public ResponseEntity<Airline> createAirline(@Valid @RequestBody Airline airline) {
6579
try {
6680
Airline newAirline = airlineService.createAirline(airline);
@@ -74,8 +88,14 @@ public ResponseEntity<Airline> createAirline(@Valid @RequestBody Airline airline
7488
}
7589
}
7690

77-
@Operation(summary = "Update an airline")
7891
@PutMapping("/{id}")
92+
@Operation(summary = "Update an airline", description = "Update an airline with the specified ID.\n\nThis provides an example of using Key Value operations in Couchbase to update a document with a specified ID. \n\n Code: [`controllers/AirlineController.java`](https://github.com/couchbase-examples/java-springdata-quickstart/blob/main/src/main/java/org/couchbase/quickstart/springdata/controllers/AirlineController.java) \n File: `AirlineController.java` \n Method: `updateAirline`", tags = {
93+
"Airline" })
94+
@ApiResponses(value = {
95+
@ApiResponse(responseCode = "200", description = "Airline updated"),
96+
@ApiResponse(responseCode = "404", description = "Airline not found"),
97+
@ApiResponse(responseCode = "500", description = "Internal server error") })
98+
@Parameter(name = "id", description = "Airline ID", required = true, example = "airline_10")
7999
public ResponseEntity<Airline> updateAirline(@PathVariable String id, @Valid @RequestBody Airline airline) {
80100
try {
81101
Airline updatedAirline = airlineService.updateAirline(id, airline);
@@ -93,8 +113,14 @@ public ResponseEntity<Airline> updateAirline(@PathVariable String id, @Valid @Re
93113
}
94114
}
95115

96-
@Operation(summary = "Delete an airline")
97116
@DeleteMapping("/{id}")
117+
@Operation(summary = "Delete an airline", description = "Delete an airline with the specified ID.\n\nThis provides an example of using Key Value operations in Couchbase to delete a document with a specified ID. \n\n Code: [`controllers/AirlineController.java`](https://github.com/couchbase-examples/java-springdata-quickstart/blob/main/src/main/java/org/couchbase/quickstart/springdata/controllers/AirlineController.java) \n File: `AirlineController.java` \n Method: `deleteAirline`", tags = {
118+
"Airline" })
119+
@ApiResponses(value = {
120+
@ApiResponse(responseCode = "204", description = "Airline deleted"),
121+
@ApiResponse(responseCode = "404", description = "Airline not found"),
122+
@ApiResponse(responseCode = "500", description = "Internal server error") })
123+
@Parameter(name = "id", description = "Airline ID", required = true, example = "airline_10")
98124
public ResponseEntity<Void> deleteAirline(@PathVariable String id) {
99125
try {
100126
airlineService.deleteAirline(id);
@@ -108,42 +134,42 @@ public ResponseEntity<Void> deleteAirline(@PathVariable String id) {
108134
}
109135
}
110136

111-
@Operation(summary = "List all airlines")
112137
@GetMapping("/list")
113-
public ResponseEntity<Page<Airline>> listAirlines(@RequestParam(defaultValue = "0") int page,
114-
@RequestParam(defaultValue = "10") int size) {
115-
try {
116-
Page<Airline> airlines = airlineService.getAllAirlines(PageRequest.of(page, size));
117-
return new ResponseEntity<>(airlines, HttpStatus.OK);
118-
} catch (Exception e) {
119-
log.error(INTERNAL_SERVER_ERROR, e);
120-
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
121-
}
122-
}
123-
124-
@Operation(summary = "List all airlines by country")
125-
@GetMapping("/country/{country}")
138+
@Operation(summary = "List all airlines by country", description = "List all airlines by country.\n\nThis provides an example of using N1QL queries in Couchbase to retrieve documents with a specified field value. \n\n Code: [`controllers/AirlineController.java`](https://github.com/couchbase-examples/java-springdata-quickstart/blob/main/src/main/java/org/couchbase/quickstart/springdata/controllers/AirlineController.java) \n File: `AirlineController.java` \n Method: `listAirlinesByCountry`", tags = {
139+
"Airline" })
140+
@ApiResponses(value = {
141+
@ApiResponse(responseCode = "200", description = "Airlines found"),
142+
@ApiResponse(responseCode = "500", description = "Internal server error") })
143+
@Parameter(name = "country", description = "Country", required = false, example = "United States")
126144
public ResponseEntity<Page<Airline>> listAirlinesByCountry(
127-
@PathVariable String country,
145+
@RequestParam(required = false) String country,
128146
@RequestParam(defaultValue = "0") int page,
129147
@RequestParam(defaultValue = "10") int size) {
130148
try {
131-
132-
Page<Airline> airlines = airlineService.findByCountry(country, PageRequest.of(page, size));
133-
return new ResponseEntity<>(airlines, HttpStatus.OK);
149+
if (country == null || country.isEmpty()) {
150+
Page<Airline> airlines = airlineService.getAllAirlines(PageRequest.of(page, size));
151+
return new ResponseEntity<>(airlines, HttpStatus.OK);
152+
} else {
153+
Page<Airline> airlines = airlineService.findByCountry(country, PageRequest.of(page, size));
154+
return new ResponseEntity<>(airlines, HttpStatus.OK);
155+
}
134156
} catch (Exception e) {
135157
log.error(INTERNAL_SERVER_ERROR, e);
136158
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
137159
}
138160
}
139161

140-
@Operation(summary = "List all airlines by desination airport")
141-
@GetMapping("/destination/{destinationAirport}")
162+
@GetMapping("/to-airport")
163+
@Operation(summary = "List all airlines by desination airport", description = "List all airlines by destination airport.\n\nThis provides an example of using N1QL queries in Couchbase to retrieve documents with a specified field value. \n\n Code: [`controllers/AirlineController.java`](https://github.com/couchbase-examples/java-springdata-quickstart/blob/main/src/main/java/org/couchbase/quickstart/springdata/controllers/AirlineController.java) \n File: `AirlineController.java` \n Method: `listAirlinesByDestinationAirport`", tags = {
164+
"Airline" })
165+
@ApiResponses(value = {
166+
@ApiResponse(responseCode = "200", description = "Airlines found"),
167+
@ApiResponse(responseCode = "500", description = "Internal server error") })
168+
@Parameter(name = "destinationAirport", description = "Destination Airport", required = false, example = "SFO")
142169
public ResponseEntity<Page<Airline>> listAirlinesByDestinationAirport(
143-
@PathVariable String destinationAirport,
170+
@RequestParam(required = false) String destinationAirport,
144171
@RequestParam(defaultValue = "0") int page,
145172
@RequestParam(defaultValue = "10") int size) {
146-
147173
try {
148174
Page<Airline> airlines = airlineService.findByDestinationAirport(destinationAirport,
149175
PageRequest.of(page, size));

0 commit comments

Comments
 (0)