Add support for the HAL to RESTful services in the ASP. NET Core Web API

Source: Internet
Author: User
Tags export class



HAL (Hypertext Application Language, Hypertext Application language) is a RESTful API data format style that provides an interface specification for the design of restful APIs, while also reducing the coupling between client and server interfaces. Many of today's popular RESTful API development frameworks, including spring REST, also support the HAL specification by default, and when the RESTful API is called, the server returns JSON content contenttype to Application/hal+json. For example:


{
  "_links": {
    "self": {
      "href": "http://example.com/api/book/hal-cookbook"
    }
  },
  "_embedded": {
    "author": {
      "_links": 
        "self": {
          "href": "http://author-example.com"
        }
      }, 
      "id": "shahadat",
      "name": "Shahadat Hossain Khan"
    }
  },
  "id": "hal-cookbook",
  "name": "HAL Cookbook"
}


This JSON response contains richer information than the result of returning only one ID and one name, such as the API address of the current request, the author information of the HAL Cookbook book, and a hypertext link to access the author's information. After the client obtains the response from this server, it is convenient to bind the information to the interface without having to look for the associated information through multiple API calls. On the other hand, the hypertext links contained in this JSON response can also be dynamic, such as paging navigation links, which makes it very convenient for the client to implement paging functionality. This article focuses on how to add support for the HAL to the RESTful API that you have designed for yourself in the ASP. NET Core Web API.


Apworks Frame


Adding support for the HAL to RESTful services in the ASP. NET Core Web API is done through the Apworks framework and the HAL Framework. Both frameworks are open source frameworks that I have designed and developed based on the Apache 2.0 open source, which is based on MIT open source and is therefore fully available for commercial system development. The HAL project provides the basic data model and processing logic for the Hypertext Application Language (Hypertext Application Language), and its support for Json is based on the famous Newtonsoft.json, so performance can be guaranteed. The simple and fast fluent interface (fluent Interface API) programming method makes it easy to build a complete and reasonable HAL object model. The HAL project is designed with some object-structured patterns, and interested friends can go to the GitHub Project homepage (Https://github.com/daxnet/hal) to learn about it.



As for the Apworks framework, its main function is not just to provide HAL support to the ASP. NET core Web API, it is more important to set up a fast development framework for microservices based on the. , warehousing, factories, etc.), and integrates with Message Queuing, messaging and subscription, message processing, query services, event storage and other MicroServices architecture function modules based on MongoDB, Entity Framework, RabbitMQ, PostgreSQL, SQL Infrastructure services, such as server, are implemented. At present, the entire framework is still in the development and refinement stage, readers are interested in the Apworks examples case project to view the Apworks framework case code, case code is also in sync Update. After all the case code development is completed, I will release a relatively stable version of the Apworks framework.



It is worth mentioning that the Apworks.Integration.AspNetCore package in the Apworks framework provides a development extension of the ASP. NET Core Web API, and support for HAL is part of the package. The Ok,apworks framework and the HAL framework briefly introduce these, which are not the focus of this article. Next, let's look at how to quickly implement HAL support in the ASP. NET Core Web API.


The simplest case


In fact, in the article "using Apworks to develop data services in ASP. NET Core: Support for HAL," I've described how to provide a JSON data format for the HAL while Apworks quickly build the data service. The case was to meet the data service development model, such as the need to inject warehousing instances, and the controller needs to provide a default get, POST, PUT, delete operations. This is too heavy for a generic web API controller that only needs to implement some specific functionality. So, let's start with the simplest case.


  1. Open Visual Studio 2017 and create a new ASP. NET Core Web API. NET Framework recommends choosing. NET Core/asp.net Core 2.0, the project template selects the Web API, and a default ASP. 2.0 Web API application is generated. You can not enable Docker support for the moment
  2. Launching the ASP. NET Core Web API application directly will output value1 and value2 two values in the browser by default:



  3. Add Apworks and Apworks.Integration.AspNetCore two package to your project, as described in the article "Using Apworks for rapid development Data Services in ASP. NET Core". Note that the version must be greater than or equal to 0.1.138 (currently a development version)



  4. When added successfully, the NuGet dependencies for the ASP. NET Core Web API application resemble the following:



  5. Double-click Open Startup.cs file, and in the Configureservices method, add the following code:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
    
        var halBuildConfiguration = new HalBuildConfiguration(new HalBuildConfigurationItem[]
        {
            new HalBuildConfigurationItem("Values.Get", context =>
                new ResourceBuilder().WithState(null)
                    .AddSelfLink()
                    .WithLinkItem(context.HttpContext.Request.GetDisplayUrl())
                    .AddEmbedded("values")
                    .Resource(new ResourceBuilder().WithState(context.State)))
        });
    
        services.AddApworks()
            .WithHalSupport(halBuildConfiguration)
            .Configure();
    }
  6. Double-click the open ValuesController.cs file, and on the Get () method, add the Supportshal feature:

    [HttpGet]
    [SupportsHal]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }
  7. Running again, you can see that the returned result is already the JSON format of the HAL, Content-type for Application/hal+json:


