Create Spring Boot app
From the command line execute
spring init \
-d=data-rest,data-mongodb,lombok,data-rest-hal \
-groupId=com.joaovicente \
-artifactId=observablespring \
-name=observablespring \
observablespring
TODO: Update to Spring boot version 2.0 (not RELEASEd yet) using -bootVersion=2.0.0.M6
Be Docker ready
Build Docker image using a Maven docker plugin
Go into your project directory
cd observablespring
And edit the pom.xml adding
in properties section
<properties>
...
<docker.image.prefix>joaovicente</docker.image.prefix>
</properties>
And in the plugins section add the following
<plugins>
...
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.4.11</version>
<configuration>
<imageName>${docker.image.prefix}/${project.artifactId}</imageName>
<imageTags>
<imageTag>${project.version}</imageTag>
<imageTag>latest</imageTag>
</imageTags>
<baseImage>frolvlad/alpine-oraclejdk8:slim</baseImage>
<entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint>
<!--<dockerDirectory>src/main/docker</dockerDirectory>-->
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
Create a Docker compose file to to run both the app and MongoDB
create docker-compose.yml
version: '2'
services:
observablespring:
image: joaovicente/observablespring:latest
ports:
- "8080:8080"
links:
- mongodb
mongodb:
image: mongo:3.0.4
ports:
- "27017:27017"
command: mongod --smallfiles
Create Entities and Repositories
Author
Create the Author entity
./src/main/java/com/joaovicente/observablespring/Author.java
package com.joaovicente.observablespring;
import org.springframework.data.annotation.Id;
import lombok.Data;
@Data
public class Author {
@Id private String id;
private String email;
private String name;
}
And its repository
./src/main/java/com/joaovicente/observablespring/AuthorRepository.java
package com.joaovicente.observablespring;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import java.util.List;
@RepositoryRestResource(collectionResourceRel = "authors", path = "authors")
public interface AuthorRepository extends MongoRepository<Author, String> {
List<Author> findByName(@Param("name") String name);
}
Story
Create the Story entity
./src/main/java/com/joaovicente/observablespring/Story.java
package com.joaovicente.observablespring;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.DBRef;
import lombok.Data;
@Data
public class Story {
@Id private String id;
private String title;
private String body;
@DBRef
Author author;
}
And its repository
./src/main/java/com/joaovicente/observablespring/StoryRepository.java
package com.joaovicente.observablespring;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import java.util.List;
@RepositoryRestResource(collectionResourceRel = "stories", path = "stories")
public interface StoryRepository extends MongoRepository<Story, String> {
List<Story> findByTitle(@Param("title") String title);
}
Configure MongoDB
add mongodb connection settings to ./src/main/resources/application.properties
spring.data.mongodb.host=mongodb
spring.data.mongodb.port=27017
Package the app as a docker image
mvn clean package docker:build
Running the app with a MongoDB backend, using Docker Compose
docker-compose -p jv_ up
Explore the REST API
Create an Author
curl -X POST \
http://localhost:8080/authors \
-H 'content-type: application/json' \
-d '{
"name":"Joao",
"email":"[email protected]"
}'
You will see the Author created
{
"name" : "Joao",
"email" : "[email protected]",
"_links" : {
"self" : {
"href" : "http://localhost:8080/authors/5a038cab52faff0001e77123"
},
"author" : {
"href" : "http://localhost:8080/authors/5a038cab52faff0001e77123"
}
}
}
If you follow the URL shown in _links.self.href
curl http://localhost:8080/authors/5a038cab52faff0001e77123
you should be able to GET the Author
{
"name" : "Joao",
"email" : "[email protected]",
"_links" : {
"self" : {
"href" : "http://localhost:8080/authors/5a038cab52faff0001e77123"
},
"author" : {
"href" : "http://localhost:8080/authors/5a038cab52faff0001e77123"
}
}
}
Create a Story
Create a story linked to the Author above
curl -X POST \
http://localhost:8080/stories \
-H 'content-type: application/json' \
-d '{
"title":"Once",
"body":"Once upon a time ...",
"author":"/authors/5a038cab52faff0001e77123"
}'
which will return
{
"title": "Once",
"body": "Once upon a time ...",
"_links": {
"self": {
"href": "http://localhost:8080/stories/5a29c3ec52faff0001ee98e9"
},
"story": {
"href": "http://localhost:8080/stories/5a29c3ec52faff0001ee98e9"
},
"author": {
"href": "http://localhost:8080/stories/5a29c3ec52faff0001ee98e9/author"
}
}
}
Inspect MongoDB
docker exec -it jv_mongodb_1 sh
#mongo
>db.story.find()
{ "_id" : ObjectId("5a29c3ec52faff0001ee98e9"), "_class" : "com.joaovicente.observablespring.Story", "title" : "Once", "body" : "Once upon a time ...", "author" : DBRef("author", ObjectId("5a038cab52faff0001e77123")) }
Load test
Taurus (https://hub.docker.com/r/blazemeter/taurus/ is a very useful load test framework. We'll use it to put some load through the service
sudo pip install bzt
create a simpleload-test.yml file
---
execution:
- concurrency: 10
ramp-up: 1m
hold-for: 1m30s
scenario: simple
scenarios:
simple:
think-time: 0.75
requests:
- http://localhost:8080/authors
Now execute the load
bzt load-test.yml
And you should see a nice ASCII dashboard showing how the Author service is coping with the load
Now lets create a more interesting test author-create-load-test.ymlwhich will actually create users
---
execution:
- concurrency: 1
hold-for: 10s
scenario: author-create
write-xml-jtl: full
scenarios:
author-create:
think-time: 1
data-sources:
- author-create.csv
requests:
- url: http://localhost:8080/authors
method: POST
headers:
Content-Type: application/json
body:
name: ${name}
email: ${email}
sourced from author-create.csv
name,email
antoinette,[email protected]
brian,[email protected]
carl,[email protected]
david,[email protected]
edith,[email protected]
frank,[email protected]
greg,[email protected]
hugo,[email protected]
isabel,[email protected]
john,[email protected]
kevin,[email protected]
lidia,[email protected]
mark,[email protected]
Run it the same way
bzt author-create-load-test.yml
And it will have created 10 users, 1 per second, which is not much of a load test but it illustrates how to create one
If you want to do more on the load test side the Taurus JMeter manual should help. You will find good info about using data sources in the JMeter examples.