We will take a look at additional features such as paging, selections as well as additional features to schemas/models.
to get started lets create the order api controller by adding a new http handler based on the cszWebAPIController class.
// Object oOrderAPI is a cszWebAPIController Set psControllerDescription to "allows viewing, adding and deleting orders" Set psControllerTitle to "Order API" Set psControllerVersion to "1" Set psPath to "api/v1/order" Set psVerbs to "*" Object oVendor_DD is a cVendorDataDictionary End_Object Object oInventory_DD is a cInventoryDataDictionary Set DDO_Server to oVendor_DD End_Object Object oSalesPerson_DD is a cSalesPersonDataDictionary End_Object Object oCustomer_DD is a cCustomerDataDictionary End_Object Object oOrderHeader_DD is a cOrderHeaderDataDictionary Set DDO_Server to oSalesPerson_DD Set DDO_Server to oCustomer_DD End_Object Object oOrderDetail_DD is a cOrderDetailDataDictionary Set DDO_Server to oInventory_DD Set Constrain_file to OrderHeader.File_number Set DDO_Server to oOrderHeader_DD End_Object Set Main_DD to oOrderHeader_DD ... End_Object
Next we will define our schema/model for the API.
Procedure OnDefineModelColumnsCustomer Send AddTableColumn File_Field Customer.Customer_Number Send AddTableColumn File_Field Customer.Name Send AddTableColumn File_Field Customer.Address End_Procedure Procedure OnDefineModelColumnsInventory Send AddTableColumn File_Field Inventory.Item_ID Send AddTableColumn File_Field Inventory.Description Send AddTableColumn File_Field Inventory.On_Hand Send AddTableColumn File_Field Inventory.Unit_Price End_Procedure Procedure OnDefineModelDetail Send AddTableColumn File_Field OrderDetail.Detail_Number Send AddTableColumn File_Field OrderDetail.Order_Number Send AddTableColumn File_Field OrderDetail.Item_ID Send AddTableColumn File_Field OrderDetail.Qty_Ordered Send AddTableColumn File_Field OrderDetail.Price Send AddTableColumn File_Field OrderDetail.Extended_Price Send AddModelParent "inventory" (RefProc(OnDefineModelColumnsInventory)) True End_Procedure Procedure OnDefineModels Send BeginModel "order" Send AddTableColumn File_Field OrderHeader.Order_Number Send AddTableColumn File_Field OrderHeader.Customer_Number Send AddModelParent "Customer" (RefProc(OnDefineModelColumnsCustomer)) True Send AddModelChild "Detail" OrderDetail.File_Number (RefProc(OnDefineModelDetail)) True Send AddTableColumn File_Field OrderHeader.Order_Date Send AddTableColumn File_Field OrderHeader.Terms Send AddTableColumn File_Field OrderHeader.Ship_Via Send AddTableColumn File_Field OrderHeader.Ordered_By Send AddTableColumn File_Field OrderHeader.SalesPerson_ID Send AddTableColumn File_Field OrderHeader.Order_Total Send AddTableColumn File_Field OrderHeader.Last_Detail_Num Send EndModel Send BeginModel "orderlist" Send AddTableColumn File_Field OrderHeader.Order_Number Send AddTableColumn File_Field OrderHeader.Customer_Number Send AddTableColumn File_Field OrderHeader.Order_Date Send EndModel End_Procedure
We are definfing a schema called order. This is our main schema and contains the order header fields as well as a parent schema for customer. We also added a child schema for the detail lines as well.
In addition we are declaring a second schema called ‘orderlist’ which we will use to demonstrate using multiple schemas in an API controller.
// Send RegisterPath "GET" "" (RefProc(WebAPI_Get)) Set psPathSummary to "Get List of orders" Set psPathDescription to "Use this API to retrieve a list of orders" Send AddPathresponse 200 "successful return of list of orders" "application/json" True "order"
just like the inventory example we simply declare a GET route with the default WebAPI_Get method, summary and description info for the API documentation.
We also define the response
A test of the new API returns all orders in a json array. This can lead to a lot of data of course.
In order to limit the amount of data returned we want to add paging functionality. The REST library supports required and optional paging and the paging settings can be made for each controller as well as for each path.
to enable paging we can add the following code to our controller
// enable required paging Send SetPaging WEBAPI_PAGING_REQUIRED 50 20
This line will set the controllers paging default to required with a maximum of 50 records per page and a default of 20.
this will make 3 changes to the API.
first the output will automatically be governed by the paging settings.
second on the input side we can now supply the following query parameters
- page
the current page to be returned - pageSize
number of rows to return. this cannot be greater than the maximum page size defined on the controller or route
ad last but not least the return data will include a X-Pagination http header containing the information on the page returned.
The X-Pagination header contains a json object with the following fields
- PageSize
- CurrentPage
- TotalCount (not with embedded db)
- TotalPages (not with embedded db)
the X-Pagination header can be used by the calling program.
In addition to paging we want to be able to sort the orders by different sort orders. We need to declare these so we can allow the client to set the sort order
lets add the following to our route delcaration
Send AddPathOrder "orderNumber" 1 True Send AddPathOrder "orderDate" 3 True Send AddPathOrder "Customer" 2 False Set psPathDefaultOrder to "orderNumber"
this will declare 3 different sort orders, by order number, order date as well as customer. The first two allow descending orders as well.
And last we set the default sort order to order number.
this now enables the client to send two additional query parameters
- order
- desc
for example
/api/v1/order?order=orderDate&desc=true
or with paging
/api/v1/order?order=orderDate&desc=true&page=10
Of course we also need to be able to select orders for example by date. Lets add some functionality to do just that.
First we modify the orderheader datadictionary to add the constraint logic
Object oOrderHeader_DD is a cOrderHeaderDataDictionary Set DDO_Server to oSalesPerson_DD Set DDO_Server to oCustomer_DD Property Date pdDateFrom "" Property Date pdDateTo "" Procedure OnConstrain If (pdDateFrom(Self)<>"") Constrain OrderHeader.Order_Date ge (pdDateFrom(Self)) If (pdDateTo(Self)<>"") Constrain OrderHeader.Order_Date le (pdDateTo(Self)) End_Procedure Procedure ClearConstraints Set pdDateFrom to "" Set pdDateTo to "" Send Rebuild_Constraints End_Procedure End_Object
now we add a new method for our order API
Procedure WebAPI_GetOrders Date dFrom dTo Get UrlParameter "dateFrom" to dFrom Get UrlParameter "dateTo" to dTo Set pdDateFrom of oOrderHeader_DD to dFrom Set pdDateTo of oOrderHeader_DD to dTo Send Rebuild_Constraints to oOrderHeader_DD // call original get API Send webAPI_Get Send ClearConstraints to oOrderHeader_DD End_Procedure
this new method gets the url parameters ‘dateFrom’ and ‘dateTo’ and uses these values to initialize the DDs constraints
then we simply call the original GET API to get the data and then clear the constraints
we need to modify the route declaration to call this new method
Send RegisterPath "GET" "" (RefProc(WebAPI_GetOrders))
this will now allow the user of the API to specify the dateFrom and dateTo parameters to constrain the orders returned.
Of course all these changes are also made to the OpenAPI documentation as well
Now as a last feature lets see how we can use a second schema in the same API to return the same dataset with a different schema
All we need to do is to declare a new route as follows
Send RegisterPath "GET" "/orderlist" (RefProc(webAPI_Get)) "orderlist"
as you can see in this route we are calling the same WebAPI_GET method but we are specifying a different schema called “orderlist”.
this will return the same dataset but with a much smaller number of fields.
In the following posts in this series we will look into detailed features such as authentication and more.