If you have Docker 17.05+ with multistage builds:
docker-compose build
docker-compose up
Otherwise:
mkdir -p app/react-app/node_modules
npm install --prefix app/react-app
npm run build --prefix app/react-app
rm -r app/static; mv app/react-app/build app/static
docker swarm init # needed if not presently in swarm mode
docker run -ti -v $(pwd):/atsea -w /atsea maven:alpine mvn package -DskipTests
docker-compose build
docker-compose up
(Unfortunately the above will most likely not work on Linux due to root bind mount, you will need to get craftier with user remapping if executing there)
Browse to the app at http://localhost:8080/atsea/index.html.
The REST API base URL is http://localhost:8080/atsea/api/
.
- user account creation and sign-in
- a products page listing all available products
- a detail page for an individual products
- a shopping cart to add products
- an order page that displays the products in the cart and a total
A page for each feature will be needed in the client.
- microservices REST backend written in Java and spring-boot to handle the store functions
- PostgreSQL database for product inventory, customer data, and order data
- Nginx proxies for serving static data and handling HTTPS request
- store front client written in Angular
Local development:
From the react-app
directory (within app
), run npm install
then npm run start
.
Navigate to localhost:3000. Any changes within react-app
will be updated in real-time.
Update static files:
cd react-app
npm run build
cd ../
rm -r static; mv react-app/build static
Finally, re-run docker-compose up
Navigate to localhost:8080 to see your changes.
- The command
npm run build
builds the react-app for production in the build folder. The build is minified and the filenames include the hashes. - The command
mv react-app/build static
moves the build folder to the static folder. - The multistage build can be seen in
app/Dockerfile.app
This includes building and updating the static files.
FROM node:latest
COPY . /usr/src/atsea
WORKDIR /usr/src/atsea/app/react-app
RUN npm install
RUN npm run build
- Secrets
- Routing mesh
- Overlay networks
- Dynamic storage (infinit.io)
- Can run as a single stateless container
- Can be deployed as multi-container stateful app through compose v3 (docker stack deploy)
- Can be deployed on Docker 4 Mac for development demo
- Message queue
- Optimize for startup time
- L7 loadbalancing (HRM)
- HRM sticky sessions
- HRM HTTPS (SNI)
- Jmeter load generation
- NFS store for static content
Make a directory for static content called 'static' in the same directory as the appication (atsea-0.0.1-SNAPSHOT.jar)
Application
|- AtSea-0.0.1-SNAPSHOT.jar
|- static/
|- client files
|- images
|_ ...
the URL for the content is http://localhost:8080/atsea/*
Request:
GET /atsea/api/product/
Host: localhost:8080
Auth:
Content-type: application/json
Accept: application/json
Returns:
HTTP 200 OK
[
{
"description": "Keeping it safe and secure",
"image": "/9j/4QAYRXhpZg ...."
"name": "Trusted Registry",
"price": 25.0,
"productId": 32
},
{
"description": "Moby at work",
"image": "/9j/4QAYRXhpZg ...."
"name": "Moby",
"price": 25.0,
"productId": 11
}
]
Error:
HTTP 204 NO CONTENT
Request:
GET /atsea/api/product/{id}
Host: localhost:8080
Auth: basic username:password
Content-type: application/json
Accept: application/json
Returns:
{
"description": "Keeping it safe and secure",
"image": "/9j/4QAYRXhpZg ...."
"name": "Trusted Registry",
"price": 25.0,
"productId": 32
}
Error:
HTTP 404 NOT FOUND
Request:
POST /api/customer/
Host: localhost:8080
Auth:
Content-type: application/json
Accept: application/json
{
"customerId" : 0,
"name" : "Sally Vallery",
"address" : "address as single string",
"email" : "[email protected]".
"phone" : "phone as string"
"username" : "sallyv",
"password" : "sallypassword",
"enabled" : "true",
"role" : "USER"
}
Returns:
customerId
{
"customerId": 1
}
Error:
HTTP 409 CONFLICT
{
"error" : "Unable to create customer with username xxxx"
}
Request:
GET /api/customer/{id}
Host: localhost:8080
Auth:
Content-type: application/json
Accept: application/json
Returns:
{
"customerId" : 54321,
"name" : "Sally Vallery",
"address" : "address as single string",
"email" : "[email protected]".
"phone" : "phone as string"
"username" : "sallyv",
"password" : "sallypassword"
}
Error:
HTTP 404 NOT FOUND
{
"error":"Customer with id xx not found."
}
Request:
GET /api/customer/name={name}
Host: localhost:8080
Auth:
Content-type: application/json
Accept: application/json
Returns:
{
"customerId":9,
"name":"Space Goat",
"address":"1800 Nebula Rd",
"email":"[email protected]",
"phone":"222-333-4444",
"username":"spacegoat",
"password":"spacegoatpass",
"enabled":true,
"role":"USER"
}
Error:
HTTP 404 NOT FOUND
{
"error":"Customer with name xxx not found"
}
Request:
GET /api/customer/username={username}
Host: localhost:8080
Auth:
Content-type: application/json
Accept: application/json
Returns:
{
"customerId":9,
"name":"Space Goat",
"address":"1800 Nebula Rd",
"email":"[email protected]",
"phone":"222-333-4444",
"username":"spacegoat",
"password":"spacegoatpass",
"enabled":true,
"role":"USER"
}
Error:
HTTP 404 NOT FOUND
{
"error":"Customer with username xxx not found"
}
Request:
PUT /api/customer/{customerId}
Host: localhost:8080
Auth:
Content-type: application/json
Accept: application/json
{
"customerId" : 0,
"name" : "Sally Vallery",
"address" : "my new address",
"email" : "[email protected]".
"phone" : "phone as string"
"username" : "sallyv",
"password" : "sallynewpassword",
"enabled" : "true",
"role" : "USER"
}
Returns:
OK 200
{
"customerId" : 0,
"name" : "Sally Vallery",
"address" : "my new address",
"email" : "[email protected]".
"phone" : "phone as string"
"username" : "sallyv",
"password" : "betterpassword",
"enabled" : "true",
"role" : "USER"
}
Error:
HTTP 404 NOT FOUND
{
"error":"Unable to update. Customer with id xxx not found"
}
Request:
DELETE /api/customer/{customerId}
Host: localhost:8080
Auth:
Content-type: application/json
Accept:
Returns:
OK 204 NO CONTENT
Error:
{
"error":"Unable to delete. Customer with id xx not found."
}
Request:
DELETE /api/customer/
Host: localhost:8080
Auth:
Content-type: application/json
Accept:
Returns:
OK 204 NO CONTENT
Request:
POST /api/order/
Host: localhost:8080
Auth:
Content-type: application/json
Accept: application/json
{
"orderId" : 1,
"orderDate : {current date},
"customerId" : "54321",
"productsOrdered" : {
"1":1,
"2":1,
"3":1
}
}
Returns:
HTTP 201 CREATED
{
"orderId": 1
}
Error:
HTTP 409 CONFLICT
{
"error":"Unable to create. An order with id xx already exists"
}
Request:
GET /api/order/
Host: localhost:8080
Auth:
Content-type: application/json
Accept: application/json
Returns:
HTTP 200 OK
[
{
"orderId" : 1,
"orderDate : {current date},
"customerId" : "54321",
"productsOrdered" : {"1":1,"2":1,"3":1}
},
{
"orderId" : 2,
"orderDate : {current date},
"customerId" : "12345",
"productsOrdered" : {"2":1,"3":1,"4":1}
}
]
Error:
HTTP 404 NO CONTENT
Request:
GET /api/order/{orderId}
Host: localhost:8080
Auth:
Content-type: application/json
Accept: application/json
Returns:
HTTP 200 OK
{
"orderId" : 1,
"orderDate : {current date},
"customerId" : "54321",
"productsOrdered" : {"1":1,"2":1,"3":1]
}
Error:
HTTP 404 NOT FOUND
{
"error":"Order with id xx not found."
}
Request:
POST: /api/order/{orderId}
Host: localhost:8080
Auth:
Content-type: application/json
Accept: application/json
{
"orderId" : "0",
"productsOrdered" : {
"3":2,
"6":3,
"11":2
},
"orderDate" : "2017-02-28T19:52:39Z",
"customerId" : "8"
}
Returns:
HTTP 200 OK
{
"customerId": 8,
"orderDate": "2017-02-28T19:52:39Z",
"orderId": 8,
"productsOrdered": {
"11": 1,
"3": 1,
"6": 1
}
}
Error:
HTTP 404 NOT FOUND
{
"error":"Unable to update. Order with id xx not found."
}
Request:
DELETE: /api/order/{orderId}
Host: localhost:8080
Auth:
Content-type: application/json
Accept: application/json
Returns:
HTTP 204 OK
Error:
HTTP 404 NOT FOUND
{
"error":""Unable to delete order. Order with id xx not found."
}
Request:
POST: /login/
Host: localhost:8080
Auth:
Content-type: application/json
Accept: application/json
{
"username" : "gordon",
"password" : "gordonpassword"
}
Returns:
HTTP 200 OK
{
"token" : "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzcGFjZWdvYXQiLCJyb2xlcyI6InNwYWNlZ29hdCIsImlhdCI6MTQ5MjA5ODAwM30.8zdJd5PyWmIEMkBcdtJlaT65nvRhKWH5QBSHjTLGQpo"
}
Error:
HTTP 403 UNAUTHORIZED
"Customer name or password not found."
Request:
GET: /purchase/
Host: localhost:8080
Auth:
Content-type: application/json
Accept: application/json
{
"username" : "spacegoat",
"password" : "spacegoatpass"
}
Returns:
HTTP 200 OK
{
"message": "Thank you for shopping @Sea! We're sending a confirmation email shortly and getting your order ready!"
}
Error:
Request:
GET: /utility/healthcheck/
Host: localhost:8080
Auth:
Content-type: application/json
Accept: application/json
Returns:
HTTP 200 OK
{
"status":"2017-03-27 03:01"
}
Error:
HTTP 500 INTERNAL SERVER ERROR
{
"error":"Database not responding."
}
Request:
GET: /utility/containerid/
Host: localhost:8080
Auth:
Content-type: application/json
Accept: application/json
Returns:
HTTP 200 OK
{
"host": "spara-mbp",
"ip": "192.168.0.6"
}
Error:
HTTP 404 NOT FOUND
{
"error":"Container id not found"
}