Skip to Content

Introduction


As SAP customers, partners and consultants embark on their journey to designing and building your own Fiori style applications a major part of this journey will be building your own RESTful API’s using SAP Gateway ( OData services ).

I’m going to break down my learning and insights into SAP Gateway development into a series of blogs where I would like to cover the following topics:

  • Re-Use and Development Patterns
  • Encapsulation of Business Logic & Searching for Entities
  • Performance
  • eTags for concurrency control

Acknowledgement and Use Cases


The development patterns covered in this series are not originally mine.  If you look at the My Accounts Fiori application delivered by SAP in CRM (UICRM001), this pattern was written to support the OData service “CRM_BUPA_ODATA”.

Our colleagues who have put together this pattern probably don’t realise how much of a gem it has been for me to rapidly produce re-usable, nicely encapsulated entity implementations in SAP Gateway, so hats off to the folk who put a lot of thought and effort behind this.


You can consider this pattern when creating your own OData services in the customer namespace.  For modifying SAP delivered OData services you should always follow the SAP recommended approach and enhancement documentation.

Key Learnings from this article:

  • You need someone who understands how to build OData services in SAP Gateway they should know how to leverage re-use patterns to help accelerate UX development and multi-channel consumption.


  • You can build a generic template that seeds a base implementation for your concrete entities.


  • You can build a module specific abstract object where you can define re-usable functions on a module level (SD, MM, BP for example )


  • This is NOT the only way or the standard SAP way of building OData services, I just really like this pattern as it has served me enormously well on a large scale wall to wall Fiori project and I’m hoping to adopt it has a gold standard on future projects I work on and hope it helps you to accelerate your OData service development.

Putting the Pattern Together

First let’s cover our typical OData service from a high level and use a simple entity relationship model as an example ( Account or Business Partner with an Address association ):

/wp-content/uploads/2016/04/blog_image_923888.png

SEGW – Design Time.

Here we define our entities, attributes of those entities and association between them ( navigation path ).

In our example we want to look at two entities, Account and Address.  You can generate the entity with various methods but I like to generate new entities from a custom ABAP structure.

  • I like to start with a standard SAP structure as an Include ( BUT000 in this example )
  • I like to include the term “ODATA” in the naming convention to signify the structure is associated with a REST service that implies restricted use.

/wp-content/uploads/2016/04/blog_image_923888.png

DPC, DPC_EXT – Data Provider Classes


These are the classes that are generate from activating the OData service and where you have been told to implement you entity logic for CRUD functions.

I have a couple of rules around DPC_EXT:

  • Pass through implementation only for each entity CRUD function to an encapsulated class  
  • NO business logic in DPC, this should all be encapsulated in a concrete class
  • Function Imports should have their own API, in other words any implementation in EXECUTE_ACTION should be calling some API or utility type class.

Entity Implementation and Class Hierarchy


Most implementations I have seen have a loose encapsulation concept, in other words implementation in CRUD methods in the DPC_EXT class contain some business logic and other business logic is contained somewhere else.

I don’t like this as it becomes difficult to maintain and causes regression problems when new developers take over and add new features.

Instead we can use a nice class hierarchy that helps us encapsulate different business logic in layers. 

This is the current hierarchy I like:

/wp-content/uploads/2016/04/blog_image_923888.png

In context with our “Account” entity, this is what we would end up with:

/wp-content/uploads/2016/04/blog_image_923888.png

ZCL_ODATA_RT

This class provides a base line search for GET_ENTITYSET that handles skip / count / paging.  The base line search is based on a dyanmic SQL approach.  it also allows us to do eTag calculation across all out entities.  Apart from the Search pattern in this class, I only use it for Gateway framework type functions.

ZCL_ODATA_BP

I’ve called this a modular layer, we can encapsulate module specific functions.  In our use case for Accounts (Business Partner) we may have common functions such as add leading zeros to a BP number( internal / external display ) or functions that format the Business Partners full name that we can write once and call across any concrete class that belongs to our module.

ZC_ODATA_ACCOUNT

This is the concrete class, here you implement the CRUD functions GET_ENTITYSET, GET_ENTITY, UPDATE_ENTITY etc which are called from the corresponding methods in the actual DPC_EXT class of your service.  All entity specific business logic is maintained here.

