Build a standard REST API with ASP. NET Core 2.0--GET and POST

Source: Internet
Author: User
Tags try catch

This article transferred from: https://www.cnblogs.com/cgzl/archive/2018/05/23/9047626.html

Some of the preparatory knowledge required in this article can be seen here: http://www.cnblogs.com/cgzl/p/9010978.html and http://www.cnblogs.com/cgzl/p/9019314.html

This article describes the use of ASP. NET core to establish a pseudo-restful web API with Richardson Maturity Level 2, this article describes get and post.

The item used is (right-click Save As, and then change the suffix name to zip): https://images2018.cnblogs.com/blog/986268/201805/986268-20180516191053536-1701412182.jpg

Naming guidelines for RESTful API Resources (Resource)

First, the resource should use a noun, which is something, not an action .

For example:

    • The api/getusers is not correct.
    • GET api/users is right.
    • GET Api/users/{userid}.

So the resources should use nouns .

If it is a non-hierarchical resource, it should not be named this way: Api/xxx/xxx/users, but should use api/users.

If it is a single resource, this should not be api/id/users, but should be Api/users/{userid}.

( whether the resource name is plural or according to personal habits ).

Naming should reflect the structure of resources

For example, api/department/{departmentid}/emoloyees, this means that department (department) and employee (employee) are the principal and subordinate relationships.

and Api/department/{departmentid}/emoloyees/{employeeid}, it represents an employee under the department.

while filtering, sorting, and so on are not resources , so writing api/users/orderby/username is incorrect.

The filter sort parameter is passed in as a query parameter, and the correct wording should be: api/users?orderby=username.

Sometimes, however, RPC-style method calls can be difficult to map to canonical resource naming, so it is sometimes possible to break specifications such as Api/users/{userid}/totalsalaries.

What type should be used as ID

If you use the int as the ID, most of the time is not a problem, but if you use the ID of the database is self-increment, if you replace the database, and then migrate the original data to the new database, then the existing data ID will change, then the equivalent of all the resources address has changed, This is a violation of this:

The URI of the resource should always be the same .

so GUIDs should be used as IDs . (But do I use the self-increment int as ID for the sake of convenience?).

The advantage of using a GUID as a primary key is that:

    • can switch databases
    • The internal implementation details are hidden on a certain level of granularity
Interacting with resources through HTTP methods

For the country resource in the project, please refer to the following list:

Here get can be understood to get (query) resources, post for add resources, put for the overall update resources, patch for the local update resources, delete to delete resources.

What needs to be mentioned here are the latter two:

    • HEAD: Similar to get, but it should not return the body of the response, all unresponsive payload. It is primarily used to get some information about a resource, such as viewing whether a resource is available, and so on.
    • OPTIONS: It is an interactive way of querying a resource URI, in other words, using it to know whether a URI can perform a Get or post action, usually in the headers of the response rather than in the body. So there is no response to the payload.
Set up a controller

First you need to build a countrycontroller:

Note the [Route] property label labeled above Countrycontroller, whose value is the route prefix for all actions under the controller, can be written as a fixed address, or written as "Api/[controller" "This part of [controller] becomes the controller's name, and here is the" Api/country ".

If you use [controller], if the controller refactoring name changed, then the controller's routing address is also changed the address of the resource, this is not good, so it is recommended to write a fixed address do not use [controller].

GET Resource

GET all the country:

(the use of AutoMapper is not introduced here )

GET a country:

The two methods returned are Jsonresult, which seems to be fine, because we want the result in JSON format. Take the second method, for example, using the Postman test, if you can query the data:

This is not a problem, but if you query a resource that does not exist:

This is problematic, if the query is not a resource, then the return should be 404 NOF FOUND instead of a OK.

Status Code

Status codes are important because only the status code tells the consumer of the API:

    • Whether the request was successful as expected or failed
    • If an error occurs, who should be responsible for this error

Here's a list of the status codes that the Web API will use:

