Wednesday, September 24, 2014

Microsoft Dynamics GP 2015 Developer's Preview: Working with Sample URIs - Part 2

In the part 1 video, I explained how to mount the Microsoft Dynamics GP 2015 Developer's Preview virtual hard disk using Hyper-V. My intent was to provide a part two showing how to mount the VHD file on Windows Azure, but realized it would take more time than I wanted to invest in really getting the point across on many of the aspects around the new service architecture components, so I have decided to forgo the Azure portion until some other day.

Today, I will focus on some of the sample service requests provided on the Developer's preview image, which can be found in the Example Service Requests.txt file available on the desktop of the image.

Before however, I wanted to touch base on REpresentational State Transfer (REST) services. REST, a term first coined by Roy Fielding (a principle author of the HTTP specification) in his doctoral dissertation, is an architectural style that treats networked application states and functionality as resources, which share a uniform interface. This architectural style differs in many ways from that of the Remote Procedure Call (RPC) architecture where services reside on the network and are invoked using request parameters and control data contained within messages.

Some of the basic principles governing REST services are:

  • Actors interact with resources, and resources are anything that can be named and represented. Each resource can be addressed via a unique Uniform Resource Identifier (URI).
  • Interaction with resources (located through their unique URIs) is accomplished using a uniform interface of the HTTP standard verbs (GET, POST, PUT, and DELETE). Also important in the interaction is the declaration of the resource's media type, which is designated using the HTTP Content-Type header. (XHTML, XML, JPG, PNG, and JSON are some well-known media types.)
  • Resources are self-descriptive. All the information necessary to process a request on a resource is contained inside the request itself (which allows services to be stateless).
  • Resources contain links to other resources (hyper-media).

While REST is defined by its author using strict architectural principles, the term is often used loosely to describe any simple URI-based request to a specific domain over HTTP without the use of an additional messaging layer such as Simple Object Access Protocol (SOAP). Implementations adhering to the strict principles of REST are often referred to as being “RESTful,” while those which follow a loose adherence are called “REST-Like”. Microsoft Dynamics GP Services can be considered REST-like (See Chapter 1: Microsoft Dynamics GP Service, page 3 of the Microsoft Dynamics GP Service Based Architecture Preview documentation).

A quick sample

As an example, imagine you need to build a service that interacts with the Microsoft Dynamics GP item master list: basically, a service that could produce the list of items and/or information about a specific item in the list, from a specific company database - in this case Fabrikam - and to be more precise, that company database resides within a specific tenant. Technically speaking, this service could also add or retrieve data for an item to and from the item master in Fabrikam, on the current tenant.

