Hey there, fellow developers! I wanted to share an exciting journey I recently undertook to enhance my MVP app. As the first and only user, I discovered some important bugs and realized that I needed a more flexible approach to manage the data in my application.

One of the primary issues was related to mounting and demounting bike parts using the API. At first, I could only work with the current date, which was quite limiting. I needed the ability to configure my bike, which I’ve had for a while, without manually tinkering with the database. Fortunately, the solution turned out to be surprisingly simple: I needed to introduce new parameters into the component assignments API.

  1. Updating the Contract To get started, I made changes to the contract, which defines the parameters for the API:
module App
  module Contracts
    class ComponentAssignment < Dry::Validation::Contract
      params do
        required(:bike_id).filled(:integer)
        required(:component_id).filled(:integer)
        optional(:started_at).maybe(:date_time)
        optional(:ended_at).maybe(:date_time)
      end
    end
  end
end

The contract now includes the started_at and ended_at fields, which can be used for configuring bike components.

  1. Updating the Controller Next, I updated the controller to make use of these new parameters when creating a component assignment:
component = Repositories::ComponentAssignments.new.create(
    bike_id: component_data["bike_id"],
    component_id: component_data["component_id"],
    started_at: component_data["started_at"],
    ended_at: component_data["ended_at"]
)

This change allowed me to set the started_at and ended_at values directly in the API endpoint, eliminating the need for direct database manipulation.

  1. Updating the Repository To complete the process, I had to modify the repository to accommodate the new parameters:
module App
  module Repositories
    class RecordNotFound < StandardError
    end

    class ComponentAssignments
      def create(bike_id:, component_id:, started_at:, ended_at:)
        started_at = Time.now if started_at.blank()

        Records::ComponentAssignment.create(
          bike_id: bike_id,
          component_id: component_id,
          started_at: started_at,
          ended_at: ended_at
        )
      end

      def delete(bike_id:, component_id:, ended_at:)
        ended_at = Time now if ended_at.blank?
        assignment = Records::ComponentAssignment.find_by!(bike_id:, component_id:, ended_at: nil)
        assignment.update(ended_at: ended_at)
      rescue ActiveRecord::RecordNotFound
        raise RecordNotFound.new
      end
    end
  end
end

Now, the create method in the repository accepts the started_at and ended_at parameters and defaults to the current time when these fields are empty.

By implementing these changes, I transformed my MVP app into a more versatile tool that allows me to work with historical data in addition to the present. I can set started_at and ended_at directly in the API endpoint, avoiding direct database interactions on the server.

I hope my experience in improving my app’s API parameters inspires you to enhance your own projects. Code is on github. Stay curious, keep coding, and happy developing!