├── LICENSE ├── README.md ├── TestServices.md ├── api-connect-resources └── oauth_endpoint.yaml ├── app-connect-resources ├── Flow.yaml └── microservices-apis │ ├── Account_Check.json │ ├── Credit_Transaction.json │ └── Debit_Transaction.json ├── client-app └── node-red-flows │ ├── README.md │ └── flows.json ├── images ├── access-to-cluster.png ├── add-api-to-catalog.gif ├── api-connect-instance-create.png ├── api-defn-export.png ├── app-connect-flow.png ├── app-connect-instance-create.png ├── app_subscribe_plan.gif ├── architecture.png ├── cluster-status.png ├── configure_app.png ├── create_app.gif ├── create_funds_transfer_endpoint.gif ├── create_oauth_endpoint.gif ├── create_product_publish.gif ├── create_service.png ├── debit_account_service_msg.png ├── demo.gif ├── deploy_client_app.gif ├── flow-start.png ├── flow-test.gif ├── import-flow-check.gif ├── import-flow.gif ├── node-red-instance-create.png ├── note_api_connect_endpoint.gif ├── note_fund_transfer_url.gif ├── note_node_red_url.png ├── postman_accmgmtservice.png ├── postman_creditaccservice.png ├── postman_debitaccservice.png ├── postman_loginservice.png └── worker-nodes.png ├── microservices ├── account_management_service │ ├── Dockerfile │ ├── app.js │ ├── deploy.yaml │ └── package.json ├── credit_service │ ├── Dockerfile │ ├── app.js │ ├── deploy.yaml │ └── package.json ├── debit_service │ ├── Dockerfile │ ├── app.js │ ├── deploy.yaml │ └── package.json └── login_service │ ├── Dockerfile │ ├── app.js │ ├── deploy.yaml │ └── package.json └── mongodb └── deploy_mongodb.yaml /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WARNING: This repository is no longer maintained :warning: 2 | 3 | > This repository will not be updated. The repository will be kept available in read-only mode. 4 | > 5 | # Build a secure microservices-based banking application 6 | 7 | ### Use API Connect for OAuth functions, App Connect for API orchestration, and Node.js to develop the banking application 8 | 9 | In a microservices based solution, security and orchestration of workflows are common requirements across solutions. 10 | 11 | Let us consider the example of funds transfer in a personal banking scenario. The customer wishing to perform a funds transfer must be securely authenticated and authorized to perform the operation. Also, the funds transfer functionality requires integration with other applications or APIs to complete a transaction. 12 | 13 | In this code pattern, we demonstrate the security and orchestration of microservices using a personal banking use-case scenario. The IBM API Connect and IBM App Connect available on IBM Cloud is used to implement the functionality. API Connect is used to provide OAuth based authorization security to microservices, and App Connect Enterprise for easier and seamless integration of APIs (with zero code) for a business user. The solution comprises authentication and funds transfer functionality. 14 | 15 | At the end of this code pattern, users will understand: 16 | * Authentication and authorization using OAuth in API Connect. 17 | * Funds transfer operation with orchestration of APIs exposed by `Account Management Service`, `Credit Account Service` and `Debit Account Service` using App Connect. 18 | * To build and deploy Node.js microservices on IBM Kubernetes Service. 19 | * Development of a client application using Node-RED. 20 | 21 | The `Public Access Code` scheme of OAuth2 is used for authorization. Since the customer has to authorize the operation, the public scheme is suitable as the application is incapable of maintaining the secrecy of the client secret. In the access code flow, the application has the user provide authorization through a form provided by the gateway server, which, if they grant authorization, provides an authorization code to the application. 22 | 23 | In the funds transfer scenario, the following operations are orchestrated using `App Connect` flow: 24 | - Balance check using `Account Management Service`. 25 | - Perform a debit of customer account using `Debit Account Service`. 26 | - Perform a credit of payee account using `Credit Account Service`. 27 | 28 | In case of a failure in the credit operation, the transaction is rolled back and the amount is credited back to the customer account. 29 | 30 | # Flow 31 | 32 | ![Flow Diagram](images/architecture.png) 33 | 34 | 1. User logs-in to the client application. 35 | 2. Login Request will go to API Connect. 36 | 3. API Connect uses Login API for authentication. And then it generates OAuth token for authorization. 37 | 4. The user invokes the `funds transfer` transaction using the OAuth token. The request goes to app connect flow which internally uses `Account Management API`, `Credit Account API` and `Debit Account API`. 38 | 39 | > Note: 40 | > * All microservices are deployed on IBM Kubernetes Service. 41 | > * All APIs interact with MongoDB. 42 | 43 | # Pre-requisites 44 | * [IBM Cloud Account](https://cloud.ibm.com) 45 | * [Git Client](https://git-scm.com/downloads) - needed for clone commands. 46 | 47 | # Steps 48 | 49 | Follow these steps to setup and run this code pattern. The steps are described in detail below. 50 | 51 | 1. [Get the code](#1-get-the-code) 52 | 2. [Create IBM Cloud Services](#2-create-ibm-cloud-services) 53 | 3. [Setup environment for Kubernetes CLI](#3-setup-environment-for-kubernetes-cli) 54 | 4. [Deploy Mongo DB](#4-deploy-mongo-db) 55 | 5. [Deploy Microservices](#5-deploy-microservices) 56 | 6. [Configure App Connect](#6-configure-app-connect) 57 | 7. [Configure API Connect](#7-configure-api-connect) 58 | 8. [Deploy client application](#8-deploy-client-application) 59 | 9. [Analyze the result](#9-analyze-the-result) 60 | 61 | ## 1. Get the code 62 | 63 | - Clone the repo using the below command. 64 | ``` 65 | git clone https://github.com/IBM/microservices-using-apiconnect-and-appconnect.git 66 | ``` 67 | 68 | ## 2. Create IBM Cloud Services 69 | 70 | ### Create IBM Kubernetes Service 71 | 72 | Create a Kubernetes cluster with [Kubernetes Service](https://cloud.ibm.com/containers-kubernetes/catalog/cluster) using IBM Cloud Dashboard. This pattern uses the _free cluster_. 73 | 74 | ![](images/create_service.png) 75 | 76 | > Note: It can take up to 15-20 minutes for the cluster to be set up and provisioned. 77 | 78 | ### Create App Connect service instance 79 | 80 | Create an instance of [IBM App Connect](https://cloud.ibm.com/catalog/services/app-connect). Ensure `lite` plan is selected. Click `Create`. 81 | 82 | ![Create App Connect Instance](./images/app-connect-instance-create.png) 83 | 84 | A new instance of IBM App Connect should be created. 85 | 86 | ### Create API Connect service instance 87 | 88 | Create an instance of [IBM API Connect](https://cloud.ibm.com/catalog/services/api-connect). Ensure `lite` plan is selected. Click `Create`. 89 | 90 | ![Create API Connect Instance](./images/api-connect-instance-create.png) 91 | 92 | A new instance of IBM API Connect should be created. 93 | 94 | ### Create Node-RED service instance 95 | 96 | Create an instance of [Node-RED](https://cloud.ibm.com/catalog/starters/node-red-starter). Ensure `lite` plan is selected. Click `Create`. 97 | 98 | ![Create Node-RED Instance](./images/node-red-instance-create.png) 99 | 100 | A new instance of Node-RED should be created. 101 | 102 | **Note the base url of Node-RED** as shown below: 103 | 104 | ![Note Node-RED base url](./images/note_node_red_url.png) 105 | 106 | ## 3. Setup environment for Kubernetes CLI 107 | 108 | **Check status of your Kubernetes Cluster** 109 | 110 | * Check the status of your cluster `IBM Cloud Dashboard -> Clusters -> `. If status is not `Normal`, then you need to wait for some more time to proceed further. 111 | 112 | * Once your cluster is ready, open the access tab `IBM Cloud Dashboard -> Clusters -> -> Access`. Perform the steps provided under this section to get access of your cluster through `kubectl` CLI. 113 | 114 | * Verify that the kubectl commands run properly with your cluster by checking the Kubernetes CLI server version. 115 | 116 | ``` 117 | $ kubectl version --short 118 | Client Version: v1.14.6 119 | Server Version: v1.16.7+IKS 120 | ``` 121 | 122 | **Get the public IP for Kubernetes Cluster** 123 | 124 | Once cluster is up and running then find out the public IP of your cluster. It will be required for further steps. 125 | 126 | * Go to `IBM Cloud Dashboard -> Clusters -> `. It gives you details of the cluster. 127 | 128 | * Access `Worker Nodes` tab, it will show you the public IP of your cluster as shown in below screenshot. 129 | 130 | ![](images/worker-nodes.png) 131 | 132 | Make a note of this public IP. It will be used in further steps. 133 | 134 | **Create namespace on IBM Cloud container registry** 135 | 136 | IBM Cloud Container Registry is used to store and access private container images. If you have not created namespace before or you want to use a different 137 | namespace than existing one, then need to create a new namespace. You can create a namespace through interface as 138 | `Navigation > Kubernetes > Registry > Namespaces > Create` or using the following CLI commands: 139 | 140 | ``` 141 | # To create a namespace 142 | $ ibmcloud cr namespace-add 143 | 144 | # To verify that namespace is created 145 | $ ibmcloud cr namespace-list 146 | ``` 147 | 148 | ## 4. Deploy Mongo DB 149 | 150 | In this pattern, mongo db will be deployed in a container and will be used by all the microservices. Perform the following steps to deploy Mongo DB in a container. 151 | 152 | ``` 153 | $ cd mongodb 154 | $ kubectl create -f deploy_mongodb.yaml 155 | ``` 156 | 157 | After deployment, the status can be checked as: 158 | ``` 159 | $ kubectl get pods 160 | NAME READY STATUS RESTARTS AGE 161 | mongo-8dc7685d7-nxrcr 1/1 Running 0 73s 162 | 163 | $ kubectl get services |grep mongo 164 | mongo NodePort 172.21.84.39 27017:32643/TCP 11m 165 | ``` 166 | 167 | The **connection_url** to connect to mongodb will use `:`. Use the public IP of your Kubernetes cluster retrieved in step 3 above. The mongo_service_port in this case, is 32643 (as shown in the above command). This connection url will be used by microservices to connect with mongo db. 168 | 169 | ## 5. Deploy Microservices 170 | 171 | For this application, we are creating microservices for authentication (login), bank account management, credit account and debit account functionality. A set of user credentials and bank account details are pre-defined in Mongo DB. 172 | 173 | Perform the following steps to deploy microservices. 174 | 175 | **Update MongoDB Connection String** 176 | 177 | Prepare connection url as explained in step 4. Then execute the following commands to update mongo db connection url in app.js of all four microservices as per your system(linux/mac). 178 | 179 | ``` 180 | ## For MAC 181 | cd ../microservices 182 | sed -i '' s#CONNECTION_URL#x.x.x.x:port# login_service/app.js 183 | sed -i '' s#CONNECTION_URL#x.x.x.x:port# account_management_service/app.js 184 | sed -i '' s#CONNECTION_URL#x.x.x.x:port# debit_service/app.js 185 | sed -i '' s#CONNECTION_URL#x.x.x.x:port# credit_service/app.js 186 | 187 | ## For Linux 188 | cd ../microservices 189 | sed -i s#CONNECTION_URL#x.x.x.x:port# login_service/app.js 190 | sed -i s#CONNECTION_URL#x.x.x.x:port# account_management_service/app.js 191 | sed -i s#CONNECTION_URL#x.x.x.x:port# debit_service/app.js 192 | sed -i s#CONNECTION_URL#x.x.x.x:port# credit_service/app.js 193 | ``` 194 | 195 | **Prepare deploy target** 196 | 197 | All four docker images needs to be pushed to your docker image registry on IBM Cloud. You need to set the correct deploy target. Depending on the region you have created your cluster in, your URL will be in the following format: 198 | 199 | ``` 200 | .icr.io//: 201 | ``` 202 | 203 | The following command tells you the Registry API endpoint for your cluster. You can get region abbreviation from the output. 204 | 205 | ``` 206 | ibmcloud cr api 207 | ``` 208 | 209 | To get namespace use the following command: 210 | ``` 211 | ibmcloud cr namespaces 212 | ``` 213 | 214 | For example, to deploy the login microservice to my docker image registry in the US-South region, my deploy_target will be: 215 | ``` 216 | us.icr.io/test_namespace/login_app:v1.0 217 | ``` 218 | 219 | **Deploy login microservice** 220 | 221 | Execute the following steps. 222 | 223 | ``` 224 | $ cd login_service 225 | ``` 226 | Build dockerfile and push the image to registry. 227 | 228 | ``` 229 | $ ibmcloud cr build -t . 230 | ``` 231 | 232 | Update image location(deploy target) in `deploy.yaml`. 233 | 234 | ``` 235 | $ sed -i '' s#IMAGE## deploy.yaml ## mac 236 | OR 237 | $ sed -i s#IMAGE## deploy.yaml ## linux 238 | 239 | $ kubectl create -f deploy.yaml 240 | 241 | $ kubectl get services|grep login 242 | login-service NodePort 172.21.113.169 8080:32423/TCP 31s 243 | ``` 244 | 245 | The login microservice will be accessible at `http://:`. Use the public IP of your Kubernetes cluster retrieved in step 5. The login_service_nodeport in this case is 32423 (shown in above command). To use login functionality of this service, access `http://:32423/login`. 246 | 247 | 248 | **Deploy account_management service** 249 | 250 | Following are the steps for account_management service. 251 | 252 | ``` 253 | cd ../account_management_service 254 | $ ibmcloud cr build -t . 255 | 256 | $ sed -i '' s#IMAGE## deploy.yaml ## mac 257 | OR 258 | $ sed -i s#IMAGE## deploy.yaml ## linux 259 | 260 | $ kubectl create -f deploy.yaml 261 | 262 | $ kubectl get services | grep acc 263 | account-details-service NodePort 172.21.166.106 8080:32424/TCP 33s 264 | ``` 265 | Account management functionality of this service can be accessed by using `http://:32424/check_accounts`. 266 | 267 | **Deploy debit_account service** 268 | 269 | Following are the steps for debit account service. 270 | 271 | ``` 272 | cd ../debit_service 273 | $ ibmcloud cr build -t . 274 | 275 | $ sed -i '' s#IMAGE## deploy.yaml ## mac 276 | OR 277 | $ sed -i s#IMAGE## deploy.yaml ## linux 278 | 279 | $ kubectl create -f deploy.yaml 280 | 281 | $ kubectl get services |grep debit 282 | debit-account-service NodePort 172.21.138.208 8080:32425/TCP 16s 283 | ``` 284 | 285 | Debit account functionality of this service can be accessed by using `http://:32425/debit_account`. 286 | 287 | **Deploy credit_account service** 288 | 289 | Following are the steps for credit account service. 290 | 291 | ``` 292 | cd ../credit_service 293 | $ ibmcloud cr build -t . 294 | 295 | $ sed -i '' s#IMAGE## deploy.yaml ## mac 296 | OR 297 | $ sed -i s#IMAGE## deploy.yaml ## linux 298 | 299 | $ kubectl create -f deploy.yaml 300 | 301 | $ kubectl get services|grep credit 302 | credit-account-service NodePort 172.21.51.254 8080:32426/TCP 11s 303 | ``` 304 | 305 | Credit account functionality of this service can be accessed by using `http://:32426/credit_account` 306 | 307 | > Note: We have defined NodePort of all four microservices. Please change the ports if not available in your Kubernetes Cluster. 308 | 309 | If you want to test your microservices, please refer to [test instructions](https://github.com/IBM/microservices-using-apiconnect-and-appconnect/blob/master/TestServices.md). Else continue to next step. 310 | 311 | ## 6. Configure App Connect 312 | 313 | Use App Connect to connect your different applications and make your business more efficient. Set up flows that define how data is moved from one application to one or more other applications. App Connect supports a range of skill levels and interfaces, giving you the flexibility to create integrations without writing a single line of code. You can use a web user interface or drop resources into a toolkit that gives a broader range of configuration options. Your entire organization can make smarter business decisions by providing rapid access, visibility, and control over data as it flows through your business applications and systems from a single place - App Connect. Find more App Connect resources in [Learn More](#app-connect-resources-links-for-basic-familiarty) section. 314 | 315 | Following image shows App Connect flow for funds transfer functionality and the steps in the below sub-sections explain how to import/develop this flow. 316 | ![App Connect Flow](./images/app-connect-flow.png) 317 | 318 | #### Import API interfaces and flow 319 | - On IBM Cloud dashboard, click the App Connect service instance created in earlier step and will be be listed under `Cloud Foundry Services` 320 | - Click `Launch App Connect` button on the App Connect Service home page. 321 | 322 | #### Add APIs to Catalog 323 | The [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification), previously known as the Swagger Specification, is a definition format for describing REST APIs. You can import OpenAPI documents that contain API definitions into IBM App Connect. Each imported document is added as an API to the App Connect catalog of applications and APIs, and can be used to call the API from a flow. 324 | 325 | For the microservices used in this code pattern, the REST APIs definition files are available under `app-connect-resources/microservices-apis` folder. 326 | 327 | ![Add API to Catalog](./images/add-api-to-catalog.gif) 328 | - On App Connect top menu, click `Catalog` -> `APIs` -> `Add your API or web service now` -> `Add an OpenAPI definition, WSDL or ZIP` 329 | - Browse to `app-connect-resources/microservices-apis` folder and select `Account_Check.json` file. 330 | - Specify the name to be `Account_Check`. While any unique name can be given to APIs, we will maintain the names specified here so that the flow that we will import in later steps work with the APIs, without error. 331 | - Optional. Add a description that summarizes the function of the API. 332 | - Click `Add`. Click `Add your API or web service now`. Click "Add an OpenAPI definition, WSDL or Zip". 333 | - Select the `Account Check` API json file to import. 334 | - Enter name as `Account_Check`. Enter something in Description field, if required. Then click on `Add API`. 335 | - Expoand `Imported` and click `Connect`. 336 | - Under `Override the hostnameand port of the Account_Check server:(optional)` enter the Account_Check microservice's IP address and port. e.g. `http://173.193.79.231:32424`. 337 | - Click `Connect`. 338 | - Similarly add APIs `Debit_Transaction` (name should be `Debit_Transaction`) and `Credit_Transaction` (name should be `Credit_Transaction`). 339 | - As a sanity check, verify that the microservices are working fine using a REST client like postman. 340 | 341 | #### Import flow 342 | - Click `Import Flow` button. The flow should be imported now. 343 | - On the top right corner of the browser page, click the `New` button and select `Import Flow...`. 344 | ![Import Flow](./images/import-flow.gif) 345 | - Click "Add a YAML file". Browse the cloned repository and select `Flow.yaml` file in `app-connect-resources` folder. 346 | ![Import Flow Check](./images/import-flow-check.gif) 347 | - When imported click on `Operations` tab -> `Edit Flow` button and verify that there are no visible error indicator. 348 | - You have imported the flow. 349 | 350 | #### Test the imported flow 351 | - Now that you have imported the flow, you need to test it. 352 | - Navigate to App Connect dashboard and start the flow. 353 | ![Flow Start](./images/flow-start.png) 354 | - Click on the flow on App Connect Dashboard. 355 | - Click `Manage` tab. 356 | - Scroll to the bottom of the page to `Sharing Outside of Cloud Foundry organization` section. Click `Create API Key`. 357 | - Enter a name under `Descriptive name` field and click `Create`. 358 | - `API Portal Link` is populated with a link. Click on that link. 359 | - On the right hand side panel, click on `Try it` link. 360 | - Under `Parameters -> Data`, enter the input data for rest service and click `Call Operation`. 361 | - Scroll a little down and you should see response from the service. Response Code should be `200 OK`. 362 | ![Flow Test](./images/flow-test.gif) 363 | 364 | #### Export the App Connect Flow Rest interface 365 | - Navigate to App Connect dashboard. 366 | - Click on the flow on App Connect Dashboard. 367 | - Click `Manage` tab. 368 | - Scroll a little until you find `API Info` section. 369 | - Click `API Definition` that is available on the right side of the page, to see the options. Click `Export JSON File` and save the json file. This file is needed by API Connect to invoke requests to App Connect flows. 370 | ![Export API Defn JSON](./images/api-defn-export.png) 371 | 372 | ## 7. Configure API Connect 373 | 374 | **Note the end point url on API Connect** 375 | - On the API Connect Dashboard, click on `Sandbox`. 376 | - Click on `Settings`. 377 | - Click on `Gateways`. 378 | - Note the `Endpoint` url. 379 | 380 | ![Note the endpoint](./images/note_api_connect_endpoint.gif) 381 | 382 | **Create API for OAuth** 383 | - On the API Connect Dashboard, click on `Drafts`. 384 | - Click on `APIs` 385 | - Click on `Add` and select `Import API from a file or URL`. 386 | - Click on `Or import from URL...`. 387 | - Enter the url `https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/master/api-connect-resources/oauth_endpoint.yaml`. 388 | - The design tab for the API opens. Click on `OAuth 2`. 389 | - Scroll down to the `Authentication` section. For the `Authentication URL`, specify the login microservice url noted in the `Deploy login microservice` section. 390 | - Click on `Save` icon. 391 | 392 | ![Create OAuth API](./images/create_oauth_endpoint.gif) 393 | 394 | **Create API for Funds Transfer** 395 | 396 | We will use the file exported in the step `Export the App Connect Flow Rest interface` earlier. 397 | - On the API Connect Dashboard, click on `Drafts`. 398 | - Click on `APIs` 399 | - Click on `Add` and select `Import API from a file or URL`. 400 | - Click on `Browse` and select the file exported earlier from App Connect interface. 401 | - Click on `Import`. 402 | - The design tab for the API opens. Click on `Security Defintions`. 403 | - Click on `+` and select `OAuth` to create a new OAuth definition. 404 | - Scroll down to `Flow` section. Select `Access code`. 405 | - For `Authorization URL` enter the following URL - `http://[the end point url for API Connect noted earlier]/oauth-end/oauth2/authorize'. 406 | - For `Token URL` enter the following URL - `http://[the end point url for API Connect noted earlier]/oauth-end/oauth2/token'. 407 | - In the `Scopes` section, click on `+` to add a new scope. 408 | - Enter `funds_transfer` for the name. 409 | - Enter a description 410 | - Scroll down to the `Security` section. Select the newly created `OAuth` definition. The scope `funds_transfer` will get automatically selected. 411 | - Click on `Save` icon. 412 | 413 | ![Create Funds Transfer API](./images/create_funds_transfer_endpoint.gif) 414 | 415 | **Note the funds transfer endpoint url** 416 | 417 | On the funds transfer `Design` page: 418 | - Click on `Base Path` and note the base path. 419 | - Click on `Paths` and note the path. 420 | The funds transfer api endpoint url is [End point url for API Connect noted earlier]/[Base Path]/[Path]. 421 | 422 | It should look like - https://api.au-syd.apiconnect.appdomain.cloud/.../sb/Z1ZFXl/Fund_Transfer. 423 | 424 | ![Note funds transfer endpoint url](./images/note_fund_transfer_url.gif) 425 | 426 | **Create a product and publish** 427 | 428 | Go to `Drafts` and select `Products`. 429 | - Click on `Add + New Product`. 430 | - Enter `Title`, `Name` and `Version`. Click `Create`. 431 | - The `Design` page opens. 432 | - On the `Design` page, select `APIs`. 433 | - Click on `+` to add APIs. 434 | - Select both `OAuth endpoint` API and `Funds Transfer` API. 435 | - Click on `Save` icon. 436 | - Click on `Stage` icon and select `Sandbox`. 437 | - Go to `Dashboard`. 438 | - Click on `Sandbox`. 439 | - Click on the staged product. 440 | - Select `Publish` from the menu. 441 | - On the `dialog` that appears, click on `Publish` to publish the product. 442 | 443 | ![Create Product and Publish](./images/create_product_publish.gif) 444 | 445 | **Create an app on developer portal** 446 | 447 | - On the `Sandbox` dashboard, click on `Settings`. 448 | - Click on `Portal`. 449 | - Click on the `Portal` link. 450 | - On the portal page, click on `Create an account`. 451 | - Enter all the details and click `Create new account`. 452 | - Activate the account using the sent email. 453 | - Login to the portal with the chosen username and password. Click `Log-in`. 454 | - Click on `Apps`. 455 | - Click on `Create an App`. 456 | - Enter the `Title` and `Description`. For the `OAuth Redirect URI`, enter http://[Node RED Base URL noted earlier]/client. 457 | - Click `Submit`. 458 | - Note the `Client ID` generated for the created `App`. 459 | 460 | ![Create App](./images/create_app.gif) 461 | 462 | **Subscribe to a plan** 463 | 464 | On the developer portal, click on `API Products`. 465 | - Click on the product that we created earlier. 466 | - Click on `Subscribe` to subscribe to the default plan. 467 | 468 | ![Subscribe plan](./images/app_subscribe_plan.gif) 469 | 470 | ## 8. Deploy client application 471 | 472 | **Import the Node-RED flow and deploy** 473 | 474 | The Node-RED flow is available at: https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/master/client-app/node-red-flows/flows.json 475 | 476 | - Copy the raw contents from https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/master/client-app/node-red-flows/flows.json to the clipboard. 477 | - Go to the Node-RED flow editor. 478 | - Select `Import` and then `Clipboard` from menu. 479 | - Paste the copied contents. 480 | - Click on `Import`. 481 | - Click on `Deploy` to deploy the Node-RED flow. 482 | 483 | ![Deploy app](./images/deploy_client_app.gif) 484 | 485 | **Configure the application** 486 | 487 | Go to the URL: http://[Node-RED base url noted earlier]/configureui. 488 | Enter all the details and click `Configure`. 489 | ![Configure app](./images/configure_app.png) 490 | 491 | ## 9. Analyze the result 492 | 493 | As mentioned in `step 5`, a set of user credentials and bank account details are pre-defined in Mongo DB. 494 | 495 | Following are the users details (already saved in db): 496 | ``` 497 | {_id: "user1", password: "user1"} 498 | {_id: "user2", password: "user2"} 499 | {_id: "user3", password: "user3"} 500 | ``` 501 | 502 | Predefined accounts details are: 503 | ``` 504 | {_id: "121", accountholder: "John", funds: 25000} 505 | {_id: "122", accountholder: "Tim", funds: 15000} 506 | {_id: "123", accountholder: "Joseph", funds: 250000} 507 | {_id: "124", accountholder: "Mary", funds: 200000} 508 | ``` 509 | 510 | These users and account details can be used to use/test the application. 511 | 512 | Launch the application URL : 513 | ``` 514 | https:///login 515 | ``` 516 | 517 | - Enter username and password 518 | - Click `Allow Access` on the pop-up. The OAuth based authorization uses the `public access code` scheme. 519 | - Choose option - `Transfer funds to another account`. 520 | - Enter all the details for transfer. 521 | - Click `Transfer`. 522 | 523 | ![demo](./images/demo.gif) 524 | 525 | ## Learn More 526 | 527 | - [Securing an API by using OAuth 2.0](https://www.ibm.com/support/knowledgecenter/en/SSFS6T/com.ibm.apic.toolkit.doc/tutorial_apionprem_security_OAuth.html) 528 | - Introduction to App Connect on Cloud https://developer.ibm.com/integration/docs/app-connect/ 529 | - OpenAPI APIs https://developer.ibm.com/integration/docs/app-connect/how-to-guides-for-apps/use-ibm-app-connect-openapi/ 530 | - Creating flows for APIs https://developer.ibm.com/integration/docs/app-connect/tutorials-for-ibm-app-connect/creating-flows-api/ 531 | - Calling API in a flow https://developer.ibm.com/integration/docs/app-connect/creating-using-apis/calling-apis-flow/ 532 | - Toolbox flow https://developer.ibm.com/integration/docs/app-connect/toolbox-utilities/adding-conditional-logic-flow/ 533 | 534 | 535 | ## License 536 | 537 | This code pattern is licensed under the Apache Software License, Version 2. Separate third-party code objects invoked within this code pattern are licensed by their respective providers pursuant to their own separate licenses. Contributions are subject to the [Developer Certificate of Origin, Version 1.1 (DCO)](https://developercertificate.org/) and the [Apache Software License, Version 2](https://www.apache.org/licenses/LICENSE-2.0.txt). 538 | 539 | [Apache Software License (ASL) FAQ](https://www.apache.org/foundation/license-faq.html#WhatDoesItMEAN) 540 | 541 | -------------------------------------------------------------------------------- /TestServices.md: -------------------------------------------------------------------------------- 1 | ## Testing of Services 2 | 3 | The deployed microservices can be tested using a tool which enables people to test calls to APIs or using `curl` command. Here we are using `Postman` tool and also providing curl commands for test. Follow the below steps to test your deployed microservices. 4 | 5 | The microservices can be accessed by using `http://:`. 6 | 7 | For example, accessing the debit account microservice url will return something like this on your browser. 8 | 9 | ![](images/debit_account_service_msg.png) 10 | 11 | The following set of user credentials and the bank account details are already populated in Mongo DB to use/test the microservices. 12 | 13 | *Users details* 14 | 15 | ``` 16 | {_id: "user1", password: "user1"} 17 | {_id: "user2", password: "user2"} 18 | {_id: "user3", password: "user3"} 19 | ``` 20 | 21 | *Accounts details* 22 | 23 | ``` 24 | {_id: "121", accountholder: "John", funds: 25000} 25 | {_id: "122", accountholder: "Tim", funds: 15000} 26 | {_id: "123", accountholder: "Joseph", funds: 250000} 27 | {_id: "124", accountholder: "Mary", funds: 200000} 28 | ``` 29 | 30 | **Login Service** 31 | 32 | Following snapshot shows the given input and the output for the login microservice. 33 | 34 | ![](images/postman_loginservice.png) 35 | 36 | Login service uses Basic authorization. If you want to test using curl command, you need to encode username and password before submitting the request. 37 | The curl command for login service is: 38 | 39 | ``` 40 | curl -H "Authorization: Basic $(echo -n user1:user1 | base64)" http://:/login 41 | ``` 42 | 43 | **Account Management Service** 44 | 45 | The below snapshot shows the input and the output for the account management microservice. 46 | 47 | ![](images/postman_accmgmtservice.png) 48 | 49 | Here, input json is - 50 | ``` 51 | { 52 | "source_accountID":"121", 53 | "amount_to_transfer":1000, 54 | "target_accountID":"123" 55 | } 56 | ``` 57 | 58 | Alternate curl command is - 59 | 60 | ``` 61 | curl -X POST \ 62 | http://:/check_accounts \ 63 | -H 'cache-control: no-cache' \ 64 | -H 'content-type: application/json' \ 65 | -d '{ 66 | "source_accountID":"121", 67 | "amount_to_transfer":1000, 68 | "target_accountID":"123" 69 | }' 70 | ``` 71 | 72 | Corresponding pod logs can be checked for more details. 73 | 74 | ``` 75 | $ kubectl get pods 76 | $ kubectl logs -f 77 | 78 | # account_management_service pod will show something like this - 79 | 80 | {"source_accountID":"121","amount_to_transfer":1000,"target_accountID":"123"} 81 | Mongo DB connection successful 82 | Target account exists - [ { _id: '123', accountholder: 'Joseph', funds: 250000 } ] 83 | Source account exists - [ { _id: '121', accountholder: 'John', funds: 25000 } ] 84 | Sufficient funds to transfer 85 | {"responseCode":0,"message":"Sufficient funds to transfer"} 86 | ``` 87 | 88 | **Debit Account Service** 89 | 90 | It shows the input and the output for the debit account microservice. 91 | 92 | ![](images/postman_debitaccservice.png) 93 | 94 | Input JSON to API is - 95 | ``` 96 | { 97 | "source_accountID":"121", 98 | "amount_to_transfer":1000, 99 | "target_accountID":"123", 100 | "remarks":"Money transfer", 101 | "transfer_type":"IMPS" 102 | } 103 | ``` 104 | 105 | The curl command for the same: 106 | ``` 107 | curl -X POST \ 108 | http://:/debit_account \ 109 | -H 'cache-control: no-cache' \ 110 | -H 'content-type: application/json' \ 111 | -d '{ 112 | "source_accountID":"121", 113 | "amount_to_transfer":1000, 114 | "target_accountID":"123", 115 | "remarks":"Money transfer", 116 | "transfer_type":"IMPS" 117 | }' 118 | ``` 119 | 120 | Make a note of the transaction ID after successful debit transaction and provide this transaction ID for credit transaction to complete the funds transfer from one account to another. 121 | 122 | **Credit Account Service** 123 | 124 | It shows the input and the output for the credit account microservice. 125 | 126 | ![](images/postman_creditaccservice.png) 127 | 128 | Input JSON to API is - 129 | ``` 130 | { 131 | "source_accountID":"121", 132 | "amount_to_transfer":1000, 133 | "target_accountID":"123", 134 | "transactionID":"5f19d77bb56a587c07d61683" 135 | } 136 | ``` 137 | 138 | The curl command for the same: 139 | ``` 140 | curl -X POST \ 141 | http://:/credit_account \ 142 | -H 'cache-control: no-cache' \ 143 | -H 'content-type: application/json' \ 144 | -d '{ 145 | "source_accountID":"121", 146 | "amount_to_transfer":1000, 147 | "target_accountID":"123", 148 | "transactionID":"5f19d77bb56a587c07d61683" 149 | }' 150 | ``` 151 | 152 | 153 | Additionally the appropriate pod logs can be checked for more details of the transaction. 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /api-connect-resources/oauth_endpoint.yaml: -------------------------------------------------------------------------------- 1 | swagger: '2.0' 2 | info: 3 | x-ibm-name: oauth-endpoint-api 4 | title: OAuth Endpoint API 5 | version: 1.0.0 6 | schemes: 7 | - https 8 | host: $(catalog.host) 9 | basePath: /oauth-end 10 | securityDefinitions: 11 | clientID: 12 | description: "application's client_id" 13 | in: query 14 | name: client_id 15 | type: apiKey 16 | security: 17 | - clientID: [] 18 | paths: 19 | /oauth2/authorize: 20 | get: 21 | produces: 22 | - text/html 23 | summary: endpoint for Authorization Code and Implicit grants 24 | description: description 25 | parameters: 26 | - name: response_type 27 | in: query 28 | description: request an authorization code or or access token (implicit) 29 | required: true 30 | type: string 31 | enum: 32 | - code 33 | - token 34 | - name: scope 35 | in: query 36 | description: Scope being requested 37 | type: string 38 | required: true 39 | - name: redirect_uri 40 | in: query 41 | type: string 42 | description: URI where user is redirected to after authorization 43 | required: false 44 | - name: state 45 | in: query 46 | type: string 47 | description: This string will be echoed back to application when user is redirected 48 | required: false 49 | responses: 50 | '200': 51 | description: An HTML form for authentication or authorization of this request. 52 | '302': 53 | description: | 54 | Redirect to the clients redirect_uri containing one of the following 55 | - **authorization code** for Authorization code grant 56 | - **access token** for Implicity grant 57 | - **error** in case of errors, such as the user has denied the request 58 | security: 59 | - clientID: [] 60 | post: 61 | consumes: 62 | - application/x-www-form-urlencoded 63 | produces: 64 | - text/html 65 | summary: submit approval to authorization code or access token 66 | description: | 67 | Submit resource owners approval (or rejection) for the OAuth2 Server to issue an 68 | authorization code or access token to the application. 69 | security: [] 70 | parameters: 71 | - name: client_id 72 | in: formData 73 | description: application requesting the access code or token 74 | required: true 75 | type: string 76 | - name: scope 77 | in: formData 78 | description: requested scope of this authorization 79 | required: true 80 | type: string 81 | - name: resource-owner 82 | in: formData 83 | description: resource owners user name 84 | required: true 85 | type: string 86 | - name: redirect_uri 87 | in: formData 88 | description: URI the application is requesting this code or token to be redirected to 89 | required: true 90 | type: string 91 | - name: original-url 92 | in: formData 93 | description: URL of the original authorization request 94 | required: true 95 | type: string 96 | - name: dp-state 97 | in: formData 98 | description: state information provided in the authorization form 99 | required: true 100 | type: string 101 | - name: dp-data 102 | in: formData 103 | description: state information provided in the authorization form 104 | required: true 105 | type: string 106 | responses: 107 | '200': 108 | description: A consent form for oauth processing. 109 | /oauth2/token: 110 | post: 111 | consumes: 112 | - application/x-www-form-urlencoded 113 | produces: 114 | - application/json 115 | summary: Request Access Tokens 116 | description: | 117 | This endpoint allows requesting an access token following one of the flows below: 118 | - Authorization Code (exchange code for access token) 119 | - Client Credentials (2-legged, there isnt resource owner information) 120 | - Resource Owner Password Credentials (2-legged, client provides resource owner name and password) 121 | - Refresh Token (exchange refresh token for a new access code) 122 | 123 | The table below indicates the required parameters for each specific grant_type options. 124 | Empty cells indicate a parameter is ignored for that specific grant type. 125 | 126 | Client authentication: 127 | - Confidential clients should authenticate using HTTP Basic Authentication. Alternatively, they may post 128 | their client_id and client_secret information as a formData parameter. 129 | - Public clients should send their client_id as formData parameter. 130 | 131 | | grant_type | code | client_credentials | password | refresh_token | 132 | |----------------------|------------|--------------------|-------------|---------------| 133 | | client_id | required* | required* | required* | required* | 134 | | client_secret | required* | required* | required* | required* | 135 | | code | required | | | | 136 | | redirect_uri | required | | | | 137 | | username | | | required | | 138 | | password | | | required | | 139 | | scope | | optional | optional | | 140 | | refresh_token | | | | required | 141 | 142 | The implicit grant requests, see /oauth2/authorize. 143 | security: [] 144 | parameters: 145 | - name: grant_type 146 | in: formData 147 | description: Type of grant 148 | type: string 149 | required: true 150 | enum: 151 | - authorization_code 152 | - password 153 | - client_credentials 154 | - refresh_token 155 | - name: client_id 156 | in: formData 157 | description: 'Application client ID, can be provided in formData or using HTTP Basic Authentication' 158 | required: false 159 | type: string 160 | - name: client_secret 161 | in: formData 162 | description: 'Application secret, must be provided in formData or using HTTP Basic Authentication' 163 | required: false 164 | type: string 165 | - name: code 166 | in: formData 167 | description: Authorization code provided by the /oauth2/authorize endpoint 168 | required: false 169 | type: string 170 | - name: redirect_uri 171 | in: formData 172 | description: required only if the redirect_uri parameter was included in the authorization request /oauth2/authorize; their values MUST be identical. 173 | required: false 174 | type: string 175 | - name: username 176 | in: formData 177 | type: string 178 | description: Resource owner username 179 | required: false 180 | - name: password 181 | in: formData 182 | type: string 183 | description: Resource owner password 184 | required: false 185 | - name: scope 186 | in: formData 187 | type: string 188 | description: Scope being requested 189 | required: false 190 | - name: refresh_token 191 | in: formData 192 | type: string 193 | description: The refresh token that the client wants to exchange for a new access token (refresh_token grant_type) 194 | required: false 195 | responses: 196 | '200': 197 | description: 'json document containing token, etc.' 198 | schema: 199 | $ref: '#/definitions/access_token_response' 200 | '400': 201 | description: json document that may contain additional details about the failure 202 | x-ibm-configuration: 203 | testable: true 204 | enforced: true 205 | phase: realized 206 | oauth2: 207 | client-type: public 208 | scopes: 209 | funds_transfer: Transfer funds 210 | grants: 211 | - accessCode 212 | identity-extraction: 213 | type: default-form 214 | authentication: 215 | x-ibm-authentication-url: 216 | url: 'http://:32423/login' 217 | tls-profile: '' 218 | authorization: 219 | type: default-form 220 | access-token: 221 | ttl: 3600 222 | metadata: 223 | metadata-url: 224 | url: '' 225 | tls-profile: '' 226 | cors: 227 | enabled: true 228 | type: oauth 229 | definitions: 230 | access_token_response: 231 | type: object 232 | additionalProperties: false 233 | required: 234 | - token_type 235 | - access_token 236 | - expires_in 237 | properties: 238 | token_type: 239 | enum: 240 | - bearer 241 | access_token: 242 | type: string 243 | expires_in: 244 | type: integer 245 | scope: 246 | type: string 247 | refresh_token: 248 | type: string 249 | -------------------------------------------------------------------------------- /app-connect-resources/Flow.yaml: -------------------------------------------------------------------------------- 1 | $integration: 'http://ibm.com/appconnect/integration/v2/integrationFile' 2 | integration: 3 | type: api 4 | trigger-interfaces: 5 | trigger-interface-1: 6 | triggers: 7 | createFund_Transfer: 8 | assembly: 9 | $ref: '#/integration/assemblies/assembly-1' 10 | input-context: 11 | data: Fund_Transfer 12 | output-context: 13 | data: Fund_Transfer 14 | options: 15 | resources: 16 | - business-object: Fund_Transfer 17 | model: 18 | $ref: '#/models/Fund_Transfer' 19 | triggers: 20 | create: createFund_Transfer 21 | type: api-trigger 22 | action-interfaces: 23 | action-interface-1: 24 | type: api-action 25 | business-object: post_check_accounts_model 26 | connector-type: UDA.fsyf8ptni.openapi.Account_Check 27 | account-name: Account 1 28 | actions: 29 | post_check_accounts: {} 30 | action-interface-5: 31 | type: api-action 32 | business-object: post_debit_account_model 33 | connector-type: UDA.fsyf8ptni.openapi.Debit_Transaction 34 | account-name: Account 1 35 | actions: 36 | post_debit_account: {} 37 | action-interface-2: 38 | type: api-action 39 | business-object: post_credit_account_model 40 | connector-type: UDA.fsyf8ptni.openapi.Credit_Transaction 41 | account-name: Account 1 42 | actions: 43 | post_credit_account: {} 44 | action-interface-4: 45 | type: api-action 46 | business-object: post_credit_account_model 47 | connector-type: UDA.fsyf8ptni.openapi.Credit_Transaction 48 | account-name: Account 1 49 | actions: 50 | post_credit_account: {} 51 | assemblies: 52 | assembly-1: 53 | assembly: 54 | execute: 55 | - custom-action: 56 | name: Account_Check POST check_accounts 57 | target: 58 | $ref: '#/integration/action-interfaces/action-interface-1' 59 | action: post_check_accounts 60 | map: 61 | mappings: 62 | - body: 63 | mappings: 64 | - amount_to_transfer: 65 | expression: '$Request.amount_to_transfer ' 66 | - source_accountID: 67 | template: '{{$Request.source_accountID}}' 68 | - target_accountID: 69 | template: '{{$Request.target_accountID}}' 70 | $map: 'http://ibm.com/appconnect/map/v1' 71 | input: 72 | - variable: Request 73 | $ref: '#/trigger/payload' 74 | - if: 75 | name: If 76 | input: 77 | - variable: Request 78 | $ref: '#/trigger/payload' 79 | - variable: AccountCheckPOSTcheckaccounts 80 | $ref: >- 81 | #/node-output/Account_Check POST 82 | check_accounts/response/payload 83 | - variable: AccountCheckPOSTcheckaccountsMetadata 84 | $ref: '#/node-output/Account_Check POST check_accounts/response' 85 | branch: 86 | - condition: 87 | and: 88 | - '{{$AccountCheckPOSTcheckaccountsMetadata."status-code"}}': '200' 89 | - '{{$AccountCheckPOSTcheckaccounts.response."200".responseCode}}': '0' 90 | execute: 91 | - custom-action: 92 | name: Debit_Transaction POST debit_account 2 93 | target: 94 | $ref: '#/integration/action-interfaces/action-interface-5' 95 | action: post_debit_account 96 | map: 97 | mappings: 98 | - body: 99 | mappings: 100 | - amount_to_transfer: 101 | expression: '$Request.amount_to_transfer ' 102 | - remarks: 103 | template: '{{$Request.remarks}}' 104 | - source_accountID: 105 | template: '{{$Request.source_accountID}}' 106 | - transfer_type: 107 | template: '{{$Request.transfer_type}}' 108 | $map: 'http://ibm.com/appconnect/map/v1' 109 | input: 110 | - variable: Request 111 | $ref: '#/trigger/payload' 112 | - variable: AccountCheckPOSTcheckaccounts 113 | $ref: >- 114 | #/node-output/Account_Check POST 115 | check_accounts/response/payload 116 | - variable: AccountCheckPOSTcheckaccountsMetadata 117 | $ref: >- 118 | #/node-output/Account_Check POST 119 | check_accounts/response 120 | - if: 121 | name: If 2 122 | input: 123 | - variable: Request 124 | $ref: '#/trigger/payload' 125 | - variable: DebitTransactionPOSTdebitaccount2 126 | $ref: >- 127 | #/block/If/node-output/Debit_Transaction POST 128 | debit_account 2/response/payload 129 | - variable: DebitTransactionPOSTdebitaccount2Metadata 130 | $ref: >- 131 | #/block/If/node-output/Debit_Transaction POST 132 | debit_account 2/response 133 | - variable: AccountCheckPOSTcheckaccounts 134 | $ref: >- 135 | #/node-output/Account_Check POST 136 | check_accounts/response/payload 137 | - variable: AccountCheckPOSTcheckaccountsMetadata 138 | $ref: >- 139 | #/node-output/Account_Check POST 140 | check_accounts/response 141 | branch: 142 | - condition: 143 | and: 144 | - '{{$DebitTransactionPOSTdebitaccount2Metadata."status-code"}}': '200' 145 | - '{{$DebitTransactionPOSTdebitaccount2.response."200".responseCode}}': '0' 146 | execute: 147 | - custom-action: 148 | name: Credit_Transaction POST credit_account 149 | target: 150 | $ref: >- 151 | #/integration/action-interfaces/action-interface-2 152 | action: post_credit_account 153 | map: 154 | mappings: 155 | - body: 156 | mappings: 157 | - amount_to_transfer: 158 | expression: '$Request.amount_to_transfer ' 159 | - target_accountID: 160 | template: '{{$Request.target_accountID}}' 161 | - transactionID: 162 | template: >- 163 | {{$DebitTransactionPOSTdebitaccount2.response."200".transactionID}} 164 | $map: 'http://ibm.com/appconnect/map/v1' 165 | input: 166 | - variable: Request 167 | $ref: '#/trigger/payload' 168 | - variable: DebitTransactionPOSTdebitaccount2 169 | $ref: >- 170 | #/block/If/node-output/Debit_Transaction POST 171 | debit_account 2/response/payload 172 | - variable: DebitTransactionPOSTdebitaccount2Metadata 173 | $ref: >- 174 | #/block/If/node-output/Debit_Transaction POST 175 | debit_account 2/response 176 | - variable: AccountCheckPOSTcheckaccounts 177 | $ref: >- 178 | #/node-output/Account_Check POST 179 | check_accounts/response/payload 180 | - variable: AccountCheckPOSTcheckaccountsMetadata 181 | $ref: >- 182 | #/node-output/Account_Check POST 183 | check_accounts/response 184 | - if: 185 | name: If 3 186 | input: 187 | - variable: Request 188 | $ref: '#/trigger/payload' 189 | - variable: CreditTransactionPOSTcreditaccount 190 | $ref: >- 191 | #/block/If 2/node-output/Credit_Transaction POST 192 | credit_account/response/payload 193 | - variable: CreditTransactionPOSTcreditaccountMetadata 194 | $ref: >- 195 | #/block/If 2/node-output/Credit_Transaction POST 196 | credit_account/response 197 | - variable: DebitTransactionPOSTdebitaccount2 198 | $ref: >- 199 | #/block/If/node-output/Debit_Transaction POST 200 | debit_account 2/response/payload 201 | - variable: DebitTransactionPOSTdebitaccount2Metadata 202 | $ref: >- 203 | #/block/If/node-output/Debit_Transaction POST 204 | debit_account 2/response 205 | - variable: AccountCheckPOSTcheckaccounts 206 | $ref: >- 207 | #/node-output/Account_Check POST 208 | check_accounts/response/payload 209 | - variable: AccountCheckPOSTcheckaccountsMetadata 210 | $ref: >- 211 | #/node-output/Account_Check POST 212 | check_accounts/response 213 | branch: 214 | - condition: 215 | and: 216 | - '{{$CreditTransactionPOSTcreditaccountMetadata."status-code"}}': '200' 217 | - '{{$CreditTransactionPOSTcreditaccount.response."200".responseCode}}': '0' 218 | execute: [] 219 | map: 220 | $map: 'http://ibm.com/appconnect/map/v1' 221 | input: 222 | - variable: Request 223 | $ref: '#/trigger/payload' 224 | - variable: CreditTransactionPOSTcreditaccount 225 | $ref: >- 226 | #/block/If 2/node-output/Credit_Transaction POST 227 | credit_account/response/payload 228 | - variable: CreditTransactionPOSTcreditaccountMetadata 229 | $ref: >- 230 | #/block/If 2/node-output/Credit_Transaction POST 231 | credit_account/response 232 | - variable: DebitTransactionPOSTdebitaccount2 233 | $ref: >- 234 | #/block/If/node-output/Debit_Transaction POST 235 | debit_account 2/response/payload 236 | - variable: DebitTransactionPOSTdebitaccount2Metadata 237 | $ref: >- 238 | #/block/If/node-output/Debit_Transaction POST 239 | debit_account 2/response 240 | - variable: AccountCheckPOSTcheckaccounts 241 | $ref: >- 242 | #/node-output/Account_Check POST 243 | check_accounts/response/payload 244 | - variable: AccountCheckPOSTcheckaccountsMetadata 245 | $ref: >- 246 | #/node-output/Account_Check POST 247 | check_accounts/response 248 | mappings: 249 | - ceditTransactionID: 250 | template: >- 251 | {{$CreditTransactionPOSTcreditaccount.response."200".transactionID}} 252 | - creditResponseCode: 253 | template: >- 254 | {{$CreditTransactionPOSTcreditaccount.response."200".responseCode}} 255 | - creditResponseMessage: 256 | template: >- 257 | {{$CreditTransactionPOSTcreditaccount.response."200".message}} 258 | - condition: 259 | '{{$CreditTransactionPOSTcreditaccount.response."200".responseCode}}': '1' 260 | execute: 261 | - custom-action: 262 | name: Credit_Transaction POST credit_account 3 263 | target: 264 | $ref: >- 265 | #/integration/action-interfaces/action-interface-4 266 | action: post_credit_account 267 | map: 268 | mappings: 269 | - body: 270 | mappings: 271 | - amount_to_transfer: 272 | expression: '$Request.amount_to_transfer ' 273 | - target_accountID: 274 | template: '{{$Request.source_accountID}}' 275 | $map: 'http://ibm.com/appconnect/map/v1' 276 | input: 277 | - variable: Request 278 | $ref: '#/trigger/payload' 279 | - variable: CreditTransactionPOSTcreditaccount 280 | $ref: >- 281 | #/block/If 2/node-output/Credit_Transaction POST 282 | credit_account/response/payload 283 | - variable: CreditTransactionPOSTcreditaccountMetadata 284 | $ref: >- 285 | #/block/If 2/node-output/Credit_Transaction POST 286 | credit_account/response 287 | - variable: DebitTransactionPOSTdebitaccount2 288 | $ref: >- 289 | #/block/If/node-output/Debit_Transaction POST 290 | debit_account 2/response/payload 291 | - variable: DebitTransactionPOSTdebitaccount2Metadata 292 | $ref: >- 293 | #/block/If/node-output/Debit_Transaction POST 294 | debit_account 2/response 295 | - variable: AccountCheckPOSTcheckaccounts 296 | $ref: >- 297 | #/node-output/Account_Check POST 298 | check_accounts/response/payload 299 | - variable: AccountCheckPOSTcheckaccountsMetadata 300 | $ref: >- 301 | #/node-output/Account_Check POST 302 | check_accounts/response 303 | map: 304 | $map: 'http://ibm.com/appconnect/map/v1' 305 | input: 306 | - variable: Request 307 | $ref: '#/trigger/payload' 308 | - variable: CreditTransactionPOSTcreditaccount3 309 | $ref: >- 310 | #/block/If 3/node-output/Credit_Transaction POST 311 | credit_account 3/response/payload 312 | - variable: CreditTransactionPOSTcreditaccount3Metadata 313 | $ref: >- 314 | #/block/If 3/node-output/Credit_Transaction POST 315 | credit_account 3/response 316 | - variable: CreditTransactionPOSTcreditaccount 317 | $ref: >- 318 | #/block/If 2/node-output/Credit_Transaction POST 319 | credit_account/response/payload 320 | - variable: CreditTransactionPOSTcreditaccountMetadata 321 | $ref: >- 322 | #/block/If 2/node-output/Credit_Transaction POST 323 | credit_account/response 324 | - variable: DebitTransactionPOSTdebitaccount2 325 | $ref: >- 326 | #/block/If/node-output/Debit_Transaction POST 327 | debit_account 2/response/payload 328 | - variable: DebitTransactionPOSTdebitaccount2Metadata 329 | $ref: >- 330 | #/block/If/node-output/Debit_Transaction POST 331 | debit_account 2/response 332 | - variable: AccountCheckPOSTcheckaccounts 333 | $ref: >- 334 | #/node-output/Account_Check POST 335 | check_accounts/response/payload 336 | - variable: AccountCheckPOSTcheckaccountsMetadata 337 | $ref: >- 338 | #/node-output/Account_Check POST 339 | check_accounts/response 340 | mappings: 341 | - ceditTransactionID: 342 | template: >- 343 | {{$CreditTransactionPOSTcreditaccount3.response."200".transactionID}} 344 | - creditResponseCode: 345 | template: >- 346 | {{$CreditTransactionPOSTcreditaccount3.response."200".responseCode}} 347 | - creditResponseMessage: 348 | template: >- 349 | {{$CreditTransactionPOSTcreditaccount3.response."200".message}} 350 | else: 351 | execute: [] 352 | completion-action: 353 | terminate: 354 | error: 355 | input: 356 | - variable: Request 357 | $ref: '#/trigger/payload' 358 | - variable: CreditTransactionPOSTcreditaccount 359 | $ref: >- 360 | #/block/If 2/node-output/Credit_Transaction POST 361 | credit_account/response/payload 362 | - variable: CreditTransactionPOSTcreditaccountMetadata 363 | $ref: >- 364 | #/block/If 2/node-output/Credit_Transaction POST 365 | credit_account/response 366 | - variable: DebitTransactionPOSTdebitaccount2 367 | $ref: >- 368 | #/block/If/node-output/Debit_Transaction POST 369 | debit_account 2/response/payload 370 | - variable: DebitTransactionPOSTdebitaccount2Metadata 371 | $ref: >- 372 | #/block/If/node-output/Debit_Transaction POST 373 | debit_account 2/response 374 | - variable: AccountCheckPOSTcheckaccounts 375 | $ref: >- 376 | #/node-output/Account_Check POST 377 | check_accounts/response/payload 378 | - variable: AccountCheckPOSTcheckaccountsMetadata 379 | $ref: >- 380 | #/node-output/Account_Check POST 381 | check_accounts/response 382 | message: >- 383 | Unknown error occurred. Check log for 384 | more details 385 | status-code: 400 386 | output-schema: 387 | required: [] 388 | properties: 389 | ceditTransactionID: 390 | type: string 391 | title: ceditTransactionID 392 | creditResponseCode: 393 | type: string 394 | title: creditResponseCode 395 | creditResponseMessage: 396 | type: string 397 | title: creditResponseMessage 398 | title: Output Schema 399 | type: object 400 | map: 401 | $map: 'http://ibm.com/appconnect/map/v1' 402 | input: 403 | - variable: Request 404 | $ref: '#/trigger/payload' 405 | - variable: CreditTransactionPOSTcreditaccount 406 | $ref: >- 407 | #/block/If 2/node-output/Credit_Transaction POST 408 | credit_account/response/payload 409 | - variable: CreditTransactionPOSTcreditaccountMetadata 410 | $ref: >- 411 | #/block/If 2/node-output/Credit_Transaction POST 412 | credit_account/response 413 | - variable: If3 414 | $ref: >- 415 | #/block/If 2/node-output/If 416 | 3/response/payload 417 | - variable: DebitTransactionPOSTdebitaccount2 418 | $ref: >- 419 | #/block/If/node-output/Debit_Transaction POST 420 | debit_account 2/response/payload 421 | - variable: DebitTransactionPOSTdebitaccount2Metadata 422 | $ref: >- 423 | #/block/If/node-output/Debit_Transaction POST 424 | debit_account 2/response 425 | - variable: AccountCheckPOSTcheckaccounts 426 | $ref: >- 427 | #/node-output/Account_Check POST 428 | check_accounts/response/payload 429 | - variable: AccountCheckPOSTcheckaccountsMetadata 430 | $ref: >- 431 | #/node-output/Account_Check POST 432 | check_accounts/response 433 | mappings: 434 | - debitResponseCode: 435 | template: '{{$If3.creditResponseCode}}' 436 | - debitResponseMessage: 437 | template: '{{$If3.creditResponseMessage}}' 438 | - debitTransactionID: 439 | template: '{{$If3.ceditTransactionID}}' 440 | else: 441 | execute: [] 442 | completion-action: 443 | terminate: 444 | error: 445 | input: 446 | - variable: Request 447 | $ref: '#/trigger/payload' 448 | - variable: DebitTransactionPOSTdebitaccount2 449 | $ref: >- 450 | #/block/If/node-output/Debit_Transaction POST 451 | debit_account 2/response/payload 452 | - variable: DebitTransactionPOSTdebitaccount2Metadata 453 | $ref: >- 454 | #/block/If/node-output/Debit_Transaction POST 455 | debit_account 2/response 456 | - variable: AccountCheckPOSTcheckaccounts 457 | $ref: >- 458 | #/node-output/Account_Check POST 459 | check_accounts/response/payload 460 | - variable: AccountCheckPOSTcheckaccountsMetadata 461 | $ref: >- 462 | #/node-output/Account_Check POST 463 | check_accounts/response 464 | message: >- 465 | {{$DebitTransactionPOSTdebitaccount2.response."200".message}} 466 | status-code: 400 467 | output-schema: 468 | required: [] 469 | properties: 470 | debitTransactionID: 471 | type: string 472 | title: debitTransactionID 473 | debitResponseCode: 474 | type: string 475 | title: debitResponseCode 476 | debitResponseMessage: 477 | type: string 478 | title: debitResponseMessage 479 | title: Output Schema 480 | type: object 481 | map: 482 | $map: 'http://ibm.com/appconnect/map/v1' 483 | input: 484 | - variable: Request 485 | $ref: '#/trigger/payload' 486 | - variable: DebitTransactionPOSTdebitaccount2 487 | $ref: >- 488 | #/block/If/node-output/Debit_Transaction POST debit_account 489 | 2/response/payload 490 | - variable: DebitTransactionPOSTdebitaccount2Metadata 491 | $ref: >- 492 | #/block/If/node-output/Debit_Transaction POST debit_account 493 | 2/response 494 | - variable: If2 495 | $ref: '#/block/If/node-output/If 2/response/payload' 496 | - variable: AccountCheckPOSTcheckaccounts 497 | $ref: >- 498 | #/node-output/Account_Check POST 499 | check_accounts/response/payload 500 | - variable: AccountCheckPOSTcheckaccountsMetadata 501 | $ref: >- 502 | #/node-output/Account_Check POST 503 | check_accounts/response 504 | mappings: 505 | - acCheckResponse: 506 | template: '{{$If2.debitResponseMessage}}' 507 | - acCheckResponseCode: 508 | template: '{{$If2.debitResponseCode}}' 509 | - acCheckTransactionID: 510 | template: '{{$If2.debitTransactionID}}' 511 | else: 512 | execute: [] 513 | completion-action: 514 | terminate: 515 | error: 516 | input: 517 | - variable: Request 518 | $ref: '#/trigger/payload' 519 | - variable: AccountCheckPOSTcheckaccounts 520 | $ref: >- 521 | #/node-output/Account_Check POST 522 | check_accounts/response/payload 523 | - variable: AccountCheckPOSTcheckaccountsMetadata 524 | $ref: >- 525 | #/node-output/Account_Check POST 526 | check_accounts/response 527 | message: >- 528 | {{$AccountCheckPOSTcheckaccounts.response."200".responseMsg}}{{$AccountCheckPOSTcheckaccounts.response."200".responseMsg}} 529 | status-code: 400 530 | output-schema: 531 | required: [] 532 | properties: 533 | acCheckTransactionID: 534 | type: string 535 | title: acCheckTransactionID 536 | acCheckResponseCode: 537 | type: string 538 | title: acCheckResponseCode 539 | acCheckResponse: 540 | type: string 541 | title: acCheckResponse 542 | title: Output Schema 543 | type: object 544 | - response: 545 | name: response-1 546 | reply-maps: 547 | - title: Fund_Transfer successfully created 548 | status-code: '200' 549 | map: 550 | $map: 'http://ibm.com/appconnect/map/v1' 551 | input: 552 | - variable: Request 553 | $ref: '#/trigger/payload' 554 | - variable: AccountCheckPOSTcheckaccounts 555 | $ref: >- 556 | #/node-output/Account_Check POST 557 | check_accounts/response/payload 558 | - variable: AccountCheckPOSTcheckaccountsMetadata 559 | $ref: >- 560 | #/node-output/Account_Check POST 561 | check_accounts/response 562 | - variable: If 563 | $ref: '#/node-output/If/response/payload' 564 | mappings: 565 | - amount_to_transfer: 566 | expression: '$Request.amount_to_transfer ' 567 | - remarks: 568 | template: '{{$Request.remarks}}' 569 | - request_no: 570 | template: '{{$ceil($random() *100000000)}}' 571 | - responseCode: 572 | template: '{{$If.acCheckResponseCode}}' 573 | - responseMsg: 574 | template: '{{$If.acCheckResponse}}' 575 | - source_accountID: 576 | template: '{{$Request.source_accountID}}' 577 | - target_accountID: 578 | template: '{{$Request.target_accountID}}' 579 | - transactionID: 580 | template: '{{$If.acCheckTransactionID}}' 581 | - transfer_type: 582 | template: '{{$Request.transfer_type}}' 583 | input: 584 | - variable: Request 585 | $ref: '#/trigger/payload' 586 | - variable: AccountCheckPOSTcheckaccounts 587 | $ref: >- 588 | #/node-output/Account_Check POST 589 | check_accounts/response/payload 590 | - variable: AccountCheckPOSTcheckaccountsMetadata 591 | $ref: >- 592 | #/node-output/Account_Check POST 593 | check_accounts/response 594 | - variable: If 595 | $ref: '#/node-output/If/response/payload' 596 | name: Fund Transfer 597 | models: 598 | Fund_Transfer: 599 | name: Fund_Transfer 600 | properties: 601 | request_no: 602 | required: false 603 | id: true 604 | type: string 605 | source_accountID: 606 | required: false 607 | id: false 608 | type: string 609 | target_accountID: 610 | required: false 611 | id: false 612 | type: string 613 | amount_to_transfer: 614 | required: false 615 | id: false 616 | type: number 617 | transfer_type: 618 | required: false 619 | id: false 620 | type: string 621 | remarks: 622 | required: false 623 | id: false 624 | type: string 625 | transactionID: 626 | required: false 627 | id: false 628 | type: string 629 | responseCode: 630 | required: false 631 | id: false 632 | type: string 633 | responseMsg: 634 | required: false 635 | id: false 636 | type: string 637 | plural: Fund_Transfer 638 | description: ' ' 639 | operations: 640 | create: '#/integration/assemblies/assembly-1' 641 | -------------------------------------------------------------------------------- /app-connect-resources/microservices-apis/Account_Check.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Account Check", 5 | "description": "Check if a transfer can be made to an account or not", 6 | "version": "1.0.0" 7 | }, 8 | "basePath": "/", 9 | "host": ".", 10 | "schemes": [ 11 | "http" 12 | ], 13 | "paths": { 14 | "/check_accounts": { 15 | "post": { 16 | "consumes": [ 17 | "application/json" 18 | ], 19 | "produces": [ 20 | "application/json" 21 | ], 22 | "parameters": [ 23 | { 24 | "in": "body", 25 | "name": "body", 26 | "description": "Account Check", 27 | "required": true, 28 | "schema": { 29 | "$ref": "#/definitions/account_check_input" 30 | } 31 | } 32 | ], 33 | "responses": { 34 | "200": { 35 | "description": "successful operation", 36 | "schema": { 37 | "$ref": "#/definitions/account_check_output" 38 | } 39 | }, 40 | "500": { 41 | "description": "Internal Server Error" 42 | } 43 | } 44 | } 45 | } 46 | }, 47 | "definitions": { 48 | "account_check_input": { 49 | "type": "object", 50 | "properties": { 51 | "source_accountID": { 52 | "type": "string" 53 | }, 54 | "amount_to_transfer": { 55 | "type": "integer" 56 | }, 57 | "target_accountID": { 58 | "type": "string" 59 | } 60 | } 61 | }, 62 | "account_check_output": { 63 | "type": "object", 64 | "properties": { 65 | "responseCode": { 66 | "type": "integer" 67 | }, 68 | "responseMsg": { 69 | "type": "string" 70 | } 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app-connect-resources/microservices-apis/Credit_Transaction.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Credit Transaction", 5 | "description": "Credit an account", 6 | "version": "1.0.0" 7 | }, 8 | "host": ".", 9 | "basePath": "/", 10 | "schemes": [ 11 | "http" 12 | ], 13 | "paths": { 14 | "/credit_account": { 15 | "post": { 16 | "consumes": [ 17 | "application/json" 18 | ], 19 | "produces": [ 20 | "application/json" 21 | ], 22 | "parameters": [ 23 | { 24 | "in": "body", 25 | "name": "body", 26 | "description": "Credit account", 27 | "required": true, 28 | "schema": { 29 | "$ref": "#/definitions/credit_input" 30 | } 31 | } 32 | ], 33 | "responses": { 34 | "200": { 35 | "description": "successful operation", 36 | "schema": { 37 | "$ref": "#/definitions/credit_output" 38 | } 39 | }, 40 | "500": { 41 | "description": "Internal Server Error" 42 | } 43 | } 44 | } 45 | } 46 | }, 47 | "definitions": { 48 | "credit_input": { 49 | "type": "object", 50 | "properties": { 51 | "transactionID": { 52 | "type": "string" 53 | }, 54 | "target_accountID": { 55 | "type": "string" 56 | }, 57 | "amount_to_transfer": { 58 | "type": "integer" 59 | } 60 | } 61 | }, 62 | "credit_output": { 63 | "type": "object", 64 | "properties": { 65 | "responseCode": { 66 | "type": "integer" 67 | }, 68 | "message": { 69 | "type": "string" 70 | }, 71 | "transactionID": { 72 | "type": "string" 73 | } 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app-connect-resources/microservices-apis/Debit_Transaction.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Debit Transaction", 5 | "description": "Debit an account", 6 | "version": "1.0.0" 7 | }, 8 | "host": ".", 9 | "basePath": "/", 10 | "schemes": [ 11 | "http" 12 | ], 13 | "paths": { 14 | "/debit_account": { 15 | "post": { 16 | "consumes": [ 17 | "application/json" 18 | ], 19 | "produces": [ 20 | "application/json" 21 | ], 22 | "parameters": [ 23 | { 24 | "in": "body", 25 | "name": "body", 26 | "description": "Debit account", 27 | "required": true, 28 | "schema": { 29 | "$ref": "#/definitions/debit_input" 30 | } 31 | } 32 | ], 33 | "responses": { 34 | "200": { 35 | "description": "successful operation", 36 | "schema": { 37 | "$ref": "#/definitions/debit_output" 38 | } 39 | }, 40 | "500": { 41 | "description": "Internal Server Error" 42 | } 43 | } 44 | } 45 | } 46 | }, 47 | "definitions": { 48 | "debit_input": { 49 | "type": "object", 50 | "properties": { 51 | "source_accountID": { 52 | "type": "string" 53 | }, 54 | "amount_to_transfer": { 55 | "type": "integer" 56 | }, 57 | "transfer_type": { 58 | "type": "string" 59 | }, 60 | "remarks": { 61 | "type": "string" 62 | } 63 | } 64 | }, 65 | "debit_output": { 66 | "type": "object", 67 | "properties": { 68 | "responseCode": { 69 | "type": "integer" 70 | }, 71 | "message": { 72 | "type": "string" 73 | }, 74 | "transactionID": { 75 | "type": "string" 76 | } 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /client-app/node-red-flows/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /client-app/node-red-flows/flows.json: -------------------------------------------------------------------------------- 1 | [{"id":"c6bbf06d.815c5","type":"tab","label":"pattern","disabled":false,"info":""},{"id":"f65e962c.de225","type":"http in","z":"c6bbf06d.815c5","name":"","url":"client","method":"get","upload":false,"swaggerDoc":"","x":80,"y":800,"wires":[["285c3d20.6b7442"]]},{"id":"28e32e4a.11e5aa","type":"http request","z":"c6bbf06d.815c5","name":"Get token","method":"POST","ret":"txt","paytoqs":false,"url":"","tls":"","proxy":"","authType":"basic","x":460,"y":800,"wires":[["26595f8c.942c6"]]},{"id":"285c3d20.6b7442","type":"function","z":"c6bbf06d.815c5","name":"","func":"var globalContext = global;\n\nmsg.url=globalContext.get(\"oauth_token_url\");\nmsg.headers = {};\nmsg.headers['Content-Type'] = 'application/x-www-form-urlencoded';\nmsg.payload.grant_type='authorization_code';\nmsg.payload.redirect_uri=globalContext.get(\"redirect_url\");\nmsg.payload.client_id=globalContext.get(\"client_id\");\nmsg.payload.domain = globalContext.get(\"node_red_url\").substring(8);\nreturn msg;","outputs":1,"noerr":0,"x":270,"y":800,"wires":[["28e32e4a.11e5aa"]]},{"id":"26595f8c.942c6","type":"function","z":"c6bbf06d.815c5","name":"","func":"var jsonobj = JSON.parse(msg.payload)\nnode.error(jsonobj.access_token);\nvar globalContext = global;\nglobalContext.set(\"access_token\",jsonobj.access_token);\nmsg.payload={};\nmsg.payload.url=globalContext.get(\"node_red_url\")+\"/menus\";\nmsg.payload.token = jsonobj.access_token;\nreturn msg;","outputs":1,"noerr":0,"x":630,"y":800,"wires":[["9fe03781.b5c118"]]},{"id":"af023898.f95ea8","type":"template","z":"c6bbf06d.815c5","name":"Login","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n\n\n\n\nCode Bank | Login\n\n\n\n\n\n\n\n\n\n\t\n\t\t
\n\t\t\tCode Bank \n\t\t\t\n\n\t\t\t
\n\t\t\t\t
    \n\t\t\t\t\t
  • Login
  • \n\t\t\t\t