In the simplest case, we took only a few lines of code and spent less than 10 minutes, creating the default project for the ASP. NET Core Web API as a RESTful API project that supports the HAL JSON format. Here are a few important points:


    1. You first need to create a Halbuildconfiguration object that can hold one or more Halbuildconfigurationitem objects, each Halbuildconfigurationitem object containing " Information about which Controller's action return value needs to be handled by HAL format "and" how to handle the return result of the API and wrap it into the HAL JSON data format "
    2. Constructs the first parameter of the Halbuildconfigurationitem, which specifies the method signature of the action under the API controller so that it can determine the API that the HAL processes. The approximate rules are as follows, but in fact more flexible:
      1. *. Get: Represents a Get method that matches all controllers with a parameter number of 0
      2. Values.get: Represents a Get method that matches the number of parameters 0 under the values controller
      3. Values.get (int,string): Represents a Get method that matches the number of parameters under the values controller, with a type of int and string, respectively, 2
    3. Constructs the second parameter of the Halbuildconfigurationitem, which specifies how the HAL JSON is produced. For more detailed documentation on Hal Resourcebuilder, please refer to the Https://github.com/daxnet/hal
    4. Using the Supportshal attribute on the corresponding controller action, labeling the current method needs to produce the output of the HAL JSON. Supportshalattribute can also be used directly at the controller level to label the current controller, and all actions can support the output of the HAL JSON


The process is very simple and very flexible, and developers can fully customize the resulting HAL JSON format (for example, in this example, we output the requested URL path (i.e., the _links.self node) to the result of the RESTful API. Next, let's look at a slightly more complex scenario and see how to quickly implement service-side paging through the RESTful API of the HAL JSON.


Service-side Paging case description


Paging is an unavoidable common problem in Web service development. The amount of data from the server is often large, and even if a large portion of the data can be filtered out by query criteria, the amount of data in the user database is still unpredictable. The use of service-side paging, not only can reduce the network data transmission, improve service responsiveness, but also reduce the pressure on the client data processing, to provide users with a better experience. The Apworks.Integration.AspNetCore package enables developers to easily implement specialized service-side paging capabilities by providing HAL support to the ASP. NET Core Web API. Next, let's look at a simple case: paging through 26 English letters and returning the data for the page based on the user's input criteria.



We still use the Web API project above:


  1. Change the Get () method in Valuescontroller to the following code:

    [HttpGet]
    [SupportsHal]
    public IActionResult Get(int page = 1, int size = 5)
    {
        var values = new[] { "a", "b", "c", "d", "e",
            "f", "g", "h", "i", "j",
            "k", "l", "m", "n", "o",
            "p","q", "r","s","t",
            "u","v","w","x","y",
            "z" };
        var skip = (page - 1) * size;
        var take = size;
        var records = values.Length;
        var pages = (records + size - 1) / size;
        return Ok(new PagedResult(values.Skip(skip).Take(take), page, size, records, pages));
    }
  2. Modify the Startup.cs file, change the Configureservices method to the following code, note that the first parameter of Halbuildconfigurationitem, has become a values.get (int, int), Represents a Get method that matches valuescontroller with two int type parameters:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
    
        services.AddApworks()
            .WithHalSupport(new PagedResultHalBuildConfiguration("Values.Get(int, int)"))
            .Configure();
    }
  3. Ctrl+f5 run the Web API application directly and output the following in the browser:



    As you can see, the English alphabet has been output by paging, and the _links node contains a link to self, first, last, next, and at the same time, the server also returns information about the current page number, per page, total number of records, and total pages.

  4. In the browser, enter http://localhost:52566/api/values?page=2, resulting in the following results:



    The second page of information is now displayed, and the paging link has been updated accordingly. If your browser has a JSON-formatted Data View plug-in, then it is likely that the hyperlinks in the JSON can already be clicked directly, so you can click these links directly in the browser to achieve the page jump, very convenient.


