Skip to content

Instantly share code, notes, and snippets.

@nateklaiber
Last active August 29, 2015 14:01
Show Gist options
  • Select an option

  • Save nateklaiber/53c918b468ed1921a33b to your computer and use it in GitHub Desktop.

Select an option

Save nateklaiber/53c918b468ed1921a33b to your computer and use it in GitHub Desktop.

Revisions

  1. nateklaiber revised this gist May 28, 2014. 1 changed file with 9 additions and 0 deletions.
    9 changes: 9 additions & 0 deletions envelope_expansion_example.md
    Original file line number Diff line number Diff line change
    @@ -51,6 +51,15 @@ charge.customer

    With that last part, for the sake of consistency, I want to always return a `Stripe::Model::Customer` object. This means the `customer` method needs to know if it's expanded or not. If not, then it doesn't need to make an extra request. If only the ID is provided, it needs to lazy load the `Customer` via another API call.

    This way, a consumer of the client can safely call:

    ```ruby
    charge.customer.email
    charge.customer.account_balance
    ```

    They don't have to determine, from the outer scope, if they need to make a second request based on the value of `customer`.

    This is why I'd prefer a method of `customer_id` and `customer` as different envelopes. Stripe could have returned the nested object:

    ```json
  2. nateklaiber revised this gist May 28, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion envelope_expansion_example.md
    Original file line number Diff line number Diff line change
    @@ -22,7 +22,7 @@ connection = Stripe::Connection.new(configuration)

    # Make a request to the API. This is normally wrapped in a specific `Request` model.
    request_handler = Stripe::RequestHandler.new(connection)
    request = request.get(endpoint)
    request = request.get(charge_detail_url)

    # Retrieve the response body as JSON
    response = request.body
  3. nateklaiber revised this gist May 28, 2014. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions envelope_expansion_example.md
    Original file line number Diff line number Diff line change
    @@ -13,8 +13,9 @@ I'll use Stripe as an example. The client is responsible for:
    configuration = Stripe::Configuration.new(config_params_or_block)

    # Find the route I want to make the request against
    router = Stripe::Client.routes.route_for('charge-detail')
    endpoint = router.url_for(id: 'ch_1047M22eZvKYlo2CzsVZ0cX8')
    routes = Stripe::Client.routes
    charge_detail_route = routes.route_for('charge-detail')
    charge_detail_url = charge_detail.url_for(id: 'ch_1047M22eZvKYlo2CzsVZ0cX8')

    # Make a connection to the API
    connection = Stripe::Connection.new(configuration)
  4. nateklaiber created this gist May 28, 2014.
    67 changes: 67 additions & 0 deletions envelope_expansion_example.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,67 @@
    I'll use Stripe as an example. The client is responsible for:

    * Configuration
    * Routing
    * Connection Handling
    * Request Handling
    * Raw requests with JSON
    * Object model requests that wrap the raw request (allow us to say `Stripe::Request::Charge.get(id: 'sdfsdf')`)
    * Object Creation. This includes top level and associations.

    ```ruby
    # Configuration and setup
    configuration = Stripe::Configuration.new(config_params_or_block)

    # Find the route I want to make the request against
    router = Stripe::Client.routes.route_for('charge-detail')
    endpoint = router.url_for(id: 'ch_1047M22eZvKYlo2CzsVZ0cX8')

    # Make a connection to the API
    connection = Stripe::Connection.new(configuration)

    # Make a request to the API. This is normally wrapped in a specific `Request` model.
    request_handler = Stripe::RequestHandler.new(connection)
    request = request.get(endpoint)

    # Retrieve the response body as JSON
    response = request.body

    # Wrap in an object model
    charge = Stripe::Model::Charge.new(response)

    # Now we can interact with the model and it's attributes...

    charge.created
    # => 1401284558

    charge.paid
    # => true

    # Now, the `customer` is expandable. If it exists, then it's an `ID` by default. If expanded, then it's the full representation.

    # Without expansion.
    charge.customer
    # => 'cus_47Ltj7MTZguSEN'

    # With expansion. We wrap it in the `Customer` model.
    charge.customer
    # => Stripe::Model::Customer
    ```

    With that last part, for the sake of consistency, I want to always return a `Stripe::Model::Customer` object. This means the `customer` method needs to know if it's expanded or not. If not, then it doesn't need to make an extra request. If only the ID is provided, it needs to lazy load the `Customer` via another API call.

    This is why I'd prefer a method of `customer_id` and `customer` as different envelopes. Stripe could have returned the nested object:

    ```json
    {
    "customer": {
    "id": "cus_47Ltj7MTZguSEN"
    }
    }
    ```

    However, I am still left to inspect the object to determine if we have the _full_ object or only the `ID`.

    I am also open to there being better approaches. When I build API clients, I like to keep a clean separation of responsibilities without intermixing different aspects.

    Any feedback would be welcome.