From fd911cbc98602a36de3f950606daad12c829184a Mon Sep 17 00:00:00 2001 From: djmil Date: Fri, 21 Jul 2023 12:39:40 +0200 Subject: [PATCH] POST --- .obsidian/workspace.json | 33 ++- GET.md | 53 ---- Home.md | 363 +++++++++++++++---------- IntegrationTests.md | 2 +- Post.md | 123 +++++++++ assets/Pasted image 20230721100304.png | Bin 0 -> 49106 bytes 6 files changed, 369 insertions(+), 205 deletions(-) delete mode 100644 GET.md create mode 100644 Post.md create mode 100644 assets/Pasted image 20230721100304.png diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index 5d859d4..08280bb 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -25,7 +25,19 @@ "state": { "type": "markdown", "state": { - "file": "Database.md", + "file": "Home.md", + "mode": "source", + "source": false + } + } + }, + { + "id": "92c92033d31ed01c", + "type": "leaf", + "state": { + "type": "markdown", + "state": { + "file": "Home.md", "mode": "source", "source": false } @@ -44,7 +56,7 @@ } } ], - "currentTab": 1 + "currentTab": 2 } ], "direction": "vertical" @@ -110,7 +122,7 @@ "state": { "type": "backlink", "state": { - "file": "Database.md", + "file": "Home.md", "collapseAll": false, "extraContext": false, "sortOrder": "alphabetical", @@ -127,7 +139,7 @@ "state": { "type": "outgoing-link", "state": { - "file": "Database.md", + "file": "Home.md", "linksCollapsed": false, "unlinkedCollapsed": true } @@ -150,7 +162,7 @@ "state": { "type": "outline", "state": { - "file": "Database.md" + "file": "Home.md" } } } @@ -171,14 +183,17 @@ "command-palette:Open command palette": false } }, - "active": "7e5ec70badaa86f3", + "active": "92c92033d31ed01c", "lastOpenFiles": [ + "Post.md", + "GET.md", + "Home.md", + "Get.md", + "assets/Pasted image 20230721100304.png", + "Database.md", "IntegrationTests.md", "UnitTests.md", - "Database.md", - "Home.md", "assets/Pasted image 20230719152007.png", - "GET.md", "Pasted image 20230719102301.png", "assets/Pasted image 20230719102322.png", "assets", diff --git a/GET.md b/GET.md deleted file mode 100644 index 8497cdf..0000000 --- a/GET.md +++ /dev/null @@ -1,53 +0,0 @@ -`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 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 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]]. - -Also, after running the application, you can use browser (or any other web-testing tool) by visiting http://localhost:8080/cashcards/99 \ No newline at end of file diff --git a/Home.md b/Home.md index 1c93dfc..7e2a8a4 100644 --- a/Home.md +++ b/Home.md @@ -1,142 +1,221 @@ -This repo is my first attempt to learn `SpringBoot` following [this](https://spring.academy/courses/building-a-rest-api-with-spring-boot/lessons/introduction) tutorial. The setup is Visual Code IDE alongside with [SpringBoot](https://code.visualstudio.com/docs/java/java-spring-boot) plugin. It is also advised to read this wiki via [Obsidian](https://obsidian.md/) - -# Spring Initializr - -In VsCode press `cmd+shif+p` and type `Spring Initilizr`. Choose: -- Gradle Project -- _SpringBoot version:_ latest (3.1.1) -- _project language:_ Java -- _group id:_ djmil -- _artifact id (aka project name):_ cashcard -- _packaging type:_ jar -- _java version:_ 17 -- _dependencies:_ - - SpringWeb - -Essentially, this will generate a default minimalistic jet functional SpringBoot project. Entry point, aka `main()` can be found in [src/main/java/djmil/cashcard/CashcardApplication.java](http://192.168.8.55:3000/HQLAx/FamilyCashCard/src/branch/main/src/main/java/djmil/cashcard/CashcardApplication.java). To run the application - press `ctrl+F5` or Play button in the top right corner of an editor. - -# TDD - -Software development teams love to move fast. So how do you go fast forever? By continuously improving and simplifying your code – this is called **refactoring**. Refactoring is the act of altering the implementation of a software system without altering its inputs, outputs, or behavior. One of the only ways you can safely refactor is when you have a trustworthy test suite. Which brings us to the **TDD Cycle**: - -1. **Red:** Write a failing test for the desired functionality. -2. **Green:** Implement the simplest thing that can work to make the test pass. -3. **Refactor:** Look for opportunities to simplify, reduce duplication, or otherwise improve the code without changing any behavior - to _refactor._ -4. Repeat! - -Different tests can be written at different levels of the system. At each level, there is a balance between the speed of execution, the “cost” to maintain the test, and the confidence it brings to system correctness. This hierarchy is often represented as a “testing pyramid”. - -![Testing pyramid](https://blog.missiondata.com/wp-content/uploads/MD_TestingPyramid2x-1560x1045.png "Testing pyramid") - -## Unit Tests - -[[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 - -[[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 - -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. - -# 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 `@RestController` 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 - } -``` - -# Database - -The [**Separation of Concerns**](https://en.wikipedia.org/wiki/Separation_of_concerns) principle states that well-designed software should be modular, with each module having distinct and separate concerns from any other module. - -Up until now, our codebase only returns a hard-coded response from the Controller. This setup violates the Separation of Concerns principle by mixing the concerns of a Controller, which is an abstraction of a web interface, with the concerns of reading and writing data to a data store, such as a database. In order to solve this, we’ll use a common software architecture pattern to enforce data management separation via the **[Repository](https://www.baeldung.com/java-dao-vs-repository)** pattern. - -A common architectural framework that divides these layers, typically by function or value, such as business, data, and presentation layers, is called **Layered Architecture**. Here we can think of our Repository and Controller as two layers in a Layered Architecture. The Controller is in a layer near the Client (as it receives and responds to web requests) while the Repository is in a layer near the data store (as it reads from and writes to the data store). There may be intermediate layers as well, as dictated by business needs. - -![[Pasted image 20230719152007.png]] - -The Repository is the interface between the application and the database, and provides a **common abstraction** for any database, making it easier to switch to a different database when needed. - -[Spring Data](https://spring.io/projects/spring-data) works with Spring Boot to make database integration simple. - -## Choosing a Database - -For our [[Database]] selection, we’ll use an **embedded, in-memory** database. “Embedded” simply means that it’s a Java library, so it can be added to the project just like any other dependency. “In-memory” means that it stores data in memory only, as opposed to persisting data permanent, durable storage. - -The specific in-memory database we’ll use is [H2](https://www.h2database.com/html/main.html). Fortunately, H2 is highly compatible with other relational databases, so dev-prod parity *(application might behave differently when running the in-memory database than when running in production)* won’t be a big issue. We’ll use H2 for **convenience for local development**, but want to recognize the tradeoffs. - -## Auto Configuration - -Simply by adding [[Database#Spring Data and a database dependencies]] we are getting full database functionality. This wonderfully showcases one of the most powerful features of Spring Boot: **Auto Configuration**. Without Spring Boot, we’d have to configure Spring Data to speak to H2. However, because we’ve included the Spring Data dependency (and a specific data provider, H2), Spring Boot will automatically configure your application to communicate with H2. - -## Spring Data’s CrudRepository - -For our Repository selection, we’ll use a specific type of Repository: Spring Data’s `CrudRepository`. At first glance, it’s slightly magical, but let’s unpack that magic. - -The following is a complete implementation of all CRUD operations by extending `CrudRepository`: - -```java -public interface CashCardRepository extends CrudRepository { -} -``` - -With just the above code, a caller can call any number of predefined `CrudRepository` methods, such as `findById`: - -```java -cashCard = cashCardRepository.findById(99); -``` - -You might immediately wonder: where is the implementation of the `CashCardRepository.findById()` method? `CrudRepository` and everything it inherits from is an Interface with no actual code! Well, based on the specific Spring Data framework used, which for us will be Spring Data JDBC, Spring Data takes care of this implementation for us during the IoC container startup time. The Spring runtime will then expose the repository as yet another bean that you can reference wherever needed in your application. - -As we’ve learned, there are typically trade-offs. For example the `CrudRepository` generates SQL statements to read and write your data, which is useful for many cases, but sometimes you need to write your own custom SQL statements for specific use cases. But for now, we’re happy to take advantage of its convenient, out-of-the-box methods. \ No newline at end of file +This repo is my first attempt to learn `SpringBoot` following [this](https://spring.academy/courses/building-a-rest-api-with-spring-boot/lessons/introduction) tutorial. The setup is Visual Code IDE alongside with [SpringBoot](https://code.visualstudio.com/docs/java/java-spring-boot) plugin. + +# Spring Initializr + +In VsCode press `cmd+shif+p` and type `Spring Initilizr`. Choose: +- Gradle Project +- _SpringBoot version:_ latest (3.1.1) +- _project language:_ Java +- _group id:_ djmil +- _artifact id (aka project name):_ cashcard +- _packaging type:_ jar +- _java version:_ 17 +- _dependencies:_ + - SpringWeb + +Essentially, this will generate a default minimalistic jet functional SpringBoot project. Entry point, aka `main()` can be found in [src/main/java/djmil/cashcard/CashcardApplication.java](http://192.168.8.55:3000/HQLAx/FamilyCashCard/src/branch/main/src/main/java/djmil/cashcard/CashcardApplication.java). To run the application - press `ctrl+F5` or Play button in the top right corner of an editor. + +# TDD + +Software development teams love to move fast. So how do you go fast forever? By continuously improving and simplifying your code – this is called **refactoring**. Refactoring is the act of altering the implementation of a software system without altering its inputs, outputs, or behavior. One of the only ways you can safely refactor is when you have a trustworthy test suite. Which brings us to the **TDD Cycle**: + +1. **Red:** Write a failing test for the desired functionality. +2. **Green:** Implement the simplest thing that can work to make the test pass. +3. **Refactor:** Look for opportunities to simplify, reduce duplication, or otherwise improve the code without changing any behavior - to _refactor._ +4. Repeat! + +Different tests can be written at different levels of the system. At each level, there is a balance between the speed of execution, the “cost” to maintain the test, and the confidence it brings to system correctness. This hierarchy is often represented as a “testing pyramid”. + +![Testing pyramid](https://blog.missiondata.com/wp-content/uploads/MD_TestingPyramid2x-1560x1045.png "Testing pyramid") + +## Unit Tests + +[[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 + +[[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 + +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. + +# RESTful API + +REST is not exactly a standard; it’s merely a way to use HTTP to perform data operations. REST contains a number of guidelines, which developers shall follow to create coherent web-application. + +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 `@RestController` 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 + } +``` + +## Put + +Our REST API can now [[Get]] Cash Cards with a specific ID. Now it's time to add the Create endpoint to the API. Four questions we’ll need to answer while doing this are: + +1. Who specifies the ID - the client, or the server? + Here we’ll choose to let the server create the ID. Why? Because it’s the simplest solution, and databases are efficient at managing unique IDs. However, for completeness, let’s discuss our alternatives: + - We could require the client to provide the ID. This might make sense if there were a pre-existing unique ID, but that’s not the case. + - We could allow the client to provide the ID optionally (and create it on the server if the client does not supply it). However, we don’t have a requirement to do this, and it would complicate our application. If you think you might want to do this “just in case”, the [**Yagni**](https://martinfowler.com/bliki/Yagni.html) article might dissuade you. +2. In the API Request, how do we represent the object to be created? +3. Which HTTP method should we use in the Request? +4. What does the API send as a Response? + +### Idempotence and HTTP + +An **idempotent** operation is defined as one which, if performed more than once, results in the same outcome. In a REST API, an idempotent operation is one that even if it were to be performed several times, the resulting data on the server would be the same as if it had been performed only once. + +For each method, the HTTP standard specifies whether it is idempotent or not. `GET`, `PUT`, and `DELETE` are idempotent, whereas `POST` and `PATCH` are not. + +Since we’ve decided that the server will create IDs for every Create operation, the Create operation in our API **is NOT idempotent.** Since the server will create a new ID (on every Create request), if you call Create twice - even with the same content - you’ll end up with two different objects with the same content, but with different IDs. To summarize: every Create request will generate a new ID, thus no idempotency. + +![[Pasted image 20230721100304.png]] + +This leaves us with the `POST` and `PATCH` options. As it turns out, REST permits `POST` as one of the proper methods to use for Create operations, so we'll use it. We’ll revisit `PATCH` in a later lesson. + +### The [[Post]] Request + +The `POST` method allows a Body, so we will use the Body to send a JSON representation of the object: + +Request: + +- Method: `POST` +- URI: `/cashcards/` +- Body: + ```json + { + amount: 123.45 + } + ``` + +In contrast, if you recall from a previous lesson, the `GET` operation includes the ID of the Cash Card in the URI and but _not_ in the request Body. + +So why is there no ID in the Request? Because we decided to allow the server to create the ID. Thus, the data contract for the Read operation _is different_ from that of the Create operation. + +### The Response + +On successful creation, what HTTP Response Status Code should be sent? We could use `200 OK` (the response that Read returns), but there’s a more specific, more accurate code for REST APIs: `201 CREATED`. + +The fact that `CREATED` is the name of the code makes it seem intuitively appropriate, but there’s another, more technical reason to use it: A response code of `200 OK` does _not_ answer the question “Was there any change to the server data?”. By returning the `201 CREATED` status, the API is specifically communicating that data was added to the data store on the server. + +In addition to Status Code and a Body, HTTP Response also contains **Headers**. Headers have a name and a value. The HTTP standard specifies that the `Location` header in a `201 CREATED` response should contain the URI of the created resource. This is handy because it allows the caller to easily fetch the new resource using the GET endpoint (the one we implemented prior). + +Here is the complete Response: + +- Status Code: `201 CREATED` +- Header: `Location=/cashcards/42` + +### Spring Web Convenience Methods + +Spring Web provides methods which are geared towards the recommended use of HTTP and REST. For example, we’ll use the `ResponseEntity.created(uriOfCashCard)` method to create the above response. This method requires you to specify the location, ensures the Location URI is well-formed (by using the `URI` class), adds the `Location` header, and sets the Status Code for you. And by doing so, this saves us from using more verbose methods. For example, the following two code snippets are equivalent (as long as `uriOfCashCard` is not `null`): + +```java +return ResponseEntity + .created(uriOfCashCard) + .build(); +``` + +Versus: + +```java +return ResponseEntity + .status(HttpStatus.CREATED) + .header(HttpHeaders.LOCATION, uriOfCashCard.toASCIIString()) + .build(); +``` + +Aren’t you glad Spring Web provides the `.created()` convenience method? + +# Database + +The [**Separation of Concerns**](https://en.wikipedia.org/wiki/Separation_of_concerns) principle states that well-designed software should be modular, with each module having distinct and separate concerns from any other module. + +Up until now, our codebase only returns a hard-coded response from the Controller. This setup violates the Separation of Concerns principle by mixing the concerns of a Controller, which is an abstraction of a web interface, with the concerns of reading and writing data to a data store, such as a database. In order to solve this, we’ll use a common software architecture pattern to enforce data management separation via the **[Repository](https://www.baeldung.com/java-dao-vs-repository)** pattern. + +A common architectural framework that divides these layers, typically by function or value, such as business, data, and presentation layers, is called **Layered Architecture**. Here we can think of our Repository and Controller as two layers in a Layered Architecture. The Controller is in a layer near the Client (as it receives and responds to web requests) while the Repository is in a layer near the data store (as it reads from and writes to the data store). There may be intermediate layers as well, as dictated by business needs. + +![[Pasted image 20230719152007.png]] + +The Repository is the interface between the application and the database, and provides a **common abstraction** for any database, making it easier to switch to a different database when needed. + +[Spring Data](https://spring.io/projects/spring-data) works with Spring Boot to make database integration simple. + +## Choosing a Database + +For our database selection, we’ll use an **embedded, in-memory** database. “Embedded” simply means that it’s a Java library, so it can be added to the project just like any other dependency. “In-memory” means that it stores data in memory only, as opposed to persisting data permanent, durable storage. + +The specific in-memory database we’ll use is [H2](https://www.h2database.com/html/main.html). Fortunately, H2 is highly compatible with other relational databases, so dev-prod parity *(application might behave differently when running the in-memory database than when running in production)* won’t be a big issue. We’ll use H2 for **convenience for local development**, but want to recognize the tradeoffs. + +## Auto Configuration + +Simply by adding [[Database#Spring Data and a database dependencies]] we are getting full database functionality. This wonderfully showcases one of the most powerful features of Spring Boot: **Auto Configuration**. Without Spring Boot, we’d have to configure Spring Data to speak to H2. However, because we’ve included the Spring Data dependency (and a specific data provider, H2), Spring Boot will automatically configure your application to communicate with H2. + +## Spring Data’s CrudRepository + +For our Repository selection, we’ll use a specific type of Repository: Spring Data’s `CrudRepository`. At first glance, it’s slightly magical, but let’s unpack that magic. + +The following is a complete implementation of all CRUD operations by extending `CrudRepository`: + +```java +public interface CashCardRepository extends CrudRepository { +} +``` + +With just the above code, a caller can call any number of predefined `CrudRepository` methods, such as `findById`: + +```java +cashCard = cashCardRepository.findById(99); +``` + +You might immediately wonder: where is the implementation of the `CashCardRepository.findById()` method? `CrudRepository` and everything it inherits from is an Interface with no actual code! Well, based on the specific Spring Data framework used, which for us will be Spring Data JDBC, Spring Data takes care of this implementation for us during the IoC container startup time. The Spring runtime will then expose the repository as yet another bean that you can reference wherever needed in your application. + +As we’ve learned, there are typically trade-offs. For example the `CrudRepository` generates SQL statements to read and write your data, which is useful for many cases, but sometimes you need to write your own custom SQL statements for specific use cases. But for now, we’re happy to take advantage of its convenient, out-of-the-box methods. diff --git a/IntegrationTests.md b/IntegrationTests.md index 011a684..bafe66f 100644 --- a/IntegrationTests.md +++ b/IntegrationTests.md @@ -69,7 +69,7 @@ void shouldReturnACashCardWhenDataIsSaved() { 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`. +`restTemplate` will return a [[Get#ResponseEntity]], which we've captured in a variable we've named `response`. ## Additional validators diff --git a/Post.md b/Post.md new file mode 100644 index 0000000..ec6d3de --- /dev/null +++ b/Post.md @@ -0,0 +1,123 @@ +# Test the HTTP POST Endpoint + +We want our Cash Card API to behave as semantically correctly as possible. Meaning, users of our API should not be surprised by how it behaves. We'll begin by writing a failing test of what we expect success to look like. + +Let's refer to the official Request for Comments for HTTP Semantics and Content ([RFC 7231](https://www.rfc-editor.org/rfc/rfc7231)) for guidance as to how our API should behave. For our `POST` endpoint, review this section about [HTTP POST](https://www.rfc-editor.org/rfc/rfc7231#section-4.3.3); note that we have added emphasis: + +> If one or more resources has been created on the origin server as a result of successfully processing a POST request, **_the origin server SHOULD send a 201 (Created) response containing a Location header field that provides an identifier for the primary resource created ..._** + +Edit `src/test/java/example/cashcard/CashCardApplicationTests.java` and add the following test method. + +```java +import java.net.URI; +... + +@Test +void shouldCreateANewCashCard() { + // The database will create and manage all unique `CashCard.id` values for us. We should not provide one. + CashCard newCashCard = new CashCard(null, 250.00); + + // Post request MUST provide newCashCard data + // We expect nothing (Void) in the Post.Response.Body + ResponseEntity createResponse = restTemplate.postForEntity("/cashcards", newCashCard, Void.class ); + + assertThat(createResponse.getStatusCode()).isEqualTo(HttpStatus.CREATED); + + // Get Location Header of newly created respurce and use it for Get request + URI locationOfNewCashCard = createResponse.getHeaders().getLocation(); + ResponseEntity getResponse = restTemplate.getForEntity(locationOfNewCashCard, String.class); + assertThat(getResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + + // Validate Get response - a JSON for newly created CashCard entity + DocumentContext documentContext = JsonPath.parse(getResponse.getBody()); + Number id = documentContext.read("$.id"); + Double amount = documentContext.read("$.amount"); + + assertThat(id).isNotNull(); + assertThat(amount).isEqualTo(250.00); +} +``` + +## `Location` Header + +The official spec continue to state the following: + +> send a 201 (Created) response **_containing a Location header field_** that provides an identifier for the primary resource created ... + +In other words, when a `POST` request results in the successful creation of a resource, such as a new `CashCard`, the response should include information for how to retrieve that resource. We'll do this by supplying a URI in a [Response Header](https://www.rfc-editor.org/rfc/rfc7231#section-7) named "Location". + +```java +URI locationOfNewCashCard = createResponse.getHeaders().getLocation(); +``` + +Note that URI is indeed the correct entity here and _not_ a URL; a [URL is a type of URI](https://www.w3.org/TR/uri-clarification/#contemporary), while a URI is more generic. + +# The POST + +## Simple endpoint stub + +The `POST` endpoint is similar to the `GET` endpoint in our `CashCardController`, but uses the `@PostMapping` annotation from Spring Web. The `POST` endpoint must accept the data we are submitting for our new `CashCard`, specifically the `amount`. But what happens if we don't accept the `CashCard`? + +Edit `src/main/java/example/cashcard/CashCardController.java` and add the following method. + +```java +import org.springframework.web.bind.annotation.PostMapping; +... + +@PostMapping +private ResponseEntity createCashCard() { + return null; +} +``` + +Note that by returning nothing at all, Spring Web will automatically generate an HTTP Response Status code of `200 OK`. But, this isn't very satisfying -- our `POST` endpoint does nothing! So let's make our tests better. + +## Actual implementation + +```java +import org.springframework.web.util.UriComponentsBuilder; +... + +@PostMapping +private ResponseEntity createCashCard(@RequestBody CashCard newCashCardRequest, UriComponentsBuilder ucb) { + // CrudRepository.save - Create + CashCard savedCashCard = cashCardRepository.save(newCashCardRequest); + + URI locationOfNewCashCard = ucb + .path("cashcards/{id}") + .buildAndExpand(savedCashCard.id()) + .toUri(); + + return ResponseEntity.created(locationOfNewCashCard).build(); +} +``` + +### CrudRepository.save + +```java +CashCard savedCashCard = cashCardRepository.save(newCashCardRequest); +``` + +`CrudRepository` provides methods that support creating, reading, updating, and deleting data from a data store. `cashCardRepository.save(newCashCardRequest)` does just as it says: it saves a new `CashCard` for us, and returns the saved object with a unique `id` provided by the database. Amazing! + +### Post request, get the body + +```java +createCashCard(@RequestBody CashCard newCashCardRequest, ...) +``` + +Unlike the `GET` we added earlier, the `POST` expects a request "body". This contains the data submitted to the API. Spring Web will deserialize the data into a `CashCard` for us. + +### Location Header +```java +URI locationOfNewCashCard = ucb + .path("cashcards/{id}") + .buildAndExpand(savedCashCard.id()) + .toUri(); +``` + +This is constructing a URI to the newly created `CashCard`. This is the URI that the caller can then use to GET the newly-created `CashCard`. Note that `savedCashCard.id` is used as the identifier, which matches the `GET` endpoint's specification of `cashcards/`. + +> Where did `UriComponentsBuilder` come from? + +We were able to add `UriComponentsBuilder ucb` as a method argument to this `POST` handler method and it was automatically passed in. How so? It was injected from our now-familiar friend, Spring's IoC Container. Thanks, Spring Web! \ No newline at end of file diff --git a/assets/Pasted image 20230721100304.png b/assets/Pasted image 20230721100304.png new file mode 100644 index 0000000000000000000000000000000000000000..5c0b2f75de6d5413679136c1d0b3113a1a77fcb9 GIT binary patch literal 49106 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

+8D;#d6z`&I>Ke=Ksa3>w+cUy5_L1H13CqM3UG9 z{)YwEq>5qx7L&D6?-tjtT3zi6rU-O>iWc+oDG;gxHy9j)cAEX~2LDYJ00%pz4Rdl# z82sz9?#H=;$aBRXyowxDvgm8UVR!(bcz$43bqjlBz*vaT*u zVPPRy!J0>`Q3>hRsy+Eo?@V6Oi7pB%gO)oj1Yepi4!m-(Dyxf&i>i(eZCDt>%E^O` z{j@oxiDeJp^K0{8V(cQ4xUd<<2EQpGSMXQ+-{^~@AMioJ!NYs935CCZYlnx2PYK-y zp8S{`S}_54pA{$umSP0#1PLT&uX_z8mVTpRV32D(21ev!fU?+EjGm4%qraE_*O+w` zO8I}KfJORH8LIjh8o6s8B&HXLR`P`|k#T!_J3cj*3=G=ABv@(i$pfQSw56l&Xa6gb z{{++o4_~K1)C`YO!|)$M#sBi15Rl_5$A;XS4UUkT`i>!gQZo1bAI^mD*_q;hfkFOZ9RB}~{>SR) r|IyI3;6UB$mGLhSfXCSqGT<*7Ip}ygM7(ze0({7RR+OrcFa-S{ZlDO! literal 0 HcmV?d00001