finish lecture 4

main
borb 4 weeks ago
parent 900a5f254c
commit 56278a2788

File diff suppressed because one or more lines are too long

@ -1,149 +1,167 @@
# 5. REST Architecture ---
marp: true
paginate: true
math: mathjax
theme: buutti
title: 4. RESTful HTTP Methods
---
# HTTP Methods for RESTful APIs # RESTful HTTP Methods
* You have so far implemented GET and POST methods for reading resources from the API and creating new ones to it <!-- headingDivider: 5 -->
* All the primary methods for following the uniform interface requirement are __GET, POST, PUT, PATCH __ and __DELETE__ <!-- class: invert -->
* Others exist, but these are by far most commonly used
* These methods correspond to __CRUD __ operations __Create__ , __Read__ , __Update __ and __Delete__
* CRUD describes what is done to a resource after a request is sent
# HTTP Methods for RESTful APIs (continued)
The primary HTTP request methods with descriptions:
| __Method__ | __Attribute__ | __Description__ |
| :-: | :-: | :-: |
| GET | [HttpGet] | _Read _ a representation of a resource |
| POST | [HttpPost] | _Create _ new resources |
| PUT | [HttpPut] | Fully _Update _ an existing resource |
| PATCH | [HttpPatch] | Partially _Update _ an existing resource |
| DELETE | [HttpDelete] | _Delete _ a resource |
[https://www.restapitutorial.com/lessons/httpmethods.html](https://www.restapitutorial.com/lessons/httpmethods.html)
# Handling HttpPost Requests
Remember, that HTTP requests can include a content body
In ASP.NET, this content is assigned to a variable with the [FromBody] attribute:
[HttpPost]
public string[] Post([FromBody] string someContent)
{
// someContent holds the content of the request body
return new string[] { text };
}
Note that the [FromBody] attribute can only be used on one parameter
However, nothing prevents you from using a custom type variable
# Handling HttpPost Requests (continued)
ASP.NET deserializes the request content body into an object: ## Contents
public class Student - [HTTP methods for RESTful APIs](#http-methods-for-restful-apis)
- [HTTP `POST` method](#http-post-method)
- [HTTP `PUT` method](#http-put-method)
- [HTTP `DELETE` method](#http-delete-method)
- [HTTP `PATCH` method](#http-patch-method)
{ ## HTTP methods for RESTful APIs
public int Id { get; set; } ### RESTful API
public string Name { get; set; } * We'll be extending our Web API into a full-blown ***RESTful API***
* More about REST in [Frontend Basics Lecture 3: REST Architecture](https://gitea.buutti.com/education/frontend-basics/src/branch/main/3-rest-architecture.md)
} * A good idea to also check out [Frontend Basics Lecture 2: HTTP methods](https://gitea.buutti.com/education/frontend-basics/src/branch/main/2-http.md)
* We have so far implemented `GET` and `POST` methods for reading resources from the API and creating new ones to it, respectively
// In controller class: * All the primary methods for following the uniform interface requirement are `GET`, `POST`, `PUT`, `PATCH` and `DELETE`
* Others exist, but these are by far most commonly used
[HttpPost] * These methods correspond to ***CRUD*** operations *__Create__*, *__Read__*, *__Update__* and *__Delete__*
* CRUD describes what is done to a resource after a request is sent
public Contact Put(int id, [FromBody] Contact contact)
{
// Contacts = list of Contact objects, fetched from some repository
Contacts.Add(contact); ### Primary HTTP request methods
return contact; The primary HTTP request methods with descriptions:
} | Method | Attribute | Description |
|:--------|:---------------|:------------------------------------------|
| `GET` | `[HttpGet]` | ***Read*** a representation of a resource |
| `POST` | `[HttpPost]` | ***Create*** new resources |
| `PUT` | `[HttpPut]` | Fully ***update*** an existing resource |
| `PATCH` | `[HttpPatch]` | Partially ***update*** an existing resource |
| `DELETE` | `[HttpDelete]` | ***Delete*** a resource |
# Creating a POST Request with Postman [https://www.restapitutorial.com/lessons/httpmethods.html](https://www.restapitutorial.com/lessons/httpmethods.html)
* ASP.NET knows to deserialize the content if the content type is set to JSON in the HTTP requests __headers__ ## HTTP `POST` method
### Handling `HttpPost` Requests
* Remember that HTTP requests can include a content body
* In ASP.NET, this content is assigned to a variable with the `[FromBody]` attribute:
```csharp
[HttpPost]
public string[] Post([FromBody] string someContent)
{
// someContent holds the content of the request body
return new string[] { text };
}
```
* Note that the `[FromBody]` attribute can only be used on one parameter
* However, nothing prevents you from using a custom type variable
---
* ASP.NET deserializes the request content body into an object:
```csharp
// Models/Contact.cs
public class Contact
{
public int Id { get; set; }
public string Name { get; set; }
}
```
* ```csharp
// Controllers/ContactsController.cs
[HttpPost]
public Contact Put(int id, [FromBody] Contact contact)
{
// Contacts is a list of Contact objects, fetched from some repository
Contacts.Add(contact);
return contact;
}
```
### Creating a POST Request with Postman
#### Request headers
* ASP.NET knows to deserialize the content if the content type is set to JSON in the HTTP requests *__headers__*
* Headers are optional parameters that can be included in every HTTP request * Headers are optional parameters that can be included in every HTTP request
* Headers are set in Key-Value format * Headers are set in a Key-Value format
* When creating a request in Postman, to inform the server what type of content was just sent, add a new key "Content-Type" and set its value to "application/json" in the _Headers _ tab: * When creating a request in Postman, to inform the server what type of content was just sent, add a new key `Content-Type` and set its value to `application/json` in the _Headers_ tab:
![](imgs/5-rest-architecture_1.png) <div class='centered'>
# Creating a POST Request with Postman (continued) ![w:800px](imgs/5-rest-architecture_1.png)
After setting the header, </div>
select the Body tab, #### Request body
change the content type to raw, After setting the header,
1) select the Body tab,
select JSON from the dropdown menu, and 2) change the content type to raw,
3) select JSON from the dropdown menu, and
insert the content in JSON format 4) insert the content in JSON format
![](imgs/5-rest-architecture_2.png)
# Creating a POST Request with Postman - Example
Suppose the Post method from before is routed at http://localhost:54106/api/students:
![](imgs/5-rest-architecture_3.png)
# Exercise 1: Creating a POST Endpoint
Continue working on CourseAPI. <div class='centered'>
Create a Post method and endpoint which adds a new course to the list in the repository, with a running ID. Content and Author values are obtained from the request body: ![w:800px](imgs/5-rest-architecture_2.png)
![](imgs/5-rest-architecture_4.png) </div>
# HTTP PUT
Use PUT to replace an existing resource, e.g. an element in a list, with a new one #### Sending the request
The ID of the resource to be replaced should be in the request URI * If the `POST` method is routed at `http://localhost:54106/api/contacts`:
The information about the new resource should be in the request body like in POST requests <div class='centered'>
![](imgs/5-rest-architecture_5.png) ![w:800](imgs/5-rest-architecture_3.png)
# Handling HttpPut Requests </div>
The ID is fetched from the URI and the contents from the request body ### Exercise 1: Creating a `POST` Endpoint
<!--_class: "exercise invert" -->
Filtering is used to copy all objects from the original list except for the new contact object, which comes from body Continue working on the CourseAPI.
[HttpPut("{id}")] 1) Create a `POST` method and endpoint which adds a new course to the list in the repository with a running ID. Content and Author values are obtained from the request body:
![](imgs/5-rest-architecture_4.png)
public List<Contact> Put(int id, [FromBody] Contact contact) ## HTTP `PUT` method
{ * Use `PUT` to replace an existing resource, e.g. an element in a list, with a new one
* The ID of the resource to be replaced should be in the request URI
* The information about the new resource should be in the request body like in `POST` requests
// Contacts = list of Contact objects, fetched from some repository <div class='centered'>
List<Contact> updatedList = Contacts.Select(c => c.Id != id ? c : contact).ToList(); ![w:900px](imgs/5-rest-architecture_5.png)
Contacts = updatedList; </div>
return updatedList; ### Handling `HttpPut` requests
} * The ID is fetched from the URI and the contents from the request body
* Filtering is used to copy all objects from the original list except for the new `contact` object, which comes from body
```csharp
// Controllers/ContactsController.cs
[HttpPut("{id}")]
public List<Contact> Put(int id, [FromBody] Contact contact)
{
// Contacts is a list of Contact objects, fetched from some repository
List<Contact> updatedList = Contacts.Select(c => c.Id != id ? c : contact).ToList();
Contacts = updatedList;
return updatedList;
}
```
# Exercise 2: Creating a PUT Endpoint ### Exercise 2: Creating a `PUT` Endpoint
* In CoursesController class, create a method for PUT requests with the URI api/courses/{id} * In CoursesController class, create a method for PUT requests with the URI api/courses/{id}
* The ID of the course to be replaced with should be in the request URI and the contents of the new course should be in the request body. * The ID of the course to be replaced with should be in the request URI and the contents of the new course should be in the request body.
@ -152,105 +170,103 @@ return updatedList;
* Return a 404 status code if a course with the corresponding ID does not exist * Return a 404 status code if a course with the corresponding ID does not exist
* Test with Swagger/Postman * Test with Swagger/Postman
# HTTP DELETE ## HTTP `DELETE` method
Use DELETE to delete an existing resource, e.g. an element in a list * Use `DELETE` to delete an existing resource, e.g. an element in a list
* The ID of the resource to be deleted should be in the request URI
* As with the `GET` method, a body is not needed
![](imgs/5-rest-architecture_6.png)
The ID of the resource to be deleted should be in the request URI ### Handling `HttpDelete` Requests
As with GET method, a body is not needed * The ID is fetched from the URI
```csharp
// Controllers/ContactsController.cs
[HttpDelete("{id}")]
public List<Contact> Delete(int id)
{
// Contacts = list of contact objects, fetched from some repository
List<Contact> updatedList = Contacts.Where(c => c.Id != id).ToList();
Contacts = updatedList;
return Contacts;
}
```
![](imgs/5-rest-architecture_6.png) ### Exercise 3: Creating a `DELETE` Endpoint
<!--_class: "exercise invert" -->
# Handling HttpDelete Requests Continue working on CourseAPI.
The ID is fetched from the URI
[HttpDelete("{id}")]
public List<Contact> Delete(int id)
{
// Contacts = list of contact objects, fetched from some repository
List<Contact> updatedList = Contacts.Where(c => c.Id != id).ToList();
Contacts = updatedList;
return Contacts;
}
# Exercise 3: Creating a DELETE Endpoint
* Continue working on CourseAPI.
* Create an endpoint for DELETE requests with the URI api/courses/{id}
* The ID of the course should be fetched from the URI
* The corresponding course should be removed from the list of courses in the repository
* The method should return the updated Courses list (for testing purposes)
* Return a 404 status code if a course with the corresponding ID does not exist
* Test with Postman
# HTTP PATCH
* Use PATCH to partially update a resource
* I.e. update some value inside of a resource
* This saves some resources as only a part of a resource has to be sent instead of an entire document (as opposed to PUT requests)
* Sending and handling PATCH requests with ASP.NET requires some extra work and the use of a third party package: [http://jsonpatch.com/](http://jsonpatch.com/)
# HTTP PATCH (continued)
* To handle PATCH requests in a standardized way, install and add the following NuGet packages to your project:
* Microsoft.AspNetCore.JsonPatch
* Microsoft.AspNetCore.Mvc.NewtonsoftJson
* Then, change the following line in Program.cs (ASP.NET 5: Startup.cs)...
* builder.Services.AddControllers();
* … to this:
* builder.Services.AddControllers().AddNewtonsoftJson();
The body of the PATCH request needs to be in the following form:
[{ "op": "replace", "path": "/propertyName", "value": "newValue"}]
Use the URI to specify the ID of the resource to update
![](imgs/5-rest-architecture_7.png)
# Handling HttpPatch Requests
The ID is fetched from the URI
The property and its new value are specified in the body, which is retrieved as JsonPatchDocument
PATCH is operated on the targeted object
[HttpPatch("{id}")]
public List<Contact> Patch(int id, [FromBody] JsonPatchDocument<Contact> patchDocument)
{
// Contacts = list of contact objects, fetched from some repository
var contact = Contacts.FirstOrDefault(c => c.Id == id);
if(contact != null){
patchDocument.ApplyTo(contact);
}
return Contacts;
} 1) Create an endpoint for `DELETE` requests with the URI `api/courses/{id}`
a) The ID of the course should be fetched from the URI
b) The corresponding course should be removed from the list of courses in the repository
c) The method should return the updated `Courses` list (for testing purposes)
d) Return a `404` status code if a course with the corresponding ID does not exist
2) Test with Postman.
## HTTP `PATCH` method
* Use `PATCH` to *partially* update a resource
* I.e., update some value inside of a resource
* This saves some resources as only a part of a resource has to be sent instead of an entire document (as opposed to `PUT` requests)
* Sending and handling `PATCH` requests with ASP.NET requires some extra work and the use of a third party package [JSON Patch](http://jsonpatch.com/)
---
* To handle `PATCH` requests in a standardized way, install and add the following NuGet packages to your project:
* `Microsoft.AspNetCore.JsonPatch`
* `Microsoft.AspNetCore.Mvc.NewtonsoftJson`
* Then, change the following line in `Program.cs`:
```csharp
builder.Services.AddControllers();
```
* to this:
```csharp
builder.Services.AddControllers().AddNewtonsoftJson();
```
---
* The body of the `PATCH` request needs to be in the following form:
```json
[{ "op": "replace", "path": "/propertyName", "value": "newValue"}]
```
* Use the URI to specify the ID of the resource to update
<div class='centered'>
![w:1000px](imgs/5-rest-architecture_7.png)
</div>
### Handling `HttpPatch` Requests
* The ID is fetched from the URI
* The property and its new value are specified in the body, which is retrieved as a `JsonPatchDocument`
* `PATCH` is operated on the targeted object:
```csharp
// Controllers/ContactsController.cs
[HttpPatch("{id}")]
public List<Contact> Patch(int id, [FromBody] JsonPatchDocument<Contact> patchDocument)
{
// Contacts is a list of contact objects, fetched from some repository
var contact = Contacts.FirstOrDefault(c => c.Id == id);
if(contact != null)
{
patchDocument.ApplyTo(contact);
}
return Contacts;
}
```
### Exercise 4: Creating a `PATCH` Endpoint
<!--_class: "exercise invert" -->
# Exercise 4: Creating a PATCH Endpoint Continue working on CourseAPI.
* Continue working on CourseAPI. 1) Create an endpoint for PATCH requests with the URI `api/courses/{id}`
* Create an endpoint for PATCH requests with the URI api/courses/{id} a) The ID of the course should be fetched from the URI
* The ID of the course should be fetched from the URI b) The corresponding course should be updated according to the JSON PATCH document in the request body
* The corresponding course should be updated according to the JSON PATCH document in the request body c) The method should return the updated `Courses` list (again, for testing purposes)
* The method should return the updated Courses list (for testing purposes) d) Return a `404` status code if a course with the corresponding ID does not exist
* Return a 404 status code if a course with the corresponding ID does not exist 2) Test with Swagger/Postman. Try to change the number of credits for some course!
* Test with Swagger/Postman: try to change the number of credits for some course

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Loading…
Cancel
Save