Re-use of Entity Objects

Start thinking about the services you need to build.  Are there re-usable entities across these services? Let’s take a look at a one example.

Below is a diagram that shows two OData services:


  • My Accounts Service
  • My Sales Order Service

These two services share common entities:


  • Account
  • Address

In some implementations, I have seen the same code duplicated across different DPC_EXT classes for the same entity which doesn’t lend itself to good re-use patterns although there certainly may be a use case where this is necessary.


Here is what I mean about acceleration, once I have the Account and Address entity implementation up and running, tested and stable I can re-use these entities across new services I’m putting together.


The initial build is obviously the longest but scaffolding up a new service with the same entities then becomes considerably faster.

/wp-content/uploads/2016/04/blog_image_923888.png

Data Provider Class ( DPC_EXT )


To facilitate this pattern, we need to make some changes in our DPC_EXT. This allows us to access instantiated concrete classes at runtime.

First we need an attribute on our DPC_EXT class that holds the instances of each entity implementation:



/wp-content/uploads/2016/04/blog_image_923888.png

The structure of the table is:

/wp-content/uploads/2016/04/blog_image_923888.png

Now to instantiate our entity implementations, during the constructor call in the DPC_EXT class we instantiate each entity and store the instance, class name and entity name:

/wp-content/uploads/2016/04/blog_image_923888.png

Now we need to call our entity concrete class implementation. Here we assume the service has been generated and you have re-defined the relevant method.

/wp-content/uploads/2016/04/blog_image_923888.png

ZCL_ODATA_RT


We’ve mentioned this class called ZCL_ODATA_RT.  The purpose of this class is to provide:



  • Common search capability based on dynamic SQL.  This means when I implement an entity for the first time I can re-use this search pattern that allows me to process complex searches that handles a range of other functions like paging.  In a nutshell we have implemented a re-usable search feature once across all our entity implementations that we can tailor for each concrete class. 
  • I can place framework specific functions such as eTag HASH calculations that will work across all of my entities



Overview of Entity Search


The first thing we probably want to do in the Fiori application is search for an entity.  I usually start by building out the generic search pattern in ZCL_ODATA_RT that follows this basic flow:



/wp-content/uploads/2016/04/blog_image2_925587.png




NB: I don’t have to use this when setting up a new concrete class for the first time, I can redefine the GET_ENTITYSET method in the ZCL_ODATA_ACCOUNT and write other code to do the search for us.

Here is an overview of the logic of the GET_ENTITYSET method in ZCL_ODATA_RT:

1) Process paging, max hits and skip tokens.  This allows our dynamic SQL to retrieve our results based on certain filter parameters and then we have a generic paging pattern taken care for us. Think about the Master Object list in a Fiori app where you type in some search criteria and the OData call includes a “substring” filter.

/wp-content/uploads/2016/04/blog_image_923888.png

2) Generate a dynamic SQL statement.  This method contains the select, inner join, where statements.


/wp-content/uploads/2016/04/blog_image_923888.png


3) Apply additional filters.  Here I can read my entity filters passed by $filter and add additional criteria to our dynamic SQL

/wp-content/uploads/2016/04/blog_image_923888.png


4) Execute the dynamic SQL statement and page the results


/wp-content/uploads/2016/04/blog_image_923888.png

5) Enrich the data and return the result. This is where where you want to populate additional attributes of the entity that could not be retrieved during the dynamic SQL statement, thing such as texts or formatted names for example.

/wp-content/uploads/2016/04/blog_image_923888.png

Implementing the search in our concrete class

I now need to implement this in our concrete class.  When I have created our ZCL_ODATA_ACCOUNT class, I can then redefine the appropriate methods where I need to put my logic, this includes:


  • GENERATE_SELECT_FOR_ENTITYSET
  • ENRICH_WITH_USER_FILTER (not shown in our basic example below)
  • ENRICH_ENTITYSET_DATA

/wp-content/uploads/2016/04/blog_image_923888.png

Generate Select


In our generate select method, all we are doing is forming up the dynamic SQL, what attributes we want to select into our entity set.  We can also include joins here if we want to search across multiple tables.

/wp-content/uploads/2016/04/blog_image_923888.png

Enrich Entity Set Data


