This project is part of the 'IBM Cloud Native Reference Architecture' suite, available at https://github.com/ibm-cloud-architecture/refarch-cloudnative
This project demonstrates how to build a Microservices application implemented as a Spring Boot application and deployed in a docker container. It provides basic operations of creating and querying customer profiles from IBM Cloudant NoSQL database as part of the Customer Profile function of BlueCompute. Additionally the Auth Microservice calls this microservice to perform Customer username/password authentication. This project covers the following technical areas:
- Build a microservice as a Spring Boot Java application
- Deploy the Customer microservice as a container on the IBM Bluemix Container Service.
- Register the container with Eureka service registry (part of Spring Cloud Netflix project
- Persist Customer data in an IBM Cloudant NoSQL database using the official Cloudant Java library.
The Customer Microservice REST API is behind the Zuul Proxy, which validates the caller using signed JWT tokens. As such, only API exposed by API Connect are considered public API. All Public REST API are OAuth 2.0 protected by the API Connect OAuth provider.
-
GET /micro/customer
(public)- Returns all customers. The caller of this API must pass API Connect a valid OAuth token. API Connect will pass down the customer ID in the
IBM-App-User
header. A JSON object array is returned consisting of only users that match the customer ID (either length 0 or 1).
- Returns all customers. The caller of this API must pass API Connect a valid OAuth token. API Connect will pass down the customer ID in the
-
GET /micro/customer/{id}
(public)- Return customer by ID. The caller of this API must pass API Connect a valid OAuth token. API Connect will pass down the customer ID in the
IBM-App-User
header. If theid
matches the customer ID passed in theIBM-App-User
header, it is returned as a JSON object in the response; otherwiseHTTP 401
is returned.
- Return customer by ID. The caller of this API must pass API Connect a valid OAuth token. API Connect will pass down the customer ID in the
-
GET /micro/customer/search
(private)- Return customer by username. This API is called by the Auth Microservice when authenticating a user. A JSON object array is returned consisting of only users that match the customer username (either length 0 or 1).
-
POST /micro/customer
(private)-
Create a customer. This API is not exposed to API Connect as user creation is not a supported function of the BlueCompute application. The Customer object must be passed as JSON object in the request body with the following format:
{ "username": <username>, "password": <password>, "email": <email address>, "firstName": <first name>, "lastName": <last name>, "imageUrl": <image URL> }
On success,
HTTP 201
is returned with the ID of the created user in theLocation
response header.
-
-
PUT /micro/customer/{id}
(private)- Update a customer record. This API is not exposed to API Connect as updating the user profile is not a function of the BlueCompute application. The full Customer object must be passed in the request body.
-
DELETE /micro/customer/{id}
(private)- Delete a customer record. This API is not exposed to API Connect as deleting the user profile is not a function of the BlueCompute application.
Install Docker
Install the Cloud Foundry CLI and the IBM Containers Plugin
Note that two components use Cloudant in BlueCompute, the Customer microservice and the Social Review microservice. If deploying both components to the same space, they can share the Cloudant database instance, as the Customer microservice saves documents to the customers
database, and the Social Review microservice saves documents to the socialreviewdb
and socialreviewdb-staging
databases.
- Login to your Bluemix console
- Open browser to create Cloudant Service using this link https://console.ng.bluemix.net/catalog/services/cloudant-nosql-db
- Name your Cloudant service name like
refarch-cloudantdb
- For testing, you can select the "Lite" plan, then click "Create"
- Once the service has been created, note the service credentials under
Service Credentials
. In particular, the Customer microservice requires theurl
property.
You can use the following button to deploy the Customer microservice to Bluemix, or you can follow the instructions manually below.
The deployment will:
- Discover and pass in the Cloudant credentials from the Cloudant instance in the space
- Provision a container group with the Customer Microservice in the Bluemix Container Service.
- Once the container group has been created, a temporary route is mapped to the container group, a user with the username 'foo' and password 'bar' is inserted into the database, and temporary route is removed.
The toolchain contains optional parameters:
New Relic License Key
- enter the license key for New Relic agent integration.Eureka Registry URL
to register the Customer microservice with a Eureka registry
-
Build the application:
# ./gradlew build
-
Copy the binaries to the docker container:
# ./gradlew docker
-
Build the docker container
# cd docker # docker build -t customer-microservice .
Execute the following to run the Docker container locally. Make sure to update the <Eureka URL>
, and the <Cloudant username>
, <Cloudant password>
, <Cloudant host>
, and <Cloudant port>
retrieved from the Service Credentials
tab in the Bluemix portal.
# docker run --name customer-service --publish 8080 -e eureka.client.fetchRegistry=true -e eureka.client.registerWithEureka=true -e spring.application.name=customer-microservice -e server.context-path=/micro -e eureka.client.serviceUrl.defaultZone=<Eureka URL> -e spring.application.cloudant.username=<Cloudant username> -e spring.application.cloudant.password=<Cloudant password> -e spring.application.cloudant.host=<Cloudant host> -e spring.application.cloudant.port=<Cloudant port> -e spring.application.cloudant.database=customers customer-microservice
-
Log into the Cloud Foundry CLI
# cf login
Be sure to set the correct target space where Cloudant instance was provisioned.
-
Initialize the Bluemix Containers plugin
# cf ic init
Ensure that the container namespace is set:
# cf ic namespace get
If it is not set, use the following command to set it:
# cf ic namespace set <namespace>
-
Tag and push the docker image to the Bluemix private registry:
# docker tag customer-microservice registry.ng.bluemix.net/$(cf ic namespace get)/customer-microservice # docker push registry.ng.bluemix.net/$(cf ic namespace get)/customer-microservice
-
Execute the following to run the container in a group on Bluemix Container Service. Make sure to update the
<Eureka URL>
, and the<Cloudant username>
,<Cloudant password>
,<Cloudant host>
, and<Cloudant port>
retrieved from theService Credentials
tab in the Bluemix portal.cf ic group create --name customer-microservice --publish 8080 -m 256 -e eureka.client.fetchRegistry=true -e eureka.client.registerWithEureka=true -e spring.application.name=customer-microservice -e server.context-path=/micro -e eureka.client.serviceUrl.defaultZone=<Eureka URL> -e spring.application.cloudant.username=<Cloudant username> -e spring.application.cloudant.password=<Cloudant password> -e spring.application.cloudant.host=<Cloudant host> -e spring.application.cloudant.port=<Cloudant port> -e spring.application.cloudant.database=customers --desired 2 --min 1 --max 3 registry.ng.bluemix.net/$(cf ic namespace get)/customer-microservice
Zuul performs authorization using signed JWT tokens generated by API Connect. As such, to call the REST API directly from Bluemix, you must temporarily map a route to the container group which bypasses Zuul.
# cf ic route map -n <temp-routename> -d mybluemix.net customer-microservice
Create a customer profile for the user foo
with the password bar
. Make sure that you replace <temp-routename>
with your temporary route.
# curl -X POST -H "Content-Type: application/json" -d '{"username": "foo", "password": "bar", "firstName": "foo", "lastName": "bar", "email": "foo@bar.com"}' -i https://<temp-routename>/micro/customer
HTTP/1.1 201 Created
X-Backside-Transport: OK OK
Connection: Keep-Alive
Transfer-Encoding: chunked
Date: Wed, 08 Feb 2017 21:41:31 GMT
Location: http://<temp-routename>/micro/customer/bff5631f24c849e8897645be8b66af16
X-Application-Context: zuul-proxy:8080
X-Global-Transaction-ID: 1311769839
Note the Location
header returned, which contains the ID of the created customer.
Verify the customer. The caller must pass a header, IBM-App-User
, to the API, to identify itself. This header is passed by API Connect whan an authenticated user passes a valid Bearer token. For testing, pass the header manually.
# curl -H "IBM-App-User: bff5631f24c849e8897645be8b66af16" http://<temp-routename>/micro/customer
{"username":"foo","password":"bar","firstName":"foo","lastName":"bar","imageUrl":null,"customerId":"bff5631f24c849e8897645be8b66af16","email":"foo@bar.com"}
Note that only the customer object identified by IBM-App-User
is returned to the caller.
Call the search
API to find the customer by username. This API is used by the Auth Microservice to authenticate users.
# curl http://<temp-routename>/micro/customer/search?username=foo
[{"username":"foo","password":"bar","firstName":"foo","lastName":"bar","imageUrl":null,"customerId":"bff5631f24c849e8897645be8b66af16","email":"foo@bar.com"}]
When verification is complete, unmap the route so that the only access to the customer microservice is through Zuul.
# cf ic route unmap -n <temp-routename> -d mybluemix.net customer-microservice
Delete the temporary route.
# cf delete-route -n <temp-routename> mybluemix.net