Level 200, indicating success:

    • 200-ok
    • 201-created, indicating that the resource creation was successful
    • 204-no content, executed successfully, but should not return anything

Level 400, which indicates an error caused by the client:

    • 400-bad request, which indicates that the consumer of the API sent to the server is wrong
    • 401-unauthorized, indicating no permissions
    • 403-forbidden, indicating that the user was authenticated successfully, but that the user still cannot access the resource
    • 404-not found, indicating that the requested resource does not exist
    • 405-method not allowed, which is when we try to send a request to a resource, the HTTP method used is not allowed, for example, using post api/countries, and the resource only implements GET, so post is not allowed
    • 406-not acceptable, where media type is involved, for example, the API consumer is requesting a media type of application/xml format, and the API only supports Application/json
    • 409-conflict indicates that the request cannot be completed because the request is in conflict with the state of the current resource, such as when you edit a resource's data and the resource is updated by someone else, you put your data in a 409 error, and sometimes it is used when you try to create a resource that already exists.
    • 415-unsupported media type, this and 406 just return, for example, I submit data to the server media type is XML, and the server only supports JSON, then it will return 415
    • 422-unprocessable entity, which indicates that the requested format is fine, but there are errors in semantics, such as entity validation errors.

Level 500, server error:

    • 500-internal Server error, which indicates that the server has been wrong

Back to the two methods, by default Jsonresult will return a number of OK status code, you can modify the Jsonresult to support other status codes. But the controller provides some help methods to return Iactionresult and specify a specific status code for 200, which is the Ok () method.

There is no need to manually return the Jsonresult.

It is important to note that the content negotiation for the collection, if the collection is empty, should not return 404, because the country resource exists, but its content is empty.

Then take a look at get specific individual resources:

For a single resource, if not found, you need to return 404 Not Found, you can use the controller's Help method NotFound ().

Handling Exceptions

When an action exception occurs, ASP. NET core returns 500 by default:

But it's better to handle it yourself. You can use try Catchin action:

This is due to a server error, so the 500 status Code Internal Server error should be returned.

Note that this should not be returned to exception, because this is the internal implementation details of the program, and it is useless to the customer.

In addition, we can handle exceptions globally.

The Configure method inside the startup:

Use the app. Useexceptionhandler (), you can customize some logic inside. If this place code is more, you can encapsulate it as an extension method and then use the app. The form of the USEXXX call.

I'll go back to try catch in action, but pay attention to change the value of the environment variable aspnetcore_environment to production (in fact, not development can):

GET a resource for a parent-child relationship

This is a typical scenario where a country contains multiple cities, which is a parent-child relationship.

First look at the domain model:

This should be very simple.

In addition to establish cityresource,repository and irepository, registration configuration, seed data and so on, these are not posted.

Build Citycontroller Below

As mentioned earlier, for the parent-child, master-slave relationship of the resources, the routing address of its sub-resources should be the above, because the controller under all the action of the route prefix is the same, so put this route to the controller level as the prefix of all action.

The Get method itself is relatively simple, nothing to say, there are some of the methods involved in writing yourself.

Look at the results of the operation:

If country is not found, 404 is returned:

Below get single city:

Note that a single resource should return 404 if it cannot be found, and the empty collection is not, as mentioned earlier.

Find the result of the resource:

When you can't find country or city, you should return 404, not the map.

Content negotiation

In short, if a resource supports multiple presentation formats, consumers can choose the format they want .

Media type is used here, which can be passed through the request's accept header, which is common:

Application/json and Application/xml ... Wait a minute

If you do not specify the accept header, you should return a default format, which is Application/json in ASP. NET Core 2.0.

When the requested media type is unavailable, and the consumer does not support the default format, the server should return the 406 not acceptable status code.

the ASP. NET Core supports both output and input formatters .

The output media type is inside the accept header, and the input media type is inside the Content-type header .

Take a look at the current situation when the requested accept header is Application/json:

When the requested accept header is application/xml:

They all return in JSON format.

Because the server (project) now does not support XML, it returns the default JSON format, but strictly speaking, it is not correct, so it needs to be handled.

