Question

TLDR: Writing a service (in the model layer). It talks to ffmpeg. Where should validation go? Should I create a service response object so it is testable? How should it be structured?

Background: I'm designing some classes to retrieve data from an external service. It could be an API, but in fact it's calls to ffmpeg cli, which in effect is an API to the conversion tools themselves.

When talking to an external service, where the data retrieved may not always be the same, how is it best to go about maintaining at least a consistent application state on your end so your application doesn't depend on the external service to work?

I have already separated out the classes thus far, trying to maintain SRP within them:

class CommandDispatcher { }

The Command Dispatcher's sole job is to make a request for data (to ffmpeg) and retrieve the response for that data back.

class Converter { }

The converter's sole responsibility is to take user requests (like convert 1 to 2), and send the basics to the command dispatcher which handles the exec() calls.

Here are my questions:

  • When talking to an external API / service, should I be creating an APIRequest and an APIResponse object (in this case an FFmpegResponse object)?

I have seen examples of this for OAuth, where there is an OAuth response object. However, that's simple enough because calls to this are done over the HTTP protocol which tends to give back at minimum an error code and a message. Calls to something like ffmpeg don't guarantee a similar response (ffmpeg may not be installed, for example). Is this object merely a domain object (i.e. an entity: some class members and setters and getters)?

  • Validation. If I am creating an FFmpegResponse object, whose job is it to put the data into the right members of the Response object?

Imagine ffmpeg isn't installed and the CommandDispatcher gets the response back empty. Is it up to the CommandDispatcher to then populate the FFmpegResponse object with an "ffmpeg not installed" error? Should I have a validation object do this?

Remember, I'm trying to stick to the Single Responsibility Principle here, so I'm thinking that the CommandDispatcher shouldn't care about whether the data is valid or not - it should merely ask for data and retrieve it. Where does my validation fit within the model layer for this service?

This isn't only for FFmpeg but will help for future external service calls. What is the best [practice] way to structure your code and classes to maintain SRP yet also a consistent application state regardless of whether or not the external service responds in an expected way?

Was it helpful?

Solution

In your current structure, CommandDispatcher should be either an interface or an abstract class (depending on the necessity of abstract code). You would then create a concrete implementation: FFMpegCommandDispatcher which would encapsulate the understanding of ffmpeg specific responses.

Response objects will then take on a similar structure: CommandResponse would be an abstraction with the concrete implementation FFMpegCommandResponse.

It would be best to create a set of common error conditions (serviceNotAvailable, serviceNotInstalled, serviceDiedAHorribleAndBloodyDeath, etc). Your dispatcher implementation can then set a common error code on the response object and provider implementation specific details. ('Error 1984: FFMpeg is watching you')

If you're concerned (and I would be) about validating input as well. You could create a CommandRequest abstraction, and FFMpegRequest implementation, that will take user input and make sure that it's okay to be sent to the command line.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top