\n\n\t\t\t
\n\t\t
\n\t\n\n\t
\n\t
\n\t\t
\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t
Login
\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t
\n\t\t
\n\t
\n\t
\n\n\n\n\n","output":"str","x":530,"y":60,"wires":[["220f9850.c43df8"]]},{"id":"64360e03.3772e","type":"http in","z":"c6bbf06d.815c5","name":"","url":"login","method":"get","upload":false,"swaggerDoc":"","x":80,"y":60,"wires":[["95cd613f.395328"]]},{"id":"220f9850.c43df8","type":"http response","z":"c6bbf06d.815c5","name":"","statusCode":"","headers":{},"x":750,"y":60,"wires":[]},{"id":"bf31cf8b.2cc6d8","type":"http in","z":"c6bbf06d.815c5","name":"","url":"menus","method":"get","upload":false,"swaggerDoc":"","x":90,"y":300,"wires":[["bb90e0.960a872"]]},{"id":"7722cac2.11a60c","type":"http response","z":"c6bbf06d.815c5","name":"","statusCode":"","headers":{},"x":530,"y":300,"wires":[]},{"id":"bb90e0.960a872","type":"template","z":"c6bbf06d.815c5","name":"Menus","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n\n\n\n\nCode Bank | Menu\n\n\n\n\n\n\n\n\n\n\t\n\t\t
\n\t\t\tCode Bank\n\t\t\t\n\n\t\t\t
\n\t\t\t\t
    \n\t\t\t\t\t
  • Home\n\t\t\t\t\t
  • \n\t\t\t\t\t
  • Logout\n\t\t\t\t\t
  • \n\t\t\t\t
