Skip to content

Tutorial 02 05 Entity Collection Endpoints

mattl91 edited this page Mar 3, 2023 · 13 revisions

Harmony Core Logo

Entity Collection Endpoints

Entity collection endpoints enable you to expose collections of entities, such as "all customers", "all orders", etc.

VIDEO: Creating a Basic Solution

Here is an example of an entity collection endpoint URL for all customers:

https://localhost:8086/odata/v1/Customers

Your first reaction might be, "Why would I want to do that? I don't have a use case for exposing everything at once." But remember, you're building an OData service, and with OData, the developers writing applications to interact with your service will use OData query URLs to specify the data they need. So exposing all entities in a collection is completely normal. In fact, it is the most common thing that OData services do.

Enabling the Feature

To generate endpoints that expose entity collections, you must set the Enable collection endpoints option.

  1. At a Windows prompt, move to the directory with your Harmony Core solution and type harmonycore gui. When the GUI for the Harmony Core CLI tool opens, go to the OData screen, scroll down to the Enable collection endpoints option, and double-click it.

  2. In the "Enter new value" screen, click the diamond icon to the right of Enable collection endpoints. (The diamond will change to a checkmark.) Then click OK.

Generating the Code

  1. Save the setting you made by selecting File > Save from the menu.

  2. Regenerate generated code for your solution by selecting Codegen > Regen from the menu.

When code generation is finished, a message will list the files that were generated.

What Changed

Enabling this feature causes a GET method to be generated in each of your controller classes. Let's see what this method looks like in Services.Controllers\CustomersController.dbl.

  1. In Visual Studio Solution Explorer, double-click Services.Controllers\CustomersController.dbl to open the file in the editor, and then scroll down to the GetCustomers method declaration. The method accepts no parameters and returns a collection of all customers. You will find similar code in the other controllers.

If you examine the GetCustomers method declaration, you will notice it is decorated with attributes that specify the way operations exposed by the controller are accessed. For example, the {HttpGet("Customers")} attribute specifies that this endpoint will be accessed by adding “Customers” to the base address of the service:

https://localhost:8086/odata/v1/Customers

The other attributes for this method define the type of returned data (application/json), HTTP status codes to be returned, and the maximum depth for the $expand query option (4 levels).

{HttpGet("Customers")}
{Produces("application/json")}
{ProducesResponseType(^typeof(IEnumerable<Customer>),StatusCodes.Status200OK)}
{EnableQuery(MaxExpansionDepth=4)}
;;; <summary>
;;; Get all Customers
;;; </summary>
;;; <returns>Returns an IActionResult indicating the status of the operation and containing any data that was returned.</returns>
public method GetCustomers, @IActionResult
proc
    mreturn Ok(_DbContext.Customers.AsNoTracking())
endmethod

Above this method, you will see a constructor method that accepts instances of various objects and saves references to them in these class variables:

;;Services provided via dependency injection
private _DbContext, @Services.Models.DBContext
private _ServiceProvider, @IServiceProvider
private _AppSettings, @IOptions<AppSettings>

;;; <summary>
;;; Constructs a new instance of CustomersController
;;; </summary>
;;; <param name="aDbContext">Database context instance (DI)</param>
;;; <param name="aServiceProvider">Service provider instance (DI)</param>
;;; <param name="aAppSettings">Application settings</param>
public method CustomersController
    aDbContext, @Services.Models.DBContext
    aServiceProvider, @IServiceProvider
    aAppSettings, @IOptions<AppSettings>
proc
    this._DbContext = aDbContext
    this._ServiceProvider = aServiceProvider
    this._AppSettings = aAppSettings
endmethod

What you see here in this constructor method is the dependency injection pattern. The service's startup code registers several useful services and makes them available throughout the environment via dependency injection. Classes in the web service can receive instances of those services, as needed, by declaring specifically-typed parameters on their constructor methods.

In this case, the constructor method doesn't need to use these services directly, so it saves references to the service objects in local class variables. This way they will be accessible to other code in the class that may need to use them later.

This code (constructor, method, etc.) is not new. It was present prior to enabling the entity collection endpoints. But it is useful to have an overall understanding of what the code is doing.

Building the Code

  1. Select Build > Rebuild Solution from the Visual Studio menu.

  2. Check the Output window, you should see something like this:

    1>------ Rebuild All started: Project: Repository, Configuration: Debug Any CPU ------
    2>------ Rebuild All started: Project: Services.Models, Configuration: Debug Any CPU ------
    3>------ Rebuild All started: Project: Services.Controllers, Configuration: Debug Any CPU ------
    4>------ Rebuild All started: Project: Services.Isolated, Configuration: Debug Any CPU ------
    5>------ Rebuild All started: Project: Services, Configuration: Debug Any CPU ------
    6>------ Rebuild All started: Project: Services.Host, Configuration: Debug Any CPU ------
    ========== Rebuild All: 6 succeeded, 0 failed, 0 skipped ==========
    

Testing the Feature

  1. In Visual Studio, press F5 (Start Debugging) to start the self-hosting application.

Once again you should see the console window appear, with a message confirming that your service is running.

  1. With your web browser, go to the "all customers" endpoint:

You should see a JSON response that includes the full record for all 38 customers in the sample customer data file.

You should also be able to do the same with the "all entities" endpoints for the other four entity types:

* https://localhost:8086/odata/v1/Items
* https://localhost:8086/odata/v1/Orders
* https://localhost:8086/odata/v1/OrderItems
* https://localhost:8086/odata/v1/Vendors

The data returned by the Orders and OrderItems endpoints is relatively large and might take a few seconds to render in your browser. REST assured (pun intended), the Harmony Core service returned the data very quickly, but it takes your web browser a few seconds to deal with all that incoming data!

Stop the Service

  1. When you are finished testing the endpoints, stop the self-hosting application.

Suppressing Entity Collection Endpoints

Enabling collection endpoints adds endpoints to all your code-generated OData controllers, but it is possible to prevent the generation of these endpoints for certain structures. This capability is documented in Structure-Specific Endpoint Control.


Next topic: API Documentation


Clone this wiki locally