In startup, the Configureservices method:

Set this returnhttpnotacceptable property to True and return 406 not acceptable if the desired format is not supported:

Returns the default JSON format without specifying the Accept header:

Below, you add support for the project in XML output format:

Try again:

At this point, the XML is returned successfully.

Create a resource

First, look at the security and power of the method.

security means that a method does not change the presentation of a resource after it is executed.

idempotent means that the method will get the same result no matter how many times it executes.

The following is a list of the security and idempotent of the HTTP method:

Refer to this list to help determine which HTTP method to use in some cases.

Here's a look at the code for creating country:

This code is simple, and the data is brought in from the body of the request.

It is important to note what is returned, and if the post operation succeeds, the standard practice is to return the 201 Created status code.

Here you can use the Createdatroute () method, which allows the response to take the location header, which contains a URIin the location header, With this URI you get to the resource we just created (country).

The first parameter of this method is a route name that can be used to generate the URI just mentioned. In this case, the route name should correspond to the Getcountry action method, so add the route name for this action:

This is consistent with the route name used in the Post method return, and the second parameter is an anonymous class with a property ID, which will program the parameters in the route, and the last parameter is the data returned by the response.

The following test, when sending the request do not forget to set Content-type to Applicaiton/json:

Then the data:

Then send the request to see the body part of the response:

Then look at the header of the response:

Here you can see the URI of the location header, through which you get to the country resource that you just created, and I won't test it here.

If you perform this post again, look at the results:

The ID of the returned data is 6, not the same as before, so the post is not idempotent, and the result is different after each execution.

Create a child resource

The creation of the country is done, and now the city can be created.

This is the same as above, just pay attention to the parameters of the route.

Test:

Create parent-child resources at the same time

This is a common requirement, and a country and its subordinate cities are passed in at the same time and created together in action.

First you need to modify the Countryaddresource:

Then, then, all the mapping operations are given to AutoMapper and EntityFramework core.

Test:

Then get these two cities:

Create a collection resource

This time I'm going to add a collection of countries at once.

Since the collection of country is equivalent to a different resource, it can be placed in a separate controller, and it is no problem.

This is actually nothing special, note that the parameters passed in is IEnumerable. For convenience, go back to OK () for the time being.

Test:

OK, the following resolves the returned issue.

We are going to return the Createdatroute method, because it contains a routing address that can return the collection resource, so you need to create an action whose parameters should be a collection of the ID of the POST method's return data. However, because the routing parameter does not support the collection form, can only be passed as a string, so the routing parameters can be made: api/xx/(1,2,3,4,5).

Instead of the action method, the accepted parameter should be a collection of IDs, which should be a collection type, so we can use Modelbinder to convert the ID string into a collection of IDs:

Then, you need to do a get collection of the action method corresponding to this post Action:

The type of argument that this action expects is the collection of IDs, and the actual strings passed in as IDs are converted by Arraymodelbinder.

Finally, the return of the Post method is modified:

Test it:

Then get this link again:

Ok

If post to an address of a single resource

If post to this address http://localhost:5000/api/countries/{id},

Then, if the resource for that ID does not exist, it should return 404;

If the resource for that ID exists, you should return 409 Conflict.

(post is not idempotent, it cannot have the same result for multiple requests).

Test the situation where the ID resource does not exist:

In the case where the resource of the ID is being tested:

Or 404, this does not work, so it needs to be handled manually:

Look at the results:

OK, the correct status code is returned for both the resource that is present in the ID and the resource that does not exist.

Support for entering other types of Content-type

I've talked about how to return the XML format, and here's how to make the request in XML format, first add this in Startup.cs:

Then, you need to set the requested Content-type to Application/xml:

I did not apply the XML data for testing.

This time, we'll write delete, UPDATE, PATCH.

The source address of this article: https://github.com/solenovex/ASP.NET-Core-2.0-RESTful-API-Tutorial

Build a standard REST API with ASP. NET Core 2.0--GET and POST

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.