When building a REST-like service, you can must answer 3 basic questions:


  • What resources you are trying to define or expose
  • How are you going to represent the resources (URIs)
  • What actions are you going to support for each URI (HTTP verbs).


  • For our example, the resources will be defined by the hierarchy Tenants(Name:tenant_name)/Companies(company_name)/Items(item_number). The URIs are really dependent on where the service is going to be hosted, so for example, this could be in the form of http://somedomain.com:port_number/gpservice/ followed by the above hierarchy. The next thing in line is then to understand what HTTP verbs or actions are supported with each URI.

    Next, we need to determine the URIs for each resource. Right now we only need to determine the relative URIs since the absolute URI will be determined by where we host the service. The item master will be the root URI of the service (/). Using this syntax, /Items() will return all of items contained in the item master; /Items({ItemNumber}) will be the URI for each item within the item master.

    Under the current Developer's preview implementation, if you wanted to retrieve information about an item (HTTP GET), you would then use the following URI notation from your browser:

    http://localhost:8084/GPService/Tenants(Name=DefaultTenant)/Companies(Fabrikam,%20Inc.)/Items(2GPROC)

    By copy and pasting the above URL in the browser, the service call will generate a JavaScript Object Notation file (.json), as shown below:

    Items(2GPROC).json
    {
      "Status": {
        "CorrelationId": "d3056b1bb9d84775ad269abfa09cfa77",
        "Code": 200
      },
      "Payload": {
        "Trace": [],
        "ItemNumber": "2GPROC",
        "ItemDescription": "2 Ghz Processor",
        "NoteIndex": 333.0,
        "ItemShortName": "",
        "ItemType": "SalesInventory",
        "ItemGenericDescription": "",
        "StandardCost": 0.0,
        "CurrentCost": 250.0,
        "ItemShippingWeight": 0.0,
        "DecimalPlacesQTYS": "NotUsed",
        "DecimalPlacesCurrency": "One",
        "ItemTaxScheduleID": "",
        "TaxOptions": "Nontaxable",
        "IVIVIndex": 18,
        "IVIVOffsetIndex": 18,
        "IVCOGSIndex": 137,
        "IVSalesIndex": 112,
        "IVSalesDiscountsIndex": 128,
        "IVSalesReturnsIndex": 134,
        "IVInUseIndex": 0,
        "IVInServiceIndex": 141,
        "IVDamagedIndex": 141,
        "IVVariancesIndex": 783,
        "DropShipIndex": 445,
        "PurchasePriceVarianceIndex": 446,
        "UnrealizedPurchasePriceVarianceIndex": 446,
        "InventoryReturnsIndex": 450,
        "AssemblyVarianceIndex": 0,
        "ItemClassCode": "RM-ACT",
        "ItemTrackingOption": 1,
        "LotType": "",
        "KeepPeriodHistory": true,
        "KeepTrxHistory": true,
        "KeepCalendarHistory": true,
        "KeepDistributionHistory": true,
        "AllowBackOrders": true,
        "ValuationMethod": "FIFOPerpetual",
        "UOfMSchedule": "EACH",
        "AlternateItem1": "",
        "AlternateItem2": "",
        "MasterRecordType": 1,
        "ModifiedDate": "2017-05-21T00:00:00",
        "CreatedDate": "2017-05-21T00:00:00",
        "WarrantyDays": 0,
        "PriceLevel": "",
        "LocationCode": "",
        "PurchInflationIndex": 0,
        "PurchMonetaryCorrectionIndex": 0,
        "InventoryInflationIndex": 0,
        "InventoryMonetaryCorrectionIndex": 0,
        "COGSInflationIndex": 0,
        "COGSMonetaryCorrectionIndex": 0,
        "ItemCode": "",
        "TaxCommodityCode": "",
        "PriceGroup": "BUY",
        "PriceMethod": "CurrencyAmount",
        "PurchasingUOfM": "",
        "SellingUOfM": "",
        "KitCOGSAccountSource": "FromComponentItem",
        "LastGeneratedSerialNumber": "",
        "ABCCode": "B",
        "RevalueInventory": true,
        "TolerancePercentage": 0.0,
        "PurchaseItemTaxScheduleID": "",
        "PurchaseTaxOptions": "NonTaxable",
        "ItemPlanningType": "Normal",
        "StatisticalValuePercentage": 0.0,
        "CountryOrigin": "",
        "Inactive": false,
        "MinShelfLife1": 0,
        "MinShelfLife2": 0,
        "IncludeinDemandPlanning": false,
        "LotExpireWarning": true,
        "LotExpireWarningDays": 0,
        "LastGeneratedLotNumber": "",
        "LotSplitQuantity": 0.0,
        "UseQtyOverageTolerance": false,
        "UseQtyShortageTolerance": false,
        "QtyOverageTolerancePercentage": 0.0,
        "QtyShortageTolerancePercentage": 0.0,
        "IVSTDCostRevaluationIndex": 0,
        "UserCategoryValues1": "",
        "UserCategoryValues2": "",
        "UserCategoryValues3": "",
        "UserCategoryValues4": "",
        "UserCategoryValues5": "",
        "UserCategoryValues6": ""
      }
    }
    

    You can also retrieve an XML payload by specifying the extension in the URI, as follows:

    http://localhost:8084/GPService/Tenants(Name=DefaultTenant)/Companies(Fabrikam,%20Inc.)/Items(2GPROC).xml

    Here are other examples of URI notations to perform various service calls to retrieve data from Microsoft Dynamics GP, as provided in the Developer's preview:

    Checking the status of the GP Service.
    http://localhost:8084/GPService/Tenants(Name=DefaultTenant)/Companies(Fabrikam,%20Inc.)/Utility/Ping

    Obtaining help on supported HTTP verbs.
    http://localhost:8084/GPService/Tenants(Name=DefaultTenant)/Companies(Fabrikam,%20Inc.)/Utility/Help

    Retrieve information on customer AARONFIT0001 (Aaron Fitz Electrical).
    http://localhost:8084/GPService/Tenants(Name=DefaultTenant)/Companies(Fabrikam,%20Inc.)/Customers(AARONFIT0001)

    Retrieve information on customer COMPUTER0001(Computer World).
    http://localhost:8084/GPService/Tenants(Name=DefaultTenant)/Companies(Fabrikam,%20Inc.)/Customers(COMPUTER0001)

    Retrieve information on item number 100XLG.
    http://localhost:8084/GPService/Tenants(Name=DefaultTenant)/Companies(Fabrikam,%20Inc.)/Items(100XLG)

    Retrieve information on site 101G.
    http://localhost:8084/GPService/Tenants(Name=DefaultTenant)/Companies(Fabrikam,%20Inc.)/Sites(101G)

    Retrieve information on site 104G.
    http://localhost:8084/GPService/Tenants(Name=DefaultTenant)/Companies(Fabrikam,%20Inc.)/Sites(104G)

    Retrieve information on all companies under the current tenant.
    http://localhost:8084/GPService/Tenants(Name=DefaultTenant)/Companies(Fabrikam,%20Inc.)/Companies()

    Retrieve information about Fabrikam, Inc. under the current tenant.
    http://localhost:8084/GPService/Tenants(Name=DefaultTenant)/Companies(Fabrikam,%20Inc.)/Companies(TWO)

    I want to mention that there 2 HTML files provided with the preview, which contain JavaScript sample code showing how to access the Dynamics GP Service. These can be found under the Samples folder. The scripts show how to make use of the HTTP POST, HTTP PATCH, and HTTP DELETE actions to create a new, and update and delete an existing record in Microsoft Dynamics GP respectively.

    There's also a .NET sample application that show how to consume a GP Service as well. This sample can be loaded with Visual Studio in the Developer's Preview image.

    While this is all good, In my next article I will show how to build a Microsoft Dexterity-based service that can be consumed by other applications.

    Until next post!

    MG.-
    Mariano Gomez, MVP
    IntelligentPartnerships, LLC
    http://www.IntelligentPartnerships.com

    1 comment:

    Anonymous said...

    Hi,

    Is there any way to configure GP web services to use REST API's instead of the defaulted SOAP API's?

    Thanks