\n\n\t\t\t
\n\t\t
\n\t\n\n\t
\n\t
\n\t\t
\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t
What do you wish to do today?
\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t
\n\t\t
\n\t
\n\n\t
\n\n","output":"str","x":310,"y":300,"wires":[["7722cac2.11a60c"]]},{"id":"29d98eb5.b1a752","type":"http response","z":"c6bbf06d.815c5","name":"","statusCode":"","headers":{},"x":1110,"y":800,"wires":[]},{"id":"98d7d99b.d746a","type":"http in","z":"c6bbf06d.815c5","name":"","url":"transfer","method":"post","upload":false,"swaggerDoc":"","x":100,"y":400,"wires":[["20fe935b.0e9cec"]]},{"id":"4b50b12b.6aa34","type":"function","z":"c6bbf06d.815c5","name":"","func":"msg.headers = {};\nmsg.headers['X-IBM-Client-Id']= msg.payload.client_id;\nvar globalContext = global;\nnode.error(msg.payload.inputaccesstoken);\nmsg.headers['Authorization']= 'Bearer '+msg.payload.inputaccesstoken;\nmsg.url = globalContext.get(\"transfer_url\");\nreturn msg;","outputs":1,"noerr":0,"x":410,"y":400,"wires":[["7b99770f.8d6ef"]]},{"id":"7b99770f.8d6ef","type":"http request","z":"c6bbf06d.815c5","name":"Transfer funds","method":"POST","ret":"txt","paytoqs":false,"url":"","tls":"","proxy":"","authType":"basic","x":600,"y":400,"wires":[["9cb826c7.24c0f8"]]},{"id":"a138ca28.343908","type":"http response","z":"c6bbf06d.815c5","name":"","statusCode":"","headers":{},"x":1270,"y":400,"wires":[]},{"id":"a01df5d2.9286e8","type":"http in","z":"c6bbf06d.815c5","name":"","url":"transferui","method":"get","upload":false,"swaggerDoc":"","x":100,"y":500,"wires":[["28e37ecb.8f730a"]]},{"id":"294bce94.2a278a","type":"template","z":"c6bbf06d.815c5","name":"Funds Transfer UI","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n\n\n\n\nCode Bank | Transfer Funds\n\n\n\n\n\n\n\n\n\n\t\n\t\t
\n\t\t\tCode Bank\n\t\t\t\n\n\t\t\t
\n\t\t\t\t
    \n\t\t\t\t\t
  • Home\n\t\t\t\t\t
  • \n\t\t\t\t\t
  • Logout\n\t\t\t\t\t
  • \n\t\t\t\t
\n\n\t\t\t
\n\t\t
\n\t\n\n\t
\n\t
\n\t\t
\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t
Transfer Funds
\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\n\t\t\t\t
\n\t\t\t
\n\t\t
\n\t
\n\n\t
\n\n\t\n\n\n\n\n","output":"str","x":490,"y":500,"wires":[["6f5579ea.009028"]]},{"id":"6f5579ea.009028","type":"http response","z":"c6bbf06d.815c5","name":"","statusCode":"","headers":{},"x":730,"y":500,"wires":[]},{"id":"fed7500a.128a68","type":"template","z":"c6bbf06d.815c5","name":"Transaction Summary Page","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n\n\n \n \n Code Bank | Summary\n \n \n \n \n \n\n\n\n\n
\n
\n
\n
\n
\n
Transaction Summary
\n
\n
\n \n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n

{{{payload.errordesc}}}

\n
\n
\n
\n
\n
\n\n
\n\n\n","output":"str","x":1040,"y":400,"wires":[["a138ca28.343908"]]},{"id":"9cb826c7.24c0f8","type":"function","z":"c6bbf06d.815c5","name":"","func":"var jsonobj = JSON.parse(msg.payload);\nmsg.payload = {};\nmsg.payload = jsonobj;\nif (!jsonobj.request_no)\n{\n msg.payload.error=\"Some error occured\";\n msg.payload.errordesc=JSON.stringify(jsonobj);\n}\nreturn msg;","outputs":1,"noerr":0,"x":810,"y":400,"wires":[["fed7500a.128a68"]]},{"id":"9fe03781.b5c118","type":"template","z":"c6bbf06d.815c5","name":"Redirect to Menu","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n\n\n \n \n Code Bank | Authentication Successful!\n \n \n \n \n \n \n \n\n\n\n\n
\n
\n
\n
\n
\n
Authentication was successful.
\n
\n Got OAuth token and storing it in a cookie - {{{payload.token}}}.\n
\n Redirecting to menu options....\n
\n
\n \n
\n
\n
\n
\n\n
\n\n\n\n","output":"str","x":810,"y":800,"wires":[["29d98eb5.b1a752"]]},{"id":"ddcaec96.ca91c","type":"http in","z":"c6bbf06d.815c5","name":"","url":"style.css","method":"get","upload":false,"swaggerDoc":"","x":90,"y":640,"wires":[["faa0d820.1d6948"]]},{"id":"faa0d820.1d6948","type":"template","z":"c6bbf06d.815c5","name":"Styles","field":"payload","fieldType":"msg","format":"css","syntax":"plain","template":"/* Starter CSS for Flyout Menu */\n \nbody, html {\n height: 100%;\n}\n.bg {\n\n /* Full height */\n height: 100%;\n\n /* Center and scale the image nicely */\n background-position: center;\n background-repeat: no-repeat;\n background-size: cover;\n}\n\n.navbar-laravel\n{\n box-shadow: 0 2px 4px rgba(0,0,0,.8);\n}\n\n.navbar-brand , .nav-link, .my-form, .login-form\n{\n font-family: Raleway, sans-serif;\n}\n\n.my-form\n{\n padding-top: 1.5rem;\n padding-bottom: 1.5rem;\n}\n.special-card {\n opacity: .7;\n}\n\n.transp {\n box-shadow: 0 2px 4px rgba(0,0,0,.04);\n}\n\n.my-form .row\n{\n margin-left: 0;\n margin-right: 0;\n}\n\n.login-form\n{\n padding-top: 12rem;\n padding-bottom: 1.5rem;\n}\n\n.login-form .row\n{\n margin-left: 0;\n margin-right: 0;\n}\n\n#cssmenu {\n padding: 0;\n margin: 0;\n border: 0;\n}\n#cssmenu ul,\nli {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n#cssmenu ul {\n position: relative;\n z-index: 597;\n float: left;\n}\n#cssmenu ul li {\n float: left;\n min-height: 1px;\n line-height: 1em;\n vertical-align: middle;\n}\n#cssmenu ul li.hover,\n#cssmenu ul li:hover {\n position: relative;\n z-index: 599;\n cursor: default;\n}\n#cssmenu ul ul {\n visibility: hidden;\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 598;\n width: 100%;\n}\n#cssmenu ul ul li {\n float: none;\n}\n#cssmenu ul li:hover > ul {\n visibility: visible;\n}\n#cssmenu ul ul {\n top: 0;\n left: 100%;\n}\n#cssmenu ul li {\n float: none;\n}\n/* Custom Stuff */\n#cssmenu span,\n#cssmenu a {\n display: inline-block;\n font-family: Arial, Helvetica, sans-serif;\n font-size: 12px;\n text-decoration: none;\n}\n#cssmenu {\n -moz-border-radius: 5px;\n -webkit-border-radius: 5px;\n border-radius: 5px;\n -moz-background-clip: padding;\n -webkit-background-clip: padding-box;\n background-clip: padding-box;\n -moz-box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.15);\n -webkit-box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.15);\n box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.15);\n font-weight: 600;\n width: 200px;\n}\n#cssmenu:after,\n#cssmenu ul:after {\n content: '';\n display: block;\n clear: both;\n}\n#cssmenu > ul > li:first-child {\n -moz-border-radius: 5px 5px 0 0;\n -webkit-border-radius: 5px 5px 0 0;\n border-radius: 5px 5px 0 0;\n -moz-background-clip: padding;\n -webkit-background-clip: padding-box;\n background-clip: padding-box;\n}\n#cssmenu > ul > li:last-child {\n -moz-border-radius: 0 0 5px 5px;\n -webkit-border-radius: 0 0 5px 5px;\n border-radius: 0 0 5px 5px;\n -moz-background-clip: padding;\n -webkit-background-clip: padding-box;\n background-clip: padding-box;\n}\n#cssmenu > ul > li ul ul li:first-child {\n -moz-border-radius: 0 5px 0 0;\n -webkit-border-radius: 0 5px 0 0;\n border-radius: 0 5px 0 0;\n -moz-background-clip: padding;\n -webkit-background-clip: padding-box;\n background-clip: padding-box;\n}\n#cssmenu > ul > li ul ul li:last-child {\n -moz-border-radius: 0 0 5px 0;\n -webkit-border-radius: 0 0 5px 0;\n border-radius: 0 0 5px 0;\n -moz-background-clip: padding;\n -webkit-background-clip: padding-box;\n background-clip: padding-box;\n}\n#cssmenu ul,\n#cssmenu li {\n width: 100%;\n}\n#cssmenu li {\n background: #c0bebf url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA0CAMAAAB8fKKlAAAAmVBMVEXy7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7erx7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7ery7eoO3g4TAAAAMnRSTlP8+fbz7+vn497Z1M/KxL+5s66oopuVj4mDfHZwamRdV1FMRkA7NTArJiEcGBQQDAkGA02z+X0AAABLSURBVHheDcGDEQMBAACwvFnbtrv/cO3F949AKBJLpDK5QqlSa2hqaevo6ukbGBoZm5iamVtYWlnb2NrZOzg6Obu4url7eHp5+/wAxikFLnlTZcYAAAAASUVORK5CYII=) repeat-x;\n background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #f2edea), color-stop(1, #c0bebf));\n background-image: -webkit-linear-gradient(top, #f2edea, #c0bebf);\n background-image: -moz-linear-gradient(top, #f2edea, #c0bebf);\n background-image: -ms-linear-gradient(top, #f2edea, #c0bebf);\n background-image: -o-linear-gradient(top, #f2edea, #c0bebf);\n background-image: linear-gradient(#f2edea, #c0bebf);\n}\n#cssmenu li:hover,\n#cssmenu li.active {\n background: #606a76 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA0CAMAAAB8fKKlAAAAmVBMVEVKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmJKVmL///9KVmL3Z0MtAAAAMnRSTlP8+fby7+vm4t3Y087Iw723sauln5mTjIaAeXNsZmBaVE5IQjw3MSwnIh0ZFBANCQYDAAm6nKYAAABLSURBVHheDcGDEQMBAACwvFnbtrv/cO3F949AKBJLpDK5QqlSa2hqaevo6ukbGBoZm5iamVtYWlnb2NrZOzg6Obu4url7eHp5+/wAxikFLnlTZcYAAAAASUVORK5CYII=) repeat-x;\n -moz-box-shadow: inset 0 -2px 3px rgba(0, 0, 0, 0.15);\n -webkit-box-shadow: inset 0 -2px 3px rgba(0, 0, 0, 0.15);\n box-shadow: inset 0 -2px 3px rgba(0, 0, 0, 0.15);\n background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #4a5662), color-stop(1, #606a76));\n background-image: -webkit-linear-gradient(top, #4a5662, #606a76);\n background-image: -moz-linear-gradient(top, #4a5662, #606a76);\n background-image: -ms-linear-gradient(top, #4a5662, #606a76);\n background-image: -o-linear-gradient(top, #4a5662, #606a76);\n background-image: linear-gradient(#4a5662, #606a76);\n}\n#cssmenu li:hover > a,\n#cssmenu li.active > a {\n color: #FFF;\n}\n#cssmenu a {\n color: #666666;\n line-height: 160%;\n padding: 16px 8px 16px 28px;\n width: 164px;\n}\n#cssmenu ul ul {\n -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);\n width: 200px;\n}\n#cssmenu ul ul li {\n background: #606a76;\n border-bottom: 1px solid #59636F;\n -moz-box-shadow: inset 0 1px 0 #66707c;\n -webkit-box-shadow: inset 0 1px 0 #66707c;\n box-shadow: inset 0 1px 0 #66707c;\n}\n#cssmenu ul ul li:hover {\n background: #4a5662;\n}\n#cssmenu ul ul li a {\n color: #FFF;\n}\n#cssmenu ul ul a,\n#cssmenu ul ul a span {\n font-size: 12px;\n}\n\nbody{\n margin: 0;\n font-size: .9rem;\n font-weight: 400;\n line-height: 1.6;\n color: #212529;\n text-align: left;\n background-color: #f5f8fa;\n}","output":"str","x":310,"y":640,"wires":[["dbc3aa15.f5da28"]]},{"id":"c7535f45.f3ad88","type":"http response","z":"c6bbf06d.815c5","name":"","statusCode":"","headers":{},"x":770,"y":640,"wires":[]},{"id":"dbc3aa15.f5da28","type":"function","z":"c6bbf06d.815c5","name":"","func":"msg.headers = {};\nmsg.headers[\"Content-Type\"]=\"text/css\";\nmsg.headers[\"Accept\"]=\"text/css\";\nreturn msg;","outputs":1,"noerr":0,"x":550,"y":640,"wires":[["c7535f45.f3ad88"]]},{"id":"38a14d84.ad506a","type":"http in","z":"c6bbf06d.815c5","name":"","url":"/authorize","method":"post","upload":false,"swaggerDoc":"","x":100,"y":180,"wires":[["8c345d04.a34438"]]},{"id":"60983a42.5d8f84","type":"function","z":"c6bbf06d.815c5","name":"","func":"var jsonstr = msg.payload;\nmsg.payload={};\nnode.error(jsonstr);\nmsg.payload = JSON.parse(jsonstr);\n\nvar globalContext = global;\nmsg.payload.username = globalContext.get(\"username\");\nmsg.payload.password = globalContext.get(\"password\");\nmsg.payload.oauth_authorize_url = globalContext.get(\"oauth_authorize_url\");\nmsg.payload.client_id = globalContext.get(\"client_id\");\n\nmsg.url = msg.payload.oauth_authorize_url;\n\nmsg.headers={}\nmsg.headers['Content-Type']= 'application/x-www-form-urlencoded';\nreturn msg;","outputs":1,"noerr":0,"x":630,"y":180,"wires":[["e47566bc.2f9018"]]},{"id":"620da1b2.3e6858","type":"http response","z":"c6bbf06d.815c5","name":"","statusCode":"","headers":{},"x":1050,"y":180,"wires":[]},{"id":"e47566bc.2f9018","type":"http request","z":"c6bbf06d.815c5","name":"","method":"POST","ret":"txt","paytoqs":false,"url":"","tls":"","proxy":"","authType":"basic","x":830,"y":180,"wires":[["620da1b2.3e6858"]]},{"id":"95cd613f.395328","type":"function","z":"c6bbf06d.815c5","name":"GetGlobal","func":"msg.payload={}\nvar globalContext = global;\nmsg.payload.node_red_url = globalContext.get(\"node_red_url\");\nreturn msg;","outputs":1,"noerr":0,"x":340,"y":60,"wires":[["af023898.f95ea8"]]},{"id":"efaffa7.fb17188","type":"http in","z":"c6bbf06d.815c5","name":"Configure OAUTH urls","url":"/configureui","method":"get","upload":false,"swaggerDoc":"","x":120,"y":960,"wires":[["d6c6970b.c6a7a8"]]},{"id":"d6c6970b.c6a7a8","type":"template","z":"c6bbf06d.815c5","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n\n\n\n\nCode Bank | Configuration\n\n\n\n\n\n\n\n\n\t\n\t\t
\n\t\t\tConfigure OAuth URLs \n\t\t\t\n\n\t\t\t
\n\t\t\t\t
    \n\t\t\t\t\t
  • Login
  • \n\t\t\t\t
\n\n\t\t\t
\n\t\t
\n\t\n\n\t
\n\t
\n\t\t
\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t
OAuth2 Configuration
\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t
\n\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t
\n\t\t
\n\t
\n\t
\n\n\n\n\n","output":"str","x":420,"y":960,"wires":[["9508e6d5.2ff9e"]]},{"id":"9508e6d5.2ff9e","type":"http response","z":"c6bbf06d.815c5","name":"","statusCode":"","headers":{},"x":710,"y":960,"wires":[]},{"id":"462146fb.1d2898","type":"http in","z":"c6bbf06d.815c5","name":"Apply Configuration","url":"/configure","method":"post","upload":false,"swaggerDoc":"","x":110,"y":1040,"wires":[["3e3385cc.9e7a1a","3f2eb0ce.eee89"]]},{"id":"3e3385cc.9e7a1a","type":"function","z":"c6bbf06d.815c5","name":"SetGlobal","func":"var node_red_url = msg.payload.node_red_base_url;\nvar oauth_authorize_url = msg.payload.authorize_url;\nvar oauth_token_url = msg.payload.token_url;\nvar redirect_url = msg.payload.redirect_url;\nvar client_id = msg.payload.client_id;\nvar transfer_url = msg.payload.transfer_url;\n\nvar globalContext = global;\nglobalContext.set(\"node_red_url\",node_red_url);\nglobalContext.set(\"oauth_authorize_url\",oauth_authorize_url);\nglobalContext.set(\"oauth_token_url\", oauth_token_url);\nglobalContext.set(\"redirect_url\", redirect_url);\nglobalContext.set(\"client_id\", client_id);\nglobalContext.set(\"transfer_url\", transfer_url);\nreturn msg;","outputs":1,"noerr":0,"x":380,"y":1040,"wires":[["761fbbd2.ef9bc4"]]},{"id":"761fbbd2.ef9bc4","type":"template","z":"c6bbf06d.815c5","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n \n Applied configuration successfully. Please wait...\n \n \n","output":"str","x":580,"y":1040,"wires":[["5d642d21.50debc"]]},{"id":"5d642d21.50debc","type":"http response","z":"c6bbf06d.815c5","name":"","statusCode":"200","headers":{},"x":800,"y":1040,"wires":[]},{"id":"3f2eb0ce.eee89","type":"debug","z":"c6bbf06d.815c5","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":400,"y":1120,"wires":[]},{"id":"5387f225.ba6ba4","type":"template","z":"c6bbf06d.815c5","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"response_type\":\"code\",\"client_id\":\"{{{payload.client_id}}}\",\"scope\":\"funds_transfer\",\"redirect_uri\":\"{{{payload.redirect_url}}}\",\"original-url\":\"{{{payload.oauth_authorize_url}}}?response_type=code&client_id={{{payload.client_id}}}&redirect_uri={{{payload.redirect_url}}}&scope=funds_transfer\",\"apim-source\":\"html-login\"}","output":"str","x":420,"y":180,"wires":[["60983a42.5d8f84"]]},{"id":"8c345d04.a34438","type":"function","z":"c6bbf06d.815c5","name":"GetGlobal","func":"var globalContext = global;\nglobalContext.set(\"username\",msg.payload.username);\nglobalContext.set(\"password\",msg.payload.password);\nmsg.payload.oauth_authorize_url = globalContext.get(\"oauth_authorize_url\");\nmsg.payload.redirect_url = globalContext.get(\"redirect_url\");\nmsg.payload.client_id = globalContext.get(\"client_id\");\nreturn msg;","outputs":1,"noerr":0,"x":260,"y":180,"wires":[["5387f225.ba6ba4"]]},{"id":"28e37ecb.8f730a","type":"function","z":"c6bbf06d.815c5","name":"GetGlobal","func":"var globalContext = global;\nglobalContext.set(\"username\",msg.payload.username);\nglobalContext.set(\"password\",msg.payload.password);\nmsg.payload.node_red_url = globalContext.get(\"node_red_url\");\nmsg.payload.oauth_authorize_url = globalContext.get(\"oauth_authorize_url\");\nmsg.payload.oauth_token_url = globalContext.get(\"oauth_token_url\");\nmsg.payload.redirect_url = globalContext.get(\"redirect_url\");\nmsg.payload.client_id = globalContext.get(\"client_id\");\nnode.error(globalContext);\nnode.error(globalContext.get(\"oauth_token_url\"));\nreturn msg;","outputs":1,"noerr":0,"x":280,"y":500,"wires":[["294bce94.2a278a"]]},{"id":"20fe935b.0e9cec","type":"function","z":"c6bbf06d.815c5","name":"GetGlobal","func":"var globalContext = global;\nglobalContext.set(\"username\",msg.payload.username);\nglobalContext.set(\"password\",msg.payload.password);\nmsg.payload.node_red_url = globalContext.get(\"node_red_url\");\nmsg.payload.oauth_authorize_url = globalContext.get(\"oauth_authorize_url\");\nmsg.payload.oauth_token_url = globalContext.get(\"oauth_token_url\");\nmsg.payload.redirect_url = globalContext.get(\"redirect_url\");\nmsg.payload.client_id = globalContext.get(\"client_id\");\nnode.error(globalContext);\nnode.error(globalContext.get(\"oauth_token_url\"));\nreturn msg;","outputs":1,"noerr":0,"x":280,"y":400,"wires":[["4b50b12b.6aa34"]]},{"id":"8df7bd0e.4dbc38","type":"comment","z":"c6bbf06d.815c5","name":"The below flow renders login page","info":"","x":160,"y":20,"wires":[]},{"id":"99463aee.698fd8","type":"comment","z":"c6bbf06d.815c5","name":"The below flow invokes authorize endpoint on API Connect","info":"","x":230,"y":140,"wires":[]},{"id":"8251b340.ebc5f","type":"comment","z":"c6bbf06d.815c5","name":"The below flow renders the menu page","info":"","x":170,"y":240,"wires":[]},{"id":"e14930b8.f5b6c","type":"comment","z":"c6bbf06d.815c5","name":"The below flow invokes the funds transfer endpoint on API Connect","info":"","x":260,"y":360,"wires":[]},{"id":"fb3fd524.30924","type":"comment","z":"c6bbf06d.815c5","name":"The below flow renders the Funds Transfer UI page","info":"","x":211,"y":458,"wires":[]},{"id":"74d5a565.96711c","type":"comment","z":"c6bbf06d.815c5","name":"The below flow returns the CSS style sheet","info":"","x":180,"y":580,"wires":[]},{"id":"1873845c.9c1544","type":"comment","z":"c6bbf06d.815c5","name":"The below endpoint is the Redirect URI for OAuth","info":"","x":200,"y":740,"wires":[]},{"id":"1ef79db3.c01faa","type":"comment","z":"c6bbf06d.815c5","name":"The below flow renders application configuration page","info":"","x":220,"y":920,"wires":[]},{"id":"f73f166b.d51a58","type":"comment","z":"c6bbf06d.815c5","name":"The below flow stores the application configuration on global context","info":"","x":270,"y":1000,"wires":[]}] -------------------------------------------------------------------------------- /images/access-to-cluster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/access-to-cluster.png -------------------------------------------------------------------------------- /images/add-api-to-catalog.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/add-api-to-catalog.gif -------------------------------------------------------------------------------- /images/api-connect-instance-create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/api-connect-instance-create.png -------------------------------------------------------------------------------- /images/api-defn-export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/api-defn-export.png -------------------------------------------------------------------------------- /images/app-connect-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/app-connect-flow.png -------------------------------------------------------------------------------- /images/app-connect-instance-create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/app-connect-instance-create.png -------------------------------------------------------------------------------- /images/app_subscribe_plan.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/app_subscribe_plan.gif -------------------------------------------------------------------------------- /images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/architecture.png -------------------------------------------------------------------------------- /images/cluster-status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/cluster-status.png -------------------------------------------------------------------------------- /images/configure_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/configure_app.png -------------------------------------------------------------------------------- /images/create_app.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/create_app.gif -------------------------------------------------------------------------------- /images/create_funds_transfer_endpoint.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/create_funds_transfer_endpoint.gif -------------------------------------------------------------------------------- /images/create_oauth_endpoint.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/create_oauth_endpoint.gif -------------------------------------------------------------------------------- /images/create_product_publish.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/create_product_publish.gif -------------------------------------------------------------------------------- /images/create_service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/create_service.png -------------------------------------------------------------------------------- /images/debit_account_service_msg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/debit_account_service_msg.png -------------------------------------------------------------------------------- /images/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/demo.gif -------------------------------------------------------------------------------- /images/deploy_client_app.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/deploy_client_app.gif -------------------------------------------------------------------------------- /images/flow-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/flow-start.png -------------------------------------------------------------------------------- /images/flow-test.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/flow-test.gif -------------------------------------------------------------------------------- /images/import-flow-check.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/import-flow-check.gif -------------------------------------------------------------------------------- /images/import-flow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/import-flow.gif -------------------------------------------------------------------------------- /images/node-red-instance-create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/node-red-instance-create.png -------------------------------------------------------------------------------- /images/note_api_connect_endpoint.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/note_api_connect_endpoint.gif -------------------------------------------------------------------------------- /images/note_fund_transfer_url.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/note_fund_transfer_url.gif -------------------------------------------------------------------------------- /images/note_node_red_url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/note_node_red_url.png -------------------------------------------------------------------------------- /images/postman_accmgmtservice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/postman_accmgmtservice.png -------------------------------------------------------------------------------- /images/postman_creditaccservice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/postman_creditaccservice.png -------------------------------------------------------------------------------- /images/postman_debitaccservice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/postman_debitaccservice.png -------------------------------------------------------------------------------- /images/postman_loginservice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/postman_loginservice.png -------------------------------------------------------------------------------- /images/worker-nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/microservices-using-apiconnect-and-appconnect/f1882c1e186d51fbf7c7198c3a0bddfe859f00d5/images/worker-nodes.png -------------------------------------------------------------------------------- /microservices/account_management_service/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM node:alpine 3 | 4 | MAINTAINER Shikha "shikha.mah@in.ibm.com" 5 | 6 | RUN apk update && apk upgrade 7 | # Install the application 8 | COPY package.json /app/package.json 9 | RUN cd /app && npm install 10 | COPY app.js /app/app.js 11 | ENV WEB_PORT 8080 12 | EXPOSE 8080 13 | 14 | # Define command to run the application when the container starts 15 | CMD ["node", "/app/app.js"] 16 | -------------------------------------------------------------------------------- /microservices/account_management_service/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var bodyParser = require('body-parser'); 3 | var MongoClient = require('mongodb').MongoClient; 4 | 5 | var app = express(); 6 | app.use(bodyParser.json()); 7 | 8 | // Connect to the db 9 | var connection_url = "CONNECTION_URL"; 10 | var url = "mongodb://"+ connection_url + "/test"; 11 | MongoClient.connect(url, {useNewUrlParser: true, useUnifiedTopology: true} , function(err, mongoclient) { 12 | if(err) { 13 | console.log("Mongo DB connection failed"); 14 | return console.dir(err); 15 | } 16 | console.log("Mongo DB connection successful"); 17 | var database = mongoclient.db("test"); 18 | 19 | database.createCollection('accountdetails', function(err1, collection) { 20 | var docs = [ 21 | {_id: "121", accountholder: "John", funds: 25000}, 22 | {_id: "122", accountholder: "Tim", funds: 15000}, 23 | {_id: "123", accountholder: "Joseph", funds: 250000}, 24 | {_id: "124", accountholder: "Mary", funds: 200000} 25 | ]; 26 | collection.insertMany(docs, {w:1}, function(err2, result) { 27 | if (!err2) { 28 | console.log("Docs inserted in Collection 'accountdetails'."); 29 | } 30 | 31 | collection.find().toArray(function(err, items) { 32 | console.log("Collection(accountdetails) items : ", items); 33 | }); 34 | }); 35 | }); 36 | 37 | database.createCollection('transactionlog', function(err3, collection) { 38 | var docs = [ 39 | {_id:0, source_account:"000", debited_amount:0, target_account:"000", credited_amount:0, transfer_type:"test", remarks:"test", debit_transaction_code:0, credit_transaction_code:0} 40 | ]; 41 | collection.insertMany(docs, {w:1}, function(err4, result) { 42 | if (!err4) { 43 | console.log("Docs inserted in Collection 'transactionlog'."); 44 | } 45 | 46 | collection.find().toArray(function(err4, items) { 47 | console.log("Collection(transactionlog) items : ", items); 48 | }); 49 | }); 50 | }); 51 | }); 52 | 53 | 54 | app.post('/check_accounts', function (req, res) { 55 | console.log("in Check Accounts -"); 56 | var body = req.body; 57 | console.log(JSON.stringify(body)); 58 | 59 | var minimum_balance = 1000; 60 | var source_account = body['source_accountID']; 61 | var amount_to_transfer = body['amount_to_transfer']; 62 | var target_account = body['target_accountID']; 63 | 64 | MongoClient.connect(url, {useNewUrlParser: true} , function(err, mongoclient) { 65 | if(err) { 66 | console.log("Mongo DB connection failed"); 67 | return console.dir(err); 68 | } 69 | console.log("Mongo DB connection successful"); 70 | var database = mongoclient.db("test"); 71 | 72 | var collection = database.collection('accountdetails'); 73 | // check whether target account exists 74 | collection.find({_id:target_account}).toArray(function(err1, account1){ 75 | if (err1){ 76 | console.log("Internal DB Server Error"); 77 | var resp = {responseCode: 1, message: "Internal DB Server Error"}; 78 | console.log(JSON.stringify(resp)); 79 | mongoclient.close(); 80 | res.send(resp); 81 | } else if (account1.length == 0 ){ 82 | console.log("Target account does not exist"); 83 | var resp = {responseCode: 1, message: "Target account does not exist"}; 84 | console.log(JSON.stringify(resp)); 85 | mongoclient.close(); 86 | res.send(resp); 87 | } else { 88 | console.log("Target account exists - ", account1); 89 | 90 | //if target account exists then check source account exists with sufficient balance 91 | collection.find({_id:source_account}).toArray(function(err2, account2){ 92 | if (err2){ 93 | console.log("Internal DB Server Error"); 94 | console.log(err2); 95 | var resp = {responseCode: 1, message: "Internal DB Server Error"}; 96 | console.log(JSON.stringify(resp)); 97 | mongoclient.close(); 98 | res.send(resp); 99 | } else if (account2.length == 0 ){ 100 | console.log("Source account does not exist"); 101 | var resp = {responseCode: 1, message: "Source account does not exist"}; 102 | console.log(JSON.stringify(resp)); 103 | mongoclient.close(); 104 | res.send(resp); 105 | } else { 106 | console.log("Source account exists - ", account2); 107 | 108 | var account_balance = account2[0].funds - minimum_balance; 109 | if ( account_balance >= amount_to_transfer ){ 110 | console.log("Sufficient funds to transfer"); 111 | var resp = {responseCode: 0, message: "Sufficient funds to transfer"}; 112 | console.log(JSON.stringify(resp)); 113 | mongoclient.close(); 114 | res.send(resp); 115 | } else { 116 | console.log("Insufficient funds to transfer"); 117 | var resp = {responseCode: 1, message: "Insufficient funds to transfer"}; 118 | console.log(JSON.stringify(resp)); 119 | mongoclient.close(); 120 | res.send(resp); 121 | } 122 | } 123 | }); 124 | } 125 | }); 126 | }); 127 | }); 128 | 129 | app.get('/', function (req, res) { 130 | res.end( "Rest API implementation for Microservice ACCOUNT MANAGEMENT" ); 131 | }); 132 | 133 | var port = 8080; 134 | 135 | var server = app.listen(port, function () { 136 | console.log("Account Management service listening on " + port); 137 | }); 138 | -------------------------------------------------------------------------------- /microservices/account_management_service/deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: account-details-app 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: account-details-app 10 | template: 11 | metadata: 12 | labels: 13 | app: account-details-app 14 | spec: 15 | containers: 16 | - name: account-details-app 17 | image: IMAGE 18 | ports: 19 | - containerPort: 8080 20 | --- 21 | apiVersion: v1 22 | kind: Service 23 | metadata: 24 | name: account-details-service 25 | labels: 26 | app: account-details-service 27 | spec: 28 | type: NodePort 29 | ports: 30 | - port: 8080 31 | nodePort: 32424 32 | selector: 33 | app: account-details-app 34 | -------------------------------------------------------------------------------- /microservices/account_management_service/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "account_management", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "Account Management Application", 6 | "author": "Shikha Maheshwari ", 7 | "dependencies": { 8 | "body-parser": "*", 9 | "express": "^4.16.4", 10 | "mongo": "*" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /microservices/credit_service/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM node:alpine 3 | 4 | MAINTAINER Shikha "shikha.mah@in.ibm.com" 5 | 6 | RUN apk update && apk upgrade 7 | # Install the application 8 | COPY package.json /app/package.json 9 | RUN cd /app && npm install 10 | COPY app.js /app/app.js 11 | ENV WEB_PORT 8080 12 | EXPOSE 8080 13 | 14 | # Define command to run the application when the container starts 15 | CMD ["node", "/app/app.js"] 16 | -------------------------------------------------------------------------------- /microservices/credit_service/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var app = express(); 3 | var bodyParser = require('body-parser'); 4 | var MongoClient = require('mongodb').MongoClient; 5 | var ObjectID = require('mongodb').ObjectID; 6 | 7 | app.use(bodyParser.json()); 8 | 9 | // Connect to db 10 | var connection_url = "CONNECTION_URL"; 11 | var url = "mongodb://"+ connection_url + "/test"; 12 | MongoClient.connect(url, {useNewUrlParser: true, useUnifiedTopology: true} , function(err, mongoclient) { 13 | if(err) { 14 | console.log("Mongo DB connection failed"); 15 | return console.dir(err); 16 | } 17 | console.log("Mongo DB connection successful"); 18 | var database = mongoclient.db("test"); 19 | 20 | var collection = database.collection('accountdetails'); 21 | collection.find().toArray(function(err, items) { 22 | console.log("Collection items : ", items); 23 | mongoclient.close(); 24 | }); 25 | }); 26 | 27 | app.post('/credit_account', function (req, res) { 28 | 29 | var body = req.body; 30 | console.log(JSON.stringify(body)); 31 | 32 | var target_account = body['target_accountID']; 33 | var amount_to_transfer = body['amount_to_transfer']; 34 | var transactionID = body['transactionID']; 35 | 36 | MongoClient.connect(url, {useNewUrlParser: true} , function(err, mongoclient) { 37 | if(err) { 38 | console.log("Mongo DB connection failed"); 39 | return console.dir(err); 40 | } 41 | console.log("Mongo DB connection successful"); 42 | var database = mongoclient.db("test"); 43 | 44 | var collection = database.collection('accountdetails'); 45 | collection.find().toArray(function(err0, items) { 46 | console.log("Collection items(accountdetails) : ", items); 47 | }); 48 | collection.findOne({_id:target_account}, function(err1, account1){ 49 | //console.log("in find query ", err1, "account " ,account1); 50 | if(err1){ 51 | console.log("Credit transaction failed - Internal DB Server Error"); 52 | console.log(err1); 53 | var resp = {transactionID:0, responseCode: 1, message: "Credit transaction failed - Internal DB server error"}; 54 | console.log(JSON.stringify(resp)); 55 | mongoclient.close(); 56 | res.send(resp); 57 | } else if (account1) { 58 | //Temporary code to test -ve scenario 59 | console.log("Account ID is : ", account1._id); 60 | if (account1._id == "125"){ 61 | console.log("testing negative scenario "); 62 | var resp = {transactionID: -2, responseCode: 1, message: "Credit transaction failed"}; 63 | console.log(JSON.stringify(resp)); 64 | //mongoclient.close(); 65 | res.send(resp); 66 | } else { 67 | //Temporry code ends 68 | //console.log("acc length ", account1); 69 | var account_balance = account1.funds + amount_to_transfer; 70 | try { 71 | collection.updateOne({_id:target_account}, { $set: {"funds":account_balance}}, function(err2, response){ 72 | if (response.modifiedCount == 1) { 73 | console.log("Credit transaction successful"); 74 | collection.findOne({_id:target_account}, function(err3, updatedDoc){ 75 | console.log("Updated Document: ", updatedDoc); 76 | }); 77 | try { 78 | var collection1 = database.collection('transactionlog'); 79 | if (transactionID) { 80 | collection1.updateOne({_id:ObjectID(transactionID)}, 81 | { $set: { target_account:target_account, credited_amount:amount_to_transfer, credit_transaction_code:0}}, 82 | function(err4, response1){ 83 | //console.log(response1); 84 | if(response1.modifiedCount == 1){ 85 | console.log("transaction log updated, transaction ID - ", transactionID); 86 | var resp = {transactionID: transactionID, responseCode: 0, message: "Funds transfer successful"}; 87 | console.log(JSON.stringify(resp)); 88 | mongoclient.close(); 89 | res.send(resp); 90 | } 91 | }); 92 | } else { 93 | collection1.insertOne( 94 | { source_account:0, debited_amount:0, transfer_type:"NA", remarks:"Credit transaction successful (Amount reversed)", debit_transaction_code:-1, target_account:target_account, credited_amount:amount_to_transfer, credit_transaction_code:0 }, 95 | function(err4, doc){ 96 | transactionID = doc.insertedId; 97 | console.log("Credit transaction successful (Amount reversed). Inserted transaction in transaction log, transaction ID - ", transactionID); 98 | var resp = {transactionID: transactionID, responseCode: 0, message: "Credit transaction successful (Amount reversed)"}; 99 | console.log(JSON.stringify(resp)); 100 | mongoclient.close(); 101 | res.send(resp); 102 | }); 103 | } 104 | 105 | } catch (e) { 106 | console.log("In catch block of transaction log update - ", e); 107 | var resp = {transactionID: -1, responseCode: 0, message: "Credit transaction successful but failed to update the transaction log"}; 108 | console.log(JSON.stringify(resp)); 109 | mongoclient.close(); 110 | res.send(resp); 111 | } 112 | } 113 | }); 114 | } catch (e) { 115 | console.log("In catch block of account update - ", e); 116 | var resp = {transactionID:0, responseCode: 1, message: "Credit transaction failed - Internal DB server error"}; 117 | console.log(JSON.stringify(resp)); 118 | mongoclient.close(); 119 | res.send(resp); 120 | } 121 | } 122 | } else { 123 | console.log("in else ", account1); 124 | console.log("Credit transaction failed - Internal Server Error"); 125 | var resp = {transactionID:0, responseCode: 1, message: "Credit transaction failed - Internal server error"}; 126 | console.log(JSON.stringify(resp)); 127 | mongoclient.close(); 128 | res.send(resp); 129 | } 130 | }); 131 | }); 132 | }); 133 | 134 | app.get('/', function (req, res) { 135 | res.end( "Rest API implementation for Microservice CREDIT ACCOUNT" ); 136 | }); 137 | 138 | var port = 8080; 139 | 140 | var server = app.listen(port, function () { 141 | 142 | console.log("Credit Account service listening on " + port); 143 | 144 | }) 145 | -------------------------------------------------------------------------------- /microservices/credit_service/deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: credit-account-app 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: credit-account-app 10 | template: 11 | metadata: 12 | labels: 13 | app: credit-account-app 14 | spec: 15 | containers: 16 | - name: credit-account-app 17 | image: IMAGE 18 | ports: 19 | - containerPort: 8080 20 | --- 21 | apiVersion: v1 22 | kind: Service 23 | metadata: 24 | name: credit-account-service 25 | labels: 26 | app: credit-account-service 27 | spec: 28 | type: NodePort 29 | ports: 30 | - port: 8080 31 | nodePort: 32426 32 | selector: 33 | app: credit-account-app 34 | -------------------------------------------------------------------------------- /microservices/credit_service/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "credit_account", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "Credit account application", 6 | "author": "Shikha Maheshwari ", 7 | "dependencies": { 8 | "body-parser": "*", 9 | "express": "^4.16.4", 10 | "mongo": "*" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /microservices/debit_service/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM node:alpine 3 | 4 | MAINTAINER Shikha "shikha.mah@in.ibm.com" 5 | 6 | RUN apk update && apk upgrade 7 | # Install the application 8 | COPY package.json /app/package.json 9 | RUN cd /app && npm install 10 | COPY app.js /app/app.js 11 | ENV WEB_PORT 8080 12 | EXPOSE 8080 13 | 14 | # Define command to run the application when the container starts 15 | CMD ["node", "/app/app.js"] 16 | -------------------------------------------------------------------------------- /microservices/debit_service/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var app = express(); 3 | var bodyParser = require('body-parser'); 4 | var MongoClient = require('mongodb').MongoClient; 5 | 6 | app.use(bodyParser.json()); 7 | 8 | // Connect to the db 9 | var connection_url = "CONNECTION_URL"; 10 | var url = "mongodb://"+ connection_url + "/test"; 11 | MongoClient.connect(url, {useNewUrlParser: true, useUnifiedTopology: true} , function(err, mongoclient) { 12 | if(err) { 13 | console.log("Mongo DB connection failed"); 14 | return console.dir(err); 15 | } 16 | console.log("Mongo DB connection successful"); 17 | var database = mongoclient.db("test"); 18 | 19 | var collection = database.collection('accountdetails'); 20 | collection.find().toArray(function(err1, items) { 21 | console.log("Collection(accountdetails) items : ", items); 22 | mongoclient.close(); 23 | }); 24 | }); 25 | 26 | app.post('/debit_account', function (req, res) { 27 | 28 | var body = req.body; 29 | console.log(JSON.stringify(body)); 30 | 31 | var source_account = body['source_accountID']; 32 | var amount_to_transfer = body['amount_to_transfer']; 33 | var remarks = body['remarks']; 34 | var transfer_type = body['transfer_type']; 35 | var transactionID; 36 | 37 | MongoClient.connect(url, {useNewUrlParser: true} , function(err, mongoclient) { 38 | if(err) { 39 | console.log("Mongo DB connection failed"); 40 | return console.dir(err); 41 | } 42 | console.log("Mongo DB connection successful"); 43 | var database = mongoclient.db("test"); 44 | 45 | var collection = database.collection('accountdetails'); 46 | collection.find().toArray(function(err, items) { 47 | console.log("Collection(accountdetails) items : ", items); 48 | }); 49 | collection.find({_id:source_account}).toArray(function(err1, account1){ 50 | if(err1){ 51 | console.log("Debit transaction failed - Internal DB Server Error"); 52 | console.log(err1); 53 | var resp = {transactionID:0, responseCode: 1, message: "Debit transaction failed - Internal DB server error"}; 54 | console.log(JSON.stringify(resp)); 55 | mongoclient.close(); 56 | res.send(resp); 57 | } else if (account1.length > 0) { 58 | //console.log("acc length ", account1); 59 | var account_balance = account1[0].funds - amount_to_transfer; 60 | try { 61 | collection.updateOne({_id:source_account}, { $set: {"funds":account_balance}}, function(err2, response){ 62 | if (response.modifiedCount == 1) { 63 | console.log("Debit transaction successful"); 64 | collection.findOne({_id:source_account}, function(err3, updatedDoc){ 65 | console.log("Updated Document: ", updatedDoc); 66 | }); 67 | try { 68 | var collection1 = database.collection('transactionlog'); 69 | collection1.insertOne( 70 | { source_account:source_account, debited_amount:amount_to_transfer, transfer_type:transfer_type, remarks:remarks, debit_transaction_code:0}, 71 | function(err4, doc){ 72 | transactionID = doc.insertedId; 73 | console.log("Inserted transaction in transaction log, transaction ID - ", transactionID); 74 | var resp = {transactionID: transactionID, responseCode: 0, message: "Debit transaction successful"}; 75 | console.log(JSON.stringify(resp)); 76 | mongoclient.close(); 77 | res.send(resp); 78 | }); 79 | } catch (e) { 80 | console.log("In catch block - ", e); 81 | var resp = {transactionID: -1, responseCode: 0, message: "Debit transaction successful but failed to create an entry in transaction log"}; 82 | console.log(JSON.stringify(resp)); 83 | mongoclient.close(); 84 | res.send(resp); 85 | } 86 | } 87 | }); 88 | } catch (e) { 89 | console.log("In catch block - ", e); 90 | var resp = {transactionID:0, responseCode: 1, message: "Debit transaction failed - Internal DB server error"}; 91 | console.log(JSON.stringify(resp)); 92 | mongoclient.close(); 93 | res.send(resp); 94 | } 95 | } else { 96 | console.log("in else ", account1); 97 | console.log("Debit transaction failed - Internal Server Error"); 98 | var resp = {transactionID:0, responseCode: 1, message: "Debit transaction failed - Internal server error"}; 99 | console.log(JSON.stringify(resp)); 100 | mongoclient.close(); 101 | res.send(resp); 102 | } 103 | }); 104 | }); 105 | }); 106 | 107 | app.get('/', function (req, res) { 108 | res.end( "Rest API implementation for Microservice DEBIT ACCOUNT" ); 109 | }); 110 | 111 | var port = 8080; 112 | 113 | var server = app.listen(port, function () { 114 | 115 | console.log("Debit Account service listening on " + port); 116 | 117 | }) 118 | -------------------------------------------------------------------------------- /microservices/debit_service/deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: debit-account-app 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: debit-account-app 10 | template: 11 | metadata: 12 | labels: 13 | app: debit-account-app 14 | spec: 15 | containers: 16 | - name: debit-account-app 17 | image: IMAGE 18 | ports: 19 | - containerPort: 8080 20 | --- 21 | apiVersion: v1 22 | kind: Service 23 | metadata: 24 | name: debit-account-service 25 | labels: 26 | app: debit-account-service 27 | spec: 28 | type: NodePort 29 | ports: 30 | - port: 8080 31 | nodePort: 32425 32 | selector: 33 | app: debit-account-app 34 | -------------------------------------------------------------------------------- /microservices/debit_service/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "debit_account", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "Debit account application", 6 | "author": "Shikha Maheshwari ", 7 | "dependencies": { 8 | "body-parser": "*", 9 | "express": "^4.16.4", 10 | "mongo": "*" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /microservices/login_service/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM node:alpine 3 | 4 | MAINTAINER Shikha "shikha.mah@in.ibm.com" 5 | 6 | RUN apk update && apk upgrade 7 | # Install the application 8 | COPY package.json /app/package.json 9 | RUN cd /app && npm install 10 | COPY app.js /app/app.js 11 | ENV WEB_PORT 8080 12 | EXPOSE 8080 13 | 14 | # Define command to run the application when the container starts 15 | CMD ["node", "/app/app.js"] 16 | -------------------------------------------------------------------------------- /microservices/login_service/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var bodyParser = require('body-parser'); 3 | 4 | // Retrieve 5 | var MongoClient = require('mongodb').MongoClient; 6 | 7 | var app = express(); 8 | app.use(bodyParser.json()); 9 | 10 | // Connect to the db 11 | var connection_url = "CONNECTION_URL"; 12 | var url = "mongodb://"+ connection_url + "/test"; 13 | MongoClient.connect(url, {useNewUrlParser: true, useUnifiedTopology: true} , function(err, mongoclient) { 14 | if(err) { 15 | console.log("Mongo DB connection failed"); 16 | return console.dir(err); 17 | } 18 | console.log("Mongo DB connection successful"); 19 | 20 | // Create and Initialize DB for Login - if not created already 21 | var database = mongoclient.db("test"); 22 | database.createCollection('login', function(err1, collection) { 23 | var docs = [ 24 | {_id: "user1", password: "user1"}, 25 | {_id: "user2", password: "user2"}, 26 | {_id: "user3", password: "user3"} 27 | ]; 28 | var collection = database.collection('login'); 29 | collection.insertMany(docs, {w:1}, function(err2, result) { 30 | if (!err2) { 31 | console.log("Docs inserted in Collection 'Login'."); 32 | } 33 | 34 | collection.find().toArray(function(err, items) { 35 | console.log("Records in Login DB : ", items); 36 | mongoclient.close(); 37 | }); 38 | }); 39 | }); 40 | }); 41 | 42 | app.get('/login', function (req, res) { 43 | 44 | console.log("in GET - login"); 45 | 46 | // check for basic auth header 47 | if (!req.headers.authorization || req.headers.authorization.indexOf('Basic ') === -1) { 48 | return res.status(401).json({ message: 'Missing Authorization Header' }); 49 | } 50 | 51 | // verify auth credentials 52 | var base64Credentials = req.headers.authorization.split(' ')[1]; 53 | var credentials = Buffer.from(base64Credentials, 'base64').toString('ascii'); 54 | var [username, password] = credentials.split(':'); 55 | console.log("username : ", username); 56 | console.log("password : ", password); 57 | 58 | MongoClient.connect(url, {useNewUrlParser: true} , function(err, mongoclient) { 59 | if(err) { 60 | console.log("Mongo DB connection failed"); 61 | return console.dir(err); 62 | } 63 | console.log("Mongo DB connection successful"); 64 | var database = mongoclient.db("test"); 65 | 66 | var collection = database.collection('login'); 67 | 68 | collection.find({_id:username}).toArray(function(err, items) { 69 | console.log("in GET - User details : ", items); 70 | 71 | if (err) { 72 | console.log("User not Found"); 73 | res.send(err); 74 | } else { 75 | var credentials = items[0]; 76 | if (credentials.password == password){ 77 | var resp = {responseCode: 0, message: "Credentials Matched"}; 78 | console.log(JSON.stringify(resp)); 79 | mongoclient.close(); 80 | res.status(200).send(resp); 81 | } else { 82 | var resp = {responseCode: 1, message: "Incorrect Credentials"}; 83 | console.log(JSON.stringify(resp)); 84 | mongoclient.close(); 85 | res.status(401).send(resp); 86 | } 87 | } 88 | }); 89 | }); 90 | }); 91 | 92 | app.get('/', function (req, res) { 93 | res.end( "Rest API implementation for LOGIN SERVICE" ); 94 | }); 95 | 96 | var port = 8080; 97 | 98 | var server = app.listen(port, function () { 99 | console.log("Login service listening on " + port); 100 | }); 101 | -------------------------------------------------------------------------------- /microservices/login_service/deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: login-app 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: login-app 10 | template: 11 | metadata: 12 | labels: 13 | app: login-app 14 | spec: 15 | containers: 16 | - name: login-app 17 | image: IMAGE 18 | ports: 19 | - containerPort: 8080 20 | --- 21 | apiVersion: v1 22 | kind: Service 23 | metadata: 24 | name: login-service 25 | labels: 26 | app: login-service 27 | spec: 28 | type: NodePort 29 | ports: 30 | - port: 8080 31 | nodePort: 32423 32 | selector: 33 | app: login-app 34 | -------------------------------------------------------------------------------- /microservices/login_service/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "login", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "Login application", 6 | "author": "Shikha Maheshwari ", 7 | "dependencies": { 8 | "body-parser": "*", 9 | "express": "^4.16.4", 10 | "mongodb": "*" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /mongodb/deploy_mongodb.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: mongo 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: mongo 11 | template: 12 | metadata: 13 | labels: 14 | app: mongo 15 | version: v1 16 | spec: 17 | containers: 18 | - image: mongo 19 | name: mongo 20 | ports: 21 | - containerPort: 27017 22 | name: mongocontainer 23 | --- 24 | apiVersion: v1 25 | kind: Service 26 | metadata: 27 | name: mongo 28 | spec: 29 | type: NodePort 30 | ports: 31 | - port: 27017 32 | targetPort: 27017 33 | selector: 34 | app: mongo 35 | --------------------------------------------------------------------------------