GET endpoint with Integration Tests
							parent
							
								
									74debb4b4c
								
							
						
					
					
						commit
						d0fd928ef7
					
				
							
								
								
									
										4
									
								
								.obsidian/app.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
								
								
									
									
								
								
								
							
						
						
									
										4
									
								
								.obsidian/app.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "alwaysUpdateLinks": true,
 | 
				
			||||||
 | 
					  "attachmentFolderPath": "assets"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								.obsidian/appearance.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
								
								
									
									
								
								
								
							
						
						
									
										3
									
								
								.obsidian/appearance.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "accentColor": ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										29
									
								
								.obsidian/core-plugins-migration.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
								
								
									
									
								
								
								
							
						
						
									
										29
									
								
								.obsidian/core-plugins-migration.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "file-explorer": true,
 | 
				
			||||||
 | 
					  "global-search": true,
 | 
				
			||||||
 | 
					  "switcher": true,
 | 
				
			||||||
 | 
					  "graph": true,
 | 
				
			||||||
 | 
					  "backlink": true,
 | 
				
			||||||
 | 
					  "canvas": true,
 | 
				
			||||||
 | 
					  "outgoing-link": true,
 | 
				
			||||||
 | 
					  "tag-pane": true,
 | 
				
			||||||
 | 
					  "page-preview": true,
 | 
				
			||||||
 | 
					  "daily-notes": true,
 | 
				
			||||||
 | 
					  "templates": true,
 | 
				
			||||||
 | 
					  "note-composer": true,
 | 
				
			||||||
 | 
					  "command-palette": true,
 | 
				
			||||||
 | 
					  "slash-command": false,
 | 
				
			||||||
 | 
					  "editor-status": true,
 | 
				
			||||||
 | 
					  "bookmarks": true,
 | 
				
			||||||
 | 
					  "markdown-importer": false,
 | 
				
			||||||
 | 
					  "zk-prefixer": false,
 | 
				
			||||||
 | 
					  "random-note": false,
 | 
				
			||||||
 | 
					  "outline": true,
 | 
				
			||||||
 | 
					  "word-count": true,
 | 
				
			||||||
 | 
					  "slides": false,
 | 
				
			||||||
 | 
					  "audio-recorder": false,
 | 
				
			||||||
 | 
					  "workspaces": false,
 | 
				
			||||||
 | 
					  "file-recovery": true,
 | 
				
			||||||
 | 
					  "publish": false,
 | 
				
			||||||
 | 
					  "sync": false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										20
									
								
								.obsidian/core-plugins.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
								
								
									
									
								
								
								
							
						
						
									
										20
									
								
								.obsidian/core-plugins.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					[
 | 
				
			||||||
 | 
					  "file-explorer",
 | 
				
			||||||
 | 
					  "global-search",
 | 
				
			||||||
 | 
					  "switcher",
 | 
				
			||||||
 | 
					  "graph",
 | 
				
			||||||
 | 
					  "backlink",
 | 
				
			||||||
 | 
					  "canvas",
 | 
				
			||||||
 | 
					  "outgoing-link",
 | 
				
			||||||
 | 
					  "tag-pane",
 | 
				
			||||||
 | 
					  "page-preview",
 | 
				
			||||||
 | 
					  "daily-notes",
 | 
				
			||||||
 | 
					  "templates",
 | 
				
			||||||
 | 
					  "note-composer",
 | 
				
			||||||
 | 
					  "command-palette",
 | 
				
			||||||
 | 
					  "editor-status",
 | 
				
			||||||
 | 
					  "bookmarks",
 | 
				
			||||||
 | 
					  "outline",
 | 
				
			||||||
 | 
					  "word-count",
 | 
				
			||||||
 | 
					  "file-recovery"
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
							
								
								
									
										1
									
								
								.obsidian/hotkeys.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
								
								
									
									
								
								
								
							
						
						
									
										1
									
								
								.obsidian/hotkeys.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					{}
 | 
				
			||||||
							
								
								
									
										192
									
								
								.obsidian/workspace.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
								
								
									
									
								
								
								
							
						
						
									
										192
									
								
								.obsidian/workspace.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,192 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "main": {
 | 
				
			||||||
 | 
					    "id": "bfa6b0eb76264f17",
 | 
				
			||||||
 | 
					    "type": "split",
 | 
				
			||||||
 | 
					    "children": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "id": "91a95d9b9ba4dc49",
 | 
				
			||||||
 | 
					        "type": "tabs",
 | 
				
			||||||
 | 
					        "children": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "id": "a3660fdf5f5aceb3",
 | 
				
			||||||
 | 
					            "type": "leaf",
 | 
				
			||||||
 | 
					            "state": {
 | 
				
			||||||
 | 
					              "type": "markdown",
 | 
				
			||||||
 | 
					              "state": {
 | 
				
			||||||
 | 
					                "file": "Home.md",
 | 
				
			||||||
 | 
					                "mode": "source",
 | 
				
			||||||
 | 
					                "source": false
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "id": "7e5ec70badaa86f3",
 | 
				
			||||||
 | 
					            "type": "leaf",
 | 
				
			||||||
 | 
					            "state": {
 | 
				
			||||||
 | 
					              "type": "markdown",
 | 
				
			||||||
 | 
					              "state": {
 | 
				
			||||||
 | 
					                "file": "IntegrationTests.md",
 | 
				
			||||||
 | 
					                "mode": "source",
 | 
				
			||||||
 | 
					                "source": false
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "id": "ec5879550528c04c",
 | 
				
			||||||
 | 
					            "type": "leaf",
 | 
				
			||||||
 | 
					            "state": {
 | 
				
			||||||
 | 
					              "type": "markdown",
 | 
				
			||||||
 | 
					              "state": {
 | 
				
			||||||
 | 
					                "file": "GET.md",
 | 
				
			||||||
 | 
					                "mode": "source",
 | 
				
			||||||
 | 
					                "source": false
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "currentTab": 2
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "direction": "vertical"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "left": {
 | 
				
			||||||
 | 
					    "id": "5eaa206d99edb028",
 | 
				
			||||||
 | 
					    "type": "split",
 | 
				
			||||||
 | 
					    "children": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "id": "d007c720b5e598a0",
 | 
				
			||||||
 | 
					        "type": "tabs",
 | 
				
			||||||
 | 
					        "children": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "id": "03171174265e0ee5",
 | 
				
			||||||
 | 
					            "type": "leaf",
 | 
				
			||||||
 | 
					            "state": {
 | 
				
			||||||
 | 
					              "type": "file-explorer",
 | 
				
			||||||
 | 
					              "state": {
 | 
				
			||||||
 | 
					                "sortOrder": "alphabetical"
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "id": "f78dd3c57a1694ca",
 | 
				
			||||||
 | 
					            "type": "leaf",
 | 
				
			||||||
 | 
					            "state": {
 | 
				
			||||||
 | 
					              "type": "search",
 | 
				
			||||||
 | 
					              "state": {
 | 
				
			||||||
 | 
					                "query": "",
 | 
				
			||||||
 | 
					                "matchingCase": false,
 | 
				
			||||||
 | 
					                "explainSearch": false,
 | 
				
			||||||
 | 
					                "collapseAll": false,
 | 
				
			||||||
 | 
					                "extraContext": false,
 | 
				
			||||||
 | 
					                "sortOrder": "alphabetical"
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "id": "ef97ee1190cc8880",
 | 
				
			||||||
 | 
					            "type": "leaf",
 | 
				
			||||||
 | 
					            "state": {
 | 
				
			||||||
 | 
					              "type": "bookmarks",
 | 
				
			||||||
 | 
					              "state": {}
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "direction": "horizontal",
 | 
				
			||||||
 | 
					    "width": 249.5
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "right": {
 | 
				
			||||||
 | 
					    "id": "3bd78c465d2a2030",
 | 
				
			||||||
 | 
					    "type": "split",
 | 
				
			||||||
 | 
					    "children": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "id": "e39fc11f28834b41",
 | 
				
			||||||
 | 
					        "type": "tabs",
 | 
				
			||||||
 | 
					        "children": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "id": "e0d70c2f91ae0cfb",
 | 
				
			||||||
 | 
					            "type": "leaf",
 | 
				
			||||||
 | 
					            "state": {
 | 
				
			||||||
 | 
					              "type": "backlink",
 | 
				
			||||||
 | 
					              "state": {
 | 
				
			||||||
 | 
					                "file": "GET.md",
 | 
				
			||||||
 | 
					                "collapseAll": false,
 | 
				
			||||||
 | 
					                "extraContext": false,
 | 
				
			||||||
 | 
					                "sortOrder": "alphabetical",
 | 
				
			||||||
 | 
					                "showSearch": false,
 | 
				
			||||||
 | 
					                "searchQuery": "",
 | 
				
			||||||
 | 
					                "backlinkCollapsed": false,
 | 
				
			||||||
 | 
					                "unlinkedCollapsed": true
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "id": "11cce84d7b97ddc8",
 | 
				
			||||||
 | 
					            "type": "leaf",
 | 
				
			||||||
 | 
					            "state": {
 | 
				
			||||||
 | 
					              "type": "outgoing-link",
 | 
				
			||||||
 | 
					              "state": {
 | 
				
			||||||
 | 
					                "file": "GET.md",
 | 
				
			||||||
 | 
					                "linksCollapsed": false,
 | 
				
			||||||
 | 
					                "unlinkedCollapsed": true
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "id": "f8f2ce3f2694f545",
 | 
				
			||||||
 | 
					            "type": "leaf",
 | 
				
			||||||
 | 
					            "state": {
 | 
				
			||||||
 | 
					              "type": "tag",
 | 
				
			||||||
 | 
					              "state": {
 | 
				
			||||||
 | 
					                "sortOrder": "frequency",
 | 
				
			||||||
 | 
					                "useHierarchy": true
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "id": "58d34025bb119389",
 | 
				
			||||||
 | 
					            "type": "leaf",
 | 
				
			||||||
 | 
					            "state": {
 | 
				
			||||||
 | 
					              "type": "outline",
 | 
				
			||||||
 | 
					              "state": {
 | 
				
			||||||
 | 
					                "file": "GET.md"
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "currentTab": 3
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "direction": "horizontal",
 | 
				
			||||||
 | 
					    "width": 300
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "left-ribbon": {
 | 
				
			||||||
 | 
					    "hiddenItems": {
 | 
				
			||||||
 | 
					      "switcher:Open quick switcher": false,
 | 
				
			||||||
 | 
					      "graph:Open graph view": false,
 | 
				
			||||||
 | 
					      "canvas:Create new canvas": false,
 | 
				
			||||||
 | 
					      "daily-notes:Open today's daily note": false,
 | 
				
			||||||
 | 
					      "templates:Insert template": false,
 | 
				
			||||||
 | 
					      "command-palette:Open command palette": false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "active": "ec5879550528c04c",
 | 
				
			||||||
 | 
					  "lastOpenFiles": [
 | 
				
			||||||
 | 
					    "IntegrationTests.md",
 | 
				
			||||||
 | 
					    "Home.md",
 | 
				
			||||||
 | 
					    "GET.md",
 | 
				
			||||||
 | 
					    "UnitTests.md",
 | 
				
			||||||
 | 
					    "Pasted image 20230719102301.png",
 | 
				
			||||||
 | 
					    "assets/Pasted image 20230719102322.png",
 | 
				
			||||||
 | 
					    "assets",
 | 
				
			||||||
 | 
					    "Pasted image 20230718185450.png",
 | 
				
			||||||
 | 
					    "testPage.md",
 | 
				
			||||||
 | 
					    "subfolder/Note1.md",
 | 
				
			||||||
 | 
					    "_Sidebar.md",
 | 
				
			||||||
 | 
					    "tests%252FSubpage.md.-.md",
 | 
				
			||||||
 | 
					    "subfolder.md",
 | 
				
			||||||
 | 
					    "subfolder%5C%2Fp2.md",
 | 
				
			||||||
 | 
					    "subfolder"
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										52
									
								
								GET.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
									
									
								
								
								
							
						
						
									
										52
									
								
								GET.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					`src/main/java/djmil/cashcard/CashCardController.java`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```java
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package example.cashcard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.springframework.http.ResponseEntity;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.GetMapping;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.PathVariable;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.RequestMapping;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.RestController;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@RestController
 | 
				
			||||||
 | 
					public class CashCardController {
 | 
				
			||||||
 | 
						@GetMapping("/cashcards/{requestedId}")
 | 
				
			||||||
 | 
						public ResponseEntity<CashCard> findById(@PathVariable Long requestedId) {
 | 
				
			||||||
 | 
							if (requestedId.equals(99L)) {
 | 
				
			||||||
 | 
							    CashCard cashCard = new CashCard(99L, 123.45);
 | 
				
			||||||
 | 
						        return ResponseEntity.ok(cashCard);
 | 
				
			||||||
 | 
						    } else {
 | 
				
			||||||
 | 
						        return ResponseEntity.notFound().build();
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# @GetMapping 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Needs the URI Path and tells Spring to route `GET` requests strictly to the `findById` method. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Alternative variant for providing URI mapping for `@RestConttroller`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```java
 | 
				
			||||||
 | 
					@RestController
 | 
				
			||||||
 | 
					@RequestMapping("/cashcards")
 | 
				
			||||||
 | 
					public class CashCardController {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @GetMapping("/{requestedId}")
 | 
				
			||||||
 | 
					   public ResponseEntity<String> findById() {
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# @PathVariable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Spring needs to know how to get the value of the `requestedId` parameter. This is done using the `@PathVariable` annotation. The fact that the parameter name matches the `{requestedId}` text *(URI Path)* within the `@GetMapping` parameter allows Spring to assign (inject) the correct value to the `requestedId` variable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ResponseEntity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					REST says that the Response needs to contain a Cash Card in its body, and a Response code of 200 (OK). Spring Web provides the `ResponseEntity` class for this purpose. It also provides several utility methods to produce Response Entities. Here `ResponseEntity` used to create a Response with code **200 (OK)**, and a body containing a `CashCard`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Testing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing `GET` and other REST request is considerate to be [[IntegrationTests]]. 
 | 
				
			||||||
							
								
								
									
										56
									
								
								Home.md
									
									
									
									
									
								
							
							
								
								
								
								
									
									
								
								
								
							
						
						
									
										56
									
								
								Home.md
									
									
									
									
									
								
							@ -27,10 +27,10 @@ Different tests can be written at different levels of the system. At each level,
 | 
				
			|||||||

 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Unit Tests
 | 
					## Unit Tests
 | 
				
			||||||
A [[UnitTests]] exercises a small “unit” of the system that is isolated from the rest of the system. They should be simple and speedy. You want a high ratio of Unit Tests in your testing pyramid as they’re key to designing highly cohesive, loosely coupled software.
 | 
					[[UnitTests]] exercises a small “unit” of the system that is isolated from the rest of the system. They should be simple and speedy. You want a high ratio of Unit Tests in your testing pyramid as they’re key to designing highly cohesive, loosely coupled software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Integration Tests
 | 
					## Integration Tests
 | 
				
			||||||
Integration Tests exercise a subset of the system and may exercise groups of units in one test. They are more complicated to write and maintain, and run slower than unit tests.
 | 
					[[IntegrationTests]] exercise a subset of the system and may exercise groups of units in one test. They are more complicated to write and maintain, and run slower than unit tests.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## End-to-End Tests
 | 
					## End-to-End Tests
 | 
				
			||||||
An End-to-End Test exercises the system using the same interface that a user would, such as a web browser. While extremely thorough, End-to-End Tests can be very slow and fragile because they use simulated user interactions in potentially complicated UIs. Implement the smallest number of these tests.
 | 
					An End-to-End Test exercises the system using the same interface that a user would, such as a web browser. While extremely thorough, End-to-End Tests can be very slow and fragile because they use simulated user interactions in potentially complicated UIs. Implement the smallest number of these tests.
 | 
				
			||||||
@ -44,7 +44,59 @@ Software development teams love to move fast. So how do you go fast forever? By
 | 
				
			|||||||
3. **Refactor:** Look for opportunities to simplify, reduce duplication, or otherwise improve the code without changing any behavior—to _refactor._
 | 
					3. **Refactor:** Look for opportunities to simplify, reduce duplication, or otherwise improve the code without changing any behavior—to _refactor._
 | 
				
			||||||
4. Repeat!
 | 
					4. Repeat!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# RESTful API
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In a RESTful system, data objects are called Resource Representations. The purpose of a RESTful API is to manage the state of these Resources. The chart below shows details about RESTful CRUD operations of an application.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					|Operation|API Endpoint|HTTP Method|Response Status|
 | 
				
			||||||
 | 
					|---|---|---|---|
 | 
				
			||||||
 | 
					|**C**reate|`/cashcards`|`POST`|201 (CREATED)|
 | 
				
			||||||
 | 
					|**R**ead|`/cashcards/{id}`|`GET`|200 (OK)|
 | 
				
			||||||
 | 
					|**U**pdate|`/cashcards/{id}`|`PUT`|204 (NO DATA)|
 | 
				
			||||||
 | 
					|**D**elete|`/cashcards/{id}`|`DELETE`|204 (NO DATA)|
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Another common concept associated with REST is the Hypertext Transfer Protocol. In **HTTP**, a caller sends a Request to a URI. A web server receives the request, and routes it to a request handler. The handler creates a Response, which is then sent back to the caller.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## REST in Spring Boot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					One of the main things Spring does is to configure and instantiate objects. These objects are called *Spring Beans*, and are usually created by Spring (as opposed to using the Java `new` keyword). You can direct Spring to create Beans in several ways.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> We will annotate a class with a Spring Annotation, which directs Spring to create an instance of the class during Spring’s *Component Scan* phase. This happens at application startup. The Bean is stored in Spring’s `IoC Container`. From here, the bean can be injected into any code that requests it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					![[Pasted image 20230719102322.png]]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## @RestController
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In Spring Web, Requests are handled by Controllers. We are going to use the more specific `RestController` annotation.  The actual class shall be placed in `src/main/java/djmil/cashcard/CashCardController.java`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```java
 | 
				
			||||||
 | 
					@RestController
 | 
				
			||||||
 | 
					public class CashCardController {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					That’s all it takes to tell Spring: “create a REST Controller”. The Controller gets injected into Spring Web, which routes API requests (handled by the Controller) with help of [[GET#@GetMapping]] annotation to the correct method.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Get
 | 
				
			||||||
 | 
					****
 | 
				
			||||||
 | 
					In [[GET]] requests, the body is empty. So, the request to read the Cash Card with an id of 123 would be:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					Request:
 | 
				
			||||||
 | 
					  Method: GET
 | 
				
			||||||
 | 
					  URL: http://cashcard.example.com/cashcards/123
 | 
				
			||||||
 | 
					  Body: (empty)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The response to a successful Read request has a body containing the JSON representation of the Resource which was requested, with a Response Status Code of 200 (OK). So the response to the above Read request would look like this:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					Response:
 | 
				
			||||||
 | 
					  Status Code: 200
 | 
				
			||||||
 | 
					  Body:
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "id": 123,
 | 
				
			||||||
 | 
					    "amount": 25.00
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										96
									
								
								IntegrationTests.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
									
									
								
								
								
							
						
						
									
										96
									
								
								IntegrationTests.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					It is expected that at this point you've worked thru [[Home#RESTful API]] section of a tutorial.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Update `src/test/java/djmil/cashcard/CashCardApplicationTests.java
 | 
				
			||||||
 | 
					with this Integration Test:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```java
 | 
				
			||||||
 | 
					package djmil.cashcard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.jayway.jsonpath.DocumentContext;
 | 
				
			||||||
 | 
					import com.jayway.jsonpath.JsonPath;
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.Test;
 | 
				
			||||||
 | 
					import org.springframework.beans.factory.annotation.Autowired;
 | 
				
			||||||
 | 
					import org.springframework.boot.test.context.SpringBootTest;
 | 
				
			||||||
 | 
					import org.springframework.boot.test.web.client.TestRestTemplate;
 | 
				
			||||||
 | 
					import org.springframework.http.HttpStatus;
 | 
				
			||||||
 | 
					import org.springframework.http.ResponseEntity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static org.assertj.core.api.Assertions.assertThat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 | 
				
			||||||
 | 
					class CashCardApplicationTests {
 | 
				
			||||||
 | 
					    @Autowired
 | 
				
			||||||
 | 
					    TestRestTemplate restTemplate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    void shouldReturnACashCardWhenDataIsSaved() {
 | 
				
			||||||
 | 
					        ResponseEntity<String> response = restTemplate.getForEntity("/cashcards/99", String.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        DocumentContext documentContext = JsonPath.parse(response.getBody());
 | 
				
			||||||
 | 
							Number id = documentContext.read("$.id");
 | 
				
			||||||
 | 
							assertThat(id).isNotNull();
 | 
				
			||||||
 | 
							assertThat(id).isEqualTo(99);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Mock an SpringBoot application
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```java
 | 
				
			||||||
 | 
					@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 | 
				
			||||||
 | 
					class CashCardApplicationTests {
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A `@SpringBootTest` annotation is a way to start our Spring Boot application and make it available for our tests to perform requests to it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# A way to perform HTTP requests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## HTTP helper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```java
 | 
				
			||||||
 | 
					class CashCardApplicationTests {
 | 
				
			||||||
 | 
					    @Autowired
 | 
				
			||||||
 | 
					    TestRestTemplate restTemplate;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[TestRestTemplate](https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/web/client/TestRestTemplate.html) can be used to make HTTP requests to the locally running *(web)* application.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**_Note_** that while [[UnitTests#@Autowired]] annotation is a convenient form of [Spring dependency injection](https://docs.spring.io/spring-framework/reference/core/beans/dependencies/factory-collaborators.html) ==it’s best used only in tests==. We'll discuss this in more detail later.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Perform actual `Get` request
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```java
 | 
				
			||||||
 | 
					@Test
 | 
				
			||||||
 | 
					void shouldReturnACashCardWhenDataIsSaved() {
 | 
				
			||||||
 | 
					    ResponseEntity<String> response = restTemplate.getForEntity("/cashcards/99", String.class);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Here we use `restTemplate` to make an HTTP `GET` request to the application endpoint `/cashcards/99`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`restTemplate` will return a [[GET#ResponseEntity]], which we've captured in a variable we've named `response`. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Additional validators
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Now, we can (and shall) validate various aspects of expected response message.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### HTTP Response Status code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```java
 | 
				
			||||||
 | 
					assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Response Body
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```java
 | 
				
			||||||
 | 
					DocumentContext documentContext = JsonPath.parse(response.getBody());
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Converts the response String into a JSON-aware object with lots of helper methods.
 | 
				
			||||||
 | 
					```java
 | 
				
			||||||
 | 
					Number id = documentContext.read("$.id");
 | 
				
			||||||
 | 
					assertThat(id).isNotNull();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We expect that when we request a Cash Card with `id` of `99` a JSON object will be returned with _something_ in the `id` field. For now assert that the `id` is not `null`.
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								assets/Pasted image 20230719102322.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
								
							
						
						
									
										
											BIN
										
									
								
								assets/Pasted image 20230719102322.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 141 KiB  | 
		Loading…
	
		Reference in New Issue
	
	Block a user