Before we pass the selected entity set records back to the odata framework we want to format and add additional things into the result.  Stuff like full name or texts.  In our example we’ve just formatted the full name of the business partner into the field FULL_NAME.


/wp-content/uploads/2016/04/blog_image_923888.png

We now have a concrete class implementation with an entity set search routine.



Implementing Other CRUD methods


We can then continue to implement the other CRUD functions by redefining the appropriate methods in our concrete class (ZCL_ODATA_ACCOUNT) and data provider class.


Let’s do an GET_ENTITY example.  Here is the re-definition in the DPC_EXT class:

/wp-content/uploads/2016/04/blog_image2_925587.png

And let’s put some logic in the ZCL_ODATA_ACCOUNT method GET_ENTITY:

/wp-content/uploads/2016/04/blog_image_923888.png

I won’t go through POST, DELETE, UPDATE this should provide enough foundation for how the pattern works and encapsulates our business logic nicely into a concrete object.

Summary

In this part of the series we’ve demonstrated that it is possible to build a re-use pattern that encapsulates our entity implementations cleanly and also include a powerful search feature that we can consume on demand if required without having to re-write the same functions more than once.

I hope you have found this blog useful and see you next time where when we cover some performance considerations for your OData services and e-tag handling for data concurrency control.


Stay tuned for updates as I prepare a set of video walkthroughs to augment the content outlined in part 1 of this series and to show more complex search patterns.


Thanks for stopping by.



Other Episodes in this series – Part 1.2 – Search patterns and service inclusion


Make your SAP Gateway Work Smarter not Harder – Part 1.2 ) Search Patterns and Service inclusion




Follow On Video 1)


Here is the ink to the first follow on video where I walk through some of the basics of the development pattern and add a new entity to the service.


Make Your SAP Gateway Work Smarter not Harder – Part 1 – YouTube

This is my first attempt at putting together one of these videos so please don’t be too harsh on production value 🙂

To report this post you need to login first.

21 Comments

