API and Provider methodology 
Tags: ruby, methodology
Published: 2018-05-29 11:55:40

---
title: API and Provider methodology 
published: true
description: A way of thinking to Keep your API and your implementation separate
tags: ruby, methodology
---
# Introduction

So, One of the biggest issues when designing a library/framework Is when you need to make a call to an external dependency. 

Specifically in the context of this post, when that dependency is no longer usable for any reason, what do you do? Most would then need to implement a new interface for a new dependency, and then as a result potentially make breaking changes to your API to accommodate which isn't good.

I bring this up because I see all to often libraries that directly call the external dependency in there API methods (I'm guilty of this too -_-), then have to completly change there API when the dependency changes that requires data to be structured differently. 

This then breaks things for many people.

This is why I advocate separating the API and the external calls into separate classes, it does add complexity and increases the amount of code but the advantage is that when you're external dependency changes, your API doesn't, and nor does it for anyone using you're libraries. 

When I think to do this (ahem) I like to separate the logic into:

+ API: The API of your library

+ Provider: The logic that calls your an external dependency

+ Formatter: If needed, the logic that handles data formatting between the API and the Provider

# Basic Provider Logic

Now you can do this any way you like, so long as there is a clear separation of concerns. Using ruby as an example, I like to take advantage of the fact you can define `def self.[]()` to make my provider API easy to use so I can do somthing like this:

```ruby
Module Providers
    class << self
        attr_writer :listing
        def [](provider)
            @listing[provider]       
        end
    end
    class Provider_Base
        def self.inherited(child, name = child.class.to_s.downcase.to_sym)
            # Normally I'd add logic to ensure that only this method can add to
            # `Providers.listing`, but I can't be arsed for this example
            Providers.listing[name] = child
        end
    end
end
```

The reason I do `name = child.class.to_s.downcase.to_sym` in the function declaration is so that if you want you can easily change the way the name is set by doing:

```ruby
Module Providers
    class OtherProviderBase < Provider_Base
        def self.inherited(child)
            super(child, :some_other_naming_mechaism)
        end
    end
end
```

Now you can inherit from `OtherProviderBase` instead.

# Using Your provider

Using the providers in you're api becomes super easy now:

```ruby
class API

    PROVIDER_NAME = :provider_name

    def some_method
        Providers[PROVIDER_NAME].some_method
    end

end
```

Why do it like this? Lets say you build a new dependency provider, you can just change the provider to this:

```ruby
class API

    PROVIDER_NAME = :other_provider_name

    def some_method
        Providers[PROVIDER_NAME].some_method
    end

end
```

End result is that the API doesn't change and won't break for you of your users.

And using the above providers example, you can add formatters like this:

```ruby
class API
    PROVIDER_NAME = :provider_name

    def some_method
        Formatters[PROVIDER_NAME].some_method(
            Providers[PROVIDER_NAME].some_method)
    end

end
```

You can even go further and do this:

```ruby
class API

    PROVIDER_NAME = :provider_name

    def some_method(*args)
        method = :some_method
        output = Providers[PROVIDER_NAME].send(method, (Formatters::Input[PROVIDER_NAME].send(method,*args))
        Formatters::Output[PROVIDER_NAME].send(method, output)
    end

end
```

# Provider Piplines

You could even provide a mechanism (where appropriate of course) to automatically pipeline, like this maybe:

```ruby
module Pipelines
    attr_reader :listing

    def pipline_for(action, *pipes)
        @listing[action] = pipes
        define_method(action, do) |*args|
            run_pipline_for(action, *args)
        end
    end
    
    def self.extended(child)
        child.include Instance_Methods
    end
    
    module Instance_Methods
       def run_pipline_for(action, *args)
           Pipelines.listing[action].inject(args) do |result, (item, custom_action)|
              item[PROVIDER_NAME].send(custom_action || action, *result)
           end
       end
    end
end


class API
    extend Pipeline

    PROVIDER_NAME = :provider_name

    pipline_for :action, Formatters::Input, [Providers, :get_remote_data], Formatters::Output
    pipline_for :other_action, Formatters::Input, Providers, [Processors, :differing_name], [Formatters::Output, :custom_output]
    
end
```

> Sorry, this probably out of scope for this post but couldn't help myself when I saw somthing interesting to code. Also I'm not sure if `PROVIDER_NAME` will be picked up in the local context of the `API` class when `Pipeline` is included so you might need to code a mechanism for setting and retrieval that does but you get the idea. 

# conclusion

By separating your external dependency into it's logic that is then called by your API, you can then keep your API constant between versions and then the only difference between versions becomes the dependencies, without any breaking changes between them.

p.s. I completly admit to not having checked or tested any of this code as it was just examples to get the ball rolling.