Couchbase is an open-source, NoSQL, document database. It allows to access, index, and query JSON documents while taking advantage of integrated distributed caching for high performance data access.
Developers can write applications to Couchbase using different languages (Java, Go, .NET, Node, PHP, Python, C) multiple SDKs. This blog will show how you can easily create a CRUD application using Java SDK for Couchbase.
REST with Couchbase
The application will use curl
to issue REST commands to a JAX-RS endpoint deployed on WildFly. These commands will then perform CRUD operations on travel-sample
bucket in Couchbase. N1QL (SQL query language for JSON) will be used to communicate with Couchbase to retrieve results. Both the “builder pattern” and raw N1QL commands will be used.
TL;DR
Complete source code and instructions for the sample are available at github.com/arun-gupta/couchbase-javaee.
Lets get started!
Run Couchbase Server
Couchbase server can be easily downloaded from Couchbase Server Downloads page. In a containerized world, its a lot easier to fire up a Couchbase server using Docker.
If Docker is configured on your machine then the easiest way is to use Docker Compose for Couchbase:
1
2
3
4
5
6
7
8
9
10
11
12
|
mycouchbase:
name: mycouchbase
image: couchbase/server
volumes:
- ~/couchbase:/opt/couchbase/var
ports:
- 8091:8091
- 8092:8092
- 8093:8093
- 11210:11210
|
Starting up the application server shows:
1
2
3
4
|
> docker-compose up -d
Creating couchbaseserver_mycouchbase_1
|
And then the logs can be seen as:
1
2
3
4
5
|
> docker-compose logs
Attaching to couchbaseserver_mycouchbase_1
mycouchbase_1 | Starting Couchbase Server -- Web UI available at http://<ip>:8091
|
The database needs to be configured and is explained at Configure Couchbase Server. Make sure to install travel-sample
bucket.
Deploy the Java EE Application on WildFly
- Download WildFly 9.0.2 , unzip, and start WildFly application server as
./wildfly-9.0.0.Final/bin/standalone.sh
. - Git clone the repo:
git clone https://github.com/arun-gupta/couchbase-javaee.git
- Change directory
cd couchbase-javaee
- Deploy the application to WildFly:
mvn install -Pwildfly
.
The application uses Java SDK for Couchbase by importing the following Maven coordinates:
1
2
3
4
5
6
7
|
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>java-client</artifactId>
<version>2.2.1</version>
</dependency>
|
Invoke the REST Endpoints Using cURL
GET Airline resources (limit to 10)
Lets query the database to list 10 Airline resources.
Request
1
2
3
4
5
6
7
8
9
10
11
12
13
|
~ > curl -v http://localhost:8080/couchbase-javaee/resources/airline
* Hostname was NOT found in DNS cache
* Trying ::1...
* connect to ::1 port 8080 failed: Connection refused
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /couchbase-javaee/resources/airline HTTP/1.1
> User-Agent: curl/7.37.1
> Host: localhost:8080
> Accept: */*
>
|
Response
1
2
3
4
5
6
7
8
9
10
11
12
13
|
< HTTP/1.1 200 OK
< Connection: keep-alive
< X-Powered-By: Undertow/1
* Server WildFly/9 is not blacklisted
< Server: WildFly/9
< Content-Type: application/octet-stream
< Content-Length: 1415
< Date: Wed, 18 Nov 2015 21:19:15 GMT
<
* Connection #0 to host localhost left intact
[{"travel-sample":{"country":"France","iata":"SB","callsign":"AIRCALIN","name":"Air Caledonie International","icao":"ACI","id":139,"type":"airline"}}, {"travel-sample":{"country":"United States","iata":"WQ","callsign":null,"name":"PanAm World Airways","icao":"PQW","id":13633,"type":"airline"}}, {"travel-sample":{"country":"United Kingdom","iata":"BA","callsign":"SPEEDBIRD","name":"British Airways","icao":"BAW","id":1355,"type":"airline"}}, {"travel-sample":{"country":"United States","iata":"FL","callsign":"CITRUS","name":"AirTran Airways","icao":"TRS","id":1316,"type":"airline"}}, {"travel-sample":{"country":"United States","iata":"-+","callsign":null,"name":"U.S. Air","icao":"--+","id":13391,"type":"airline"}}, {"travel-sample":{"country":"United States","iata":"Q5","callsign":"MILE-AIR","name":"40-Mile Air","icao":"MLA","id":10,"type":"airline"}}, {"travel-sample":{"country":"France","iata":"AF","callsign":"AIRFRANS","name":"Air France","icao":"AFR","id":137,"type":"airline"}}, {"travel-sample":{"country":"United States","iata":"K5","callsign":"SASQUATCH","name":"SeaPort Airlines","icao":"SQH","id":10765,"type":"airline"}}, {"travel-sample":{"country":"France","iata":"A5","callsign":"AIRLINAIR","name":"Airlinair","icao":"RLA","id":1203,"type":"airline"}}, {"travel-sample":{"country":"United Kingdom","iata":"5W","callsign":"FLYSTAR","name":"Astraeus","icao":"AEU","id":112,"type":"airline"}}]
|
1
2
3
4
5
6
|
N1qlQuery query = N1qlQuery
.simple(select("*")
.from(i(database.getBucket().name()))
.limit(10));
|
1
2
3
|
SELECT * FROM `travel-sample` LIMIT 10
|
GET one Airline resource
Use id
attribute to query a single Airline resource
Request
1
2
3
4
5
6
7
8
9
10
11
12
13
|
~ > curl -v http://localhost:8080/couchbase-javaee/resources/airline/139
* Hostname was NOT found in DNS cache
* Trying ::1...
* connect to ::1 port 8080 failed: Connection refused
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /couchbase-javaee/resources/airline/139 HTTP/1.1
> User-Agent: curl/7.37.1
> Host: localhost:8080
> Accept: */*
>
|
Response
1
2
3
4
5
6
7
8
9
10
11
12
13
|
< HTTP/1.1 200 OK
< Connection: keep-alive
< X-Powered-By: Undertow/1
* Server WildFly/9 is not blacklisted
< Server: WildFly/9
< Content-Type: application/octet-stream
< Content-Length: 148
< Date: Wed, 18 Nov 2015 21:23:34 GMT
<
* Connection #0 to host localhost left intact
{"travel-sample":{"country":"France","iata":"SB","callsign":"AIRCALIN","name":"Air Caledonie International","icao":"ACI","id":139,"type":"airline"}}
|
POST a new Airline resource
Learn how to run N1QL queries from the CLI using CBQ tool and verify the existing sample data:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
bin > ./cbq -engine=http://192.168.99.100:8093
Couchbase query shell connected to http://192.168.99.100:8093/ . Type Ctrl-D to exit.
cbq> select * from `travel-sample` where name="Airlinair" limit 10;
{
"requestID": "ce2de67b-2c05-47df-afbe-343cb7409d2b",
"signature": {
"*": "*"
},
"results": [
{
"travel-sample": {
"callsign": "AIRLINAIR",
"country": "France",
"iata": "A5",
"icao": "RLA",
"id": 1203,
"name": "Airlinair",
"type": "airline"
}
}
],
"status": "success",
"metrics": {
"elapsedTime": "3.418285894s",
"executionTime": "3.418232688s",
"resultCount": 1,
"resultSize": 294
}
}
|
This query retrieve documents where airline’s name is Airlinair
. The count is shown in metrics.resultCount
.
Create a new document using POST.
Request
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
~ > curl -v -H "Content-Type: application/json" -X POST -d '{"country":"France","iata":"A5","callsign":"AIRLINAIR","name":"Airlinair","icao":"RLA","type":"airline"}' http://localhost:8080/couchbase-javaee/resources/airline
* Hostname was NOT found in DNS cache
* Trying ::1...
* connect to ::1 port 8080 failed: Connection refused
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /couchbase-javaee/resources/airline HTTP/1.1
> User-Agent: curl/7.37.1
> Host: localhost:8080
> Accept: */*
> Content-Type: application/json
> Content-Length: 104
>
|
Response
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
* upload completely sent off: 104 out of 104 bytes
< HTTP/1.1 200 OK
< Connection: keep-alive
< X-Powered-By: Undertow/1
* Server WildFly/9 is not blacklisted
< Server: WildFly/9
< Content-Type: application/octet-stream
< Content-Length: 117
< Date: Wed, 18 Nov 2015 21:42:51 GMT
<
* Connection #0 to host localhost left intact
{"country":"France","iata":"A5","callsign":"AIRLINAIR","name":"Airlinair","icao":"RLA","id":"19810","type":"airline"}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
cbq> select * from `travel-sample` where name="Airlinair" limit 10;
{
"requestID": "5e79031a-f7ee-4cc9-8c87-4e3b7484f09f",
"signature": {
"*": "*"
},
"results": [
{
"travel-sample": {
"callsign": "AIRLINAIR",
"country": "France",
"iata": "A5",
"icao": "RLA",
"id": 1203,
"name": "Airlinair",
"type": "airline"
}
},
{
"travel-sample": {
"callsign": "AIRLINAIR",
"country": "France",
"iata": "A5",
"icao": "RLA",
"id": "19810",
"name": "Airlinair",
"type": "airline"
}
}
],
"status": "success",
"metrics": {
"elapsedTime": "3.342391947s",
"executionTime": "3.342343455s",
"resultCount": 2,
"resultSize": 591
}
}
|
PUT an existing Airline resource
Update an existing resource using HTTP POST.
The data model for travel-sample
bucket requires to include “id” attribute in the payload and in the URI as well.
Request
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
~ > curl -v -H "Content-Type: application/json" -X PUT -d '{"country":"France","iata":"A5","callsign":"AIRLINAIR","name":"Airlin Air","icao":"RLA","type":"airline","id": "19810"}' http://localhost:8080/couchbase-javaee/resources/airline/19810
* Hostname was NOT found in DNS cache
* Trying ::1...
* connect to ::1 port 8080 failed: Connection refused
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> PUT /couchbase-javaee/resources/airline/19810 HTTP/1.1
> User-Agent: curl/7.37.1
> Host: localhost:8080
> Accept: */*
> Content-Type: application/json
> Content-Length: 118
>
* upload completely sent off: 118 out of 118 bytes
|
Response
1
2
3
4
5
6
7
8
9
10
11
12
13
|
< HTTP/1.1 200 OK
< Connection: keep-alive
< X-Powered-By: Undertow/1
* Server WildFly/9 is not blacklisted
< Server: WildFly/9
< Content-Type: application/octet-stream
< Content-Length: 117
< Date: Wed, 18 Nov 2015 21:46:16 GMT
<
* Connection #0 to host localhost left intact
{"country":"France","iata":"A5","callsign":"AIRLINAIR","name":"Airlin Air","icao":"RLA","id":"19810","type":"airline"}
|
Querying for Airlinair
gives:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
cbq> select * from `travel-sample` where name="Airlinair" limit 10;
{
"requestID": "a8d72427-9f4b-49ab-a77a-17cd99cdce5f",
"signature": {
"*": "*"
},
"results": [
{
"travel-sample": {
"callsign": "AIRLINAIR",
"country": "France",
"iata": "A5",
"icao": "RLA",
"id": 1203,
"name": "Airlinair",
"type": "airline"
}
}
],
"status": "success",
"metrics": {
"elapsedTime": "3.372603693s",
"executionTime": "3.37256091s",
"resultCount": 1,
"resultSize": 294
}
}
|
So the previously added record is now updated and thus does not appear in query results. Querying for Airlin Air
gives:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
cbq> select * from `travel-sample` where name="Airlin Air" limit 10;
{
"requestID": "a3797a73-d879-4ca1-be90-e07179aae118",
"signature": {
"*": "*"
},
"results": [
{
"travel-sample": {
"callsign": "AIRLINAIR",
"country": "France",
"iata": "A5",
"icao": "RLA",
"id": "19810",
"name": "Airlin Air",
"type": "airline"
}
}
],
"status": "success",
"metrics": {
"elapsedTime": "3.393649025s",
"executionTime": "3.393530368s",
"resultCount": 1,
"resultSize": 298
}
}
|
This shows the newly updated document.
DELETE an existing Airline resource
Query for a unique id:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
cbq> select * from `travel-sample` where id="19810" limit 10;
{
"requestID": "47a315cd-afe4-45a8-8814-5ab3034e0d0f",
"signature": {
"*": "*"
},
"results": [
{
"travel-sample": {
"callsign": "AIRLINAIR",
"country": "France",
"iata": "A5",
"icao": "RLA",
"id": "19810",
"name": "Airlin Air",
"type": "airline"
}
}
],
"status": "success",
"metrics": {
"elapsedTime": "3.006863656s",
"executionTime": "3.006821997s",
"resultCount": 1,
"resultSize": 298
}
}
|
Notice that one document is returned.
Lets delete this document.
Request
1
2
3
4
5
6
7
8
9
10
11
12
13
|
~ > curl -v -X DELETE http://localhost:8080/couchbase-javaee/resources/airline/19810
* Hostname was NOT found in DNS cache
* Trying ::1...
* connect to ::1 port 8080 failed: Connection refused
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> DELETE /couchbase-javaee/resources/airline/19810 HTTP/1.1
> User-Agent: curl/7.37.1
> Host: localhost:8080
> Accept: */*
>
|
Response
1
2
3
4
5
6
7
8
9
10
11
12
13
|
< HTTP/1.1 200 OK
< Connection: keep-alive
< X-Powered-By: Undertow/1
* Server WildFly/9 is not blacklisted
< Server: WildFly/9
< Content-Type: application/octet-stream
< Content-Length: 136
< Date: Wed, 18 Nov 2015 21:52:47 GMT
<
* Connection #0 to host localhost left intact
{"travel-sample":{"country":"France","iata":"A5","callsign":"AIRLINAIR","name":"Airlin Air","icao":"RLA","id":"19810","type":"airline"}}
|
Query again for the deleted id:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
cbq> select * from `travel-sample` where id="19810" limit 10;
{
"requestID": "972b0bbd-ba25-4f6c-a30e-ed188bf43588",
"signature": {
"*": "*"
},
"results": [
],
"status": "success",
"metrics": {
"elapsedTime": "3.261481199s",
"executionTime": "3.261431917s",
"resultCount": 0,
"resultSize": 0
}
}
|
And no results are returned!
As mentioned earlier, the complete code base is at github.com/arun-gupta/couchbase-javaee.
Enjoy!