You must be Logged on to comment or reply to a post.

  1. Simon Kemp

    Echoing Nigel’s sentiment above Leigh, this is great stuff. Can we ask you to come to the next SAP Tech Night in Sydney and present on this? 🙂

    (0) 
    1. Leigh Mason Post author

      Hi Simon, have been in contact with Graham Robinson, absolutely I’ll present on this.  Graham and I want to put several patterns up against each other, some don’t like the dynamic SQL part, that’s ok.. I’ll do a walk through on more complex search patterns and we’ll do a performance comparison.

      Just let us know when it is and I’ll probably head up with Chris Rae.

      (0) 
  2. Timothy Muchena

    Great article especially on the use of design patterns

    For someone who is just starting OData service development I feel that there are some grey areas. Maybe a simple step by step will do…maybe 🙂 . Just trying my luck

    Thanks

    (0) 
    1. Leigh Mason Post author

      Thanks Mr Eli,

      Yes there are many grey areas if you’re just starting out.  I should have prefaced the conversation by assuming the readers have at least seen or attended the GW100 course offered by SAP.  I have run this course in Australia, and whilst it provides an excellent overview of SAP Gateway and OData, the devil is in the detail always.

      I am putting together a series of videos that will augment this series showing you the development pattern in an live SAP Gateway which will help explain the concepts we’ve gone through here.

      Cheers

      Leigh.

      (0) 
  3. Jocelyn Dart

    Hi Leigh, Great work as always! Better yet – love to see these real-life experience learnings being shared.

    I’ve been hanging out for this one!  And also itching to see the OData etag handling approach.

    Cheers

    Jocelyn 

    (0) 
  4. Mike Doyle

    This looks like a great setup, Leigh.  I’ve tried to tackle the same issues, but your approach is very elegant.

    I think the two-level abstract classes (one generic, one module-specific) is spot on.  Lots of the common logic required is at the module level, in my experience.

    How do you implement GET_EXPANDED_ENTITY, GET_EXPANDED_ENTITYSET or CREATE_DEEP_ENTITY methods?  Do you just do that in the DPC_EXT, or do you add a method to one of the concrete classes?

    (0) 
    1. Leigh Mason Post author

      Hey Mike, these are very good questions, the create deep entity is handled in a different way but the expands actually fit nicely into this pattern as well.  I’ll include these examples for you in the next series.  In fact the expand works seamlessly anyway when you call a $expand in the OData URL.

      The next question is $batch, this also plays nicely with those use cases as well, obviously there are some gotchas etc that come down to each concrete entity implementation, but I’ve managed to do this with a “Deferred Processing” before where you have to implement the “CHANGESET_PROCESS” method with consideration to ETag handling.

      Will explore with you further for sure..

      cheers

      Leigh

      (0) 
    2. Leigh Mason Post author

      Hey Mike, these are very good questions, the create deep entity is handled in a different way but the expands actually fit nicely into this pattern as well.  I’ll include these examples for you in the next series.  In fact the expand works seamlessly anyway when you call a $expand in the OData URL.

      The next question is $batch, this also plays nicely with those use cases as well, obviously there are some gotchas etc that come down to each concrete entity implementation, but I’ve managed to do this with a “Deferred Processing” before where you have to implement the “CHANGESET_PROCESS” method with consideration to ETag handling.

      Will explore with you further for sure..

      cheers

      Leigh

      (0) 
  5. ' Pavan ' Golesar

    Hello Leigh,


    A nice one, Elaborating and collaborating all the IMP aspects of gateway,

    I also loved the way you tried to put encapsulation a key area to focus on while implementing CRUD operation which is actually true ➕


    Expect some Do”s & Don’t over the same to falicitate the quality of coding in in concreate classes.


    Cheers!


    –PG



    (0) 
    1. Leigh Mason Post author

      Hi Paven,

      Thanks for the nice comments, yes you’re 100% correct about the do’s and don’ts.  I think most of us when we approach this for the first time fall into some bad traps.  Off the top of my head.

      1) OData is a nice protocol, it does heaps of cool stuff for us.   I’ve seen object keys written to memory id’s because the developer doesn’t understand navigation paths correctly for example.

      2) Not understanding deep inserts and deferred change set processing, to be fair their is currently no support for Content ID referencing but I’ve seen all manner of dirty commits and “WAIT UP TO..” statements because of this.

      3) Basic OO, when an object is called “ZCL_ODATA_ACCOUNT” it shouldn’t contain business logic for some other process or object, oh I’ve seen this as well..

      4) Last but not least, thinking in entities rather than functions, I despise seeing other object attributes bound up into an other entity unless there is a solid use case for it, the only solid use case I’ve found is for a generic type inbox of business activities in CRM and even then I despise myself a little bit for it 🙂

      Encapsulation is the key for re-usability IMO, and I’ll definitely cover some do’s and don’t with my project experience.

      Thanks again for the comments.

      Leigh

      (0) 
    2. Leigh Mason Post author

      Hi Paven,

      Thanks for the nice comments, yes you’re 100% correct about the do’s and don’ts.  I think most of us when we approach this for the first time fall into some bad traps.  Off the top of my head.

      1) OData is a nice protocol, it does heaps of cool stuff for us.   I’ve seen object keys written to memory id’s because the developer doesn’t understand navigation paths correctly for example.

      2) Not understanding deep inserts and deferred change set processing, to be fair their is currently no support for Content ID referencing but I’ve seen all manner of dirty commits and “WAIT UP TO..” statements because of this.

      3) Basic OO, when an object is called “ZCL_ODATA_ACCOUNT” it shouldn’t contain business logic for some other process or object, oh I’ve seen this as well..

      4) Last but not least, thinking in entities rather than functions, I despise seeing other object attributes bound up into an other entity unless there is a solid use case for it, the only solid use case I’ve found is for a generic type inbox of business activities in CRM and even then I despise myself a little bit for it 🙂

      Encapsulation is the key for re-usability IMO, and I’ll definitely cover some do’s and don’t with my project experience.

      Thanks again for the comments.

      Leigh

      (0) 
  6. Andre Fischer

    Hi Leigh,

    I like this document very much and I am looking Forward to see the following blogs 🙂 .

    Your approach to make the development of OData Services reusalbe is very valuable.

    Nice that you mentioned the GW100 course to fill the grey areas 😉 and good to hear that you are teaching it.

    Best Regards,

    Andre

    (0) 
    1. Leigh Mason Post author

      Thank you Nabi, glad you enjoyed it..  Stay tuned for Part 1.2 which I’m about to publish regarding Search Patterns and Service Inclusion

      (0) 

Leave a Reply