This shows that it is convenient to add HAL support for RESTful services based on Apworks in the ASP. NET Core Web API. In the above pagination case, the paging query is implemented by adding a query string named page to the URL, which corresponds to the first page parameter in the Get method. So, what if I want to use a different query string as the page number parameter for pagination?


Custom Paging parameters


The custom paging parameter method is simple, just add pagenumberattribute before the parameter definition. For example, the following get method:


[HttpGet]
[SupportsHal]
public IActionResult Get([PageNumber] int p = 1, int size = 5)
{
    var values = new[] { "a", "b", "c", "d", "e",
        "f", "g", "h", "i", "j",
        "k", "l", "m", "n", "o",
        "p","q", "r","s","t",
        "u","v","w","x","y",
        "z" };
    var skip = (p - 1) * size;
    var take = size;
    var records = values.Length;
    var pages = (records + size - 1) / size;
    return Ok(new PagedResult(values.Skip(skip).Take(take), p, size, records, pages));
}


We use Pagenumberattribute to specify that the parameter p is a paging parameter, so when you access the data for a particular page, you can do so using http://localhost:52566/api/values?p=2:





Client Example


Now that we have a RESTful API for service-side paging, we might as well build a client app to try out the service-side paging API that supports the HAL JSON format. To do this, I built a client project that was developed using angular 4 and typescript, with the main code as follows:

// LettersResponse.ts
export class LettersResponse {
    public first: string;
    public prev: string;
    public next: string;
    public last: string;
    public values: string[];
}

// my-letters-service.service.ts
@Injectable()
export class MyLettersServiceService {

  constructor(private http: Http) { }

  getLetters(url: string): Promise<LettersResponse> {
    return this.http.get(url)
      .toPromise()
      .then(response => {
        const json = response.json();
        return {
          first: json._links.first ? json._links.first.href : null,
          last: json._links.last ? json._links.last.href : null,
          prev: json._links.prev ? json._links.prev.href : null,
          next: json._links.next ? json._links.next.href : null,
          values: json._embedded.values
        };
      });
  }
}

// app.component.ts
@Component({
  selector: ‘app-root‘,
  templateUrl: ‘./app.component.html‘,
  styleUrls: [‘./app.component.css‘],
  providers: [MyLettersServiceService]
})
export class AppComponent implements OnInit {

  response: LettersResponse;

  constructor(private service: MyLettersServiceService) {
  }

  ngOnInit(): void {
    this.service.getLetters(environment.serviceUrl)
      .then(res => this.response = res);
  }

  onLinkClicked(url: string): void {
    console.log(url);
    this.service.getLetters(url)
    .then(res => this.response = res);
  }
}

// app.component.html
<div *ngIf="response">
  <ul>
    <li *ngFor="let c of response.values">
      <h2>{{c}}</h2>
    </li>
  </ul>
  <button (click)="onLinkClicked(response.first)" [disabled]="!response.first">First Page</button>
  <button (click)="onLinkClicked(response.prev)" [disabled]="!response.prev">Previous Page</button>
  <button (click)="onLinkClicked(response.next)" [disabled]="!response.next">Next Page</button>
  <button (click)="onLinkClicked(response.last)" [disabled]="!response.last">Last Page</button>
</div>


Use NgCLI on the command line to start the client program, and then visit http: // localhost: 4200. The results are as follows:

to sum up
This article describes how to use Apworks' extension to ASP.NET Core to implement HAL support for RESTful APIs. The article uses two cases to show that ASP.NET Core Web API support for HAL is very simple and convenient, and the customization is very powerful. The second server-side paging case introduced Angular and TypeScript. A simple client page to show in more detail the convenience of a RESTful API with HAL features. As mentioned above, the support for HAL is only a part of the extension of ASP.NET Core in the Apworks framework. The Apworks framework is more focused on providing solutions for the rapid development of microservices. In future articles, I will introduce more about Apworks support for microservices.

Add HAL support for RESTful services in ASP.NET Core Web API

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.