2

Lets say I am building an application where clients can book bus tickets. The only thing they do is select, origin, destination and the type of service (express or standard). The system will then book the ticket against the right bus company api. The user does not need to chose service provider as it has already been negotiated by the hotel manager with the different bus companies.
The main purpose is to avoid changing existing code if a new hotel manager wants to add, remove or to change the bus company for a service provider.

For instance:

consumer: Hotel 1  
type of service: express  
service provider: Bus Co. A

consumer: Hotel 1   
type of service: standard  
service provider: Bus Co. B

consumer: Hotel 2  
type of service: express  
service provider: Bus Co. A

...

Each provider has its own API for booking and I need to generate the call and the payload in run time.

This is what I thought of doing:

OPTION 1 Store rest call details as a template in a database table as string with placeholders

contract (hotel name, type of service, api call url, payload)

Payload would be stored as text with placeholders.

Example:
contrat table info:

"Hilton New York", "express", "http://api.buscoA.com/book-ticket", "{origin:<origin>, destination:<destination>, service: expr}"
"Hilton New York", "standard", "http://api.busB.com/book", "{start:<origin>, end:<destination>, service_type: standard}"

OPTION 2 Store rest call details as a template in a database table and instantiate the rest call using a class through reflection

contract (hotel name, type of service, api call url, api class name)

And a class for each api will be created and I can instantiate and I can instantiate it through reflection using the table "class name" value

Example:

"Hilton New York", "express", "http://api.buscoA.com/book-ticket", "BusCompanyAApi"

Then I will have to create a class for each api and instantiate the object on demand by reflection using the class name stored in the database (BusCompanyAApi)

  • Is either option 1 or 2 a valid way to do this?
  • Is there a design pattern I could use?

NOTE: I am using java

masber
  • 327
  • 1
  • 5
  • 9
  • I think what I just answered is quite like what you are suggesting in Option 2. I like this. I suggest read up on Strategy Pattern or look at great tutorial video... – bcperth Aug 26 '18 at 02:28

3 Answers3

1

Why wouldn't you just use a map of service providers by name? It'd be like the command pattern:

HotelServices.get(serviceProviderName)
    .handleService(serviceName, consumer);
  • Yes, this seems a safer and more flexible approach than reflection ! Reflection would just create an unnecessary coupling between data and the code. A new developer could miss this external dependency and rename the class. And in order to avoid that a user enters a bad class name or that a hacker exploits this design, a sanitation of the input will be necessary (which will certainly require a list of allowed strings). By the way, I suppose that this answer proposes an alternative to @bcperth's one, isn't it ? – Christophe Aug 26 '18 at 10:24
1

Is this the right way to do this?

Its workable but you may end up with complicated code if the API's are too different and the response formats are quite different also.

Is there a design pattern I could use?

You could consider Strategy Pattern, that would allow you to abstract an interface for a generic provider, and implement details of request and response in concrete subclasses. Then you can add new services without disturbing your main code.

Can I use reflection to build the payload?

Reflection is a way to look at the details of classes and objects during run-time. However, in Java you can use reflection to instantiate providers according to the provider name read from the database. This is better than using switch/if-else statements and new operator against provider names. For example:

Object provider = Class.forName("ProviderA").newInstance();  
bcperth
  • 275
  • 1
  • 5
0

Design options

If all the provider APIs are very similar in nature and as simple as sending a couple of attributes to make the booking + parsing the response, then option 1 is certainly the way to go.

But if API could be very different and more complex (e.g. multi-step, with different kind of authentication, or using different communication protocols), you'd certainly have use a more elaborate approach. The idea would then be:

  • use an API specific builder to generate a set of API calls
  • the calls would be implemented using the command pattern and then let the final step of the builder invoke the commands in the right order.
  • Different APIs could require totally different command classes. You might therefore use the abstract factory pattern, to create families of related commands.

Alternatively, you could just imagine to use an existing service orchestration engine.

Reflection

Reflection is a very appealing design. But self-introspecting software is full of danger. I would recommend not to use it:

  • Reflection would create an unnecessary coupling between data and the code.
  • A new developer (or your future self in 5 years ?) could miss this external dependency and rename the class.
  • In order to avoid that a user enters a bad class name or that a hacker exploits this design to leak sensitive attributes in your cutstomer object (credit card number?), a sanitization of the data will anyway be necessary (at user entry or just in time before using the data).

The data validation required by reflection would anyway require a list of allowed strings. So why not just maintain this list in a map that could find an object able to create the right class or fill in the right attribute (probably using some variant of the command pattern) ?

IMHO, this map and command alternative would not be as awesome as reflection, but it would make your system more reliable.

Christophe
  • 74,672
  • 10
  • 115
  • 187