question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Refactor Fuel to make it more extensible

See original GitHub issue

I really like Fuel but I think the existing design doesn’t allow for easy extension. Here’re some design suggestions that, IMO, will make the library a lot more user friendly and also reduce code. Thoughts?

  1. Users should be able to use any encoder, decoder, HTTP client they want using the builder pattern on Fuel, like so:
Fuel.builder.build() // creates Fuel with all default settings
Fuel.builder
  .encoder(FuelJacksonEncoder())
  .build() // creates Fuel with Jackson encoder and rest default
Fuel.builder
  .encoder(FuelJacksonEncoder())
  .client(FuelOkHttpClient())
  .build() // you get the idea

Each of the components FuelJacksonEncoder etc also follows the same builder pattern.

  1. Do away with the String.* extension methods. You always start with a Fuel instance as shown above, plain and simple.

  2. The Triple is kind of confusing, because the Result is sort of forced on the user. When I make a HTTP request, I expect a response, and thank you for also providing the request at the same time. If I didn’t ask you for a Result object, don’t force it on me.

fuel.get("http://httpbin.org/get")
  .response { request, response ->
    // response.body would be Array<Byte>
    // response.bodyAs<T> would use the decoder to convert to T, where T can be, but not limited to, InputStream
    // response.as<Result> would convert the response to a Result object provided result module is in compile scope. If not this code wouldn't compile.
  }
  1. Do away with responseString and responseJson as point 3 above is enough.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:2
  • Comments:11 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
SleeplessBytecommented, Oct 26, 2018
val manager = FuelManager()
manager.get("https://google.com").responseString()

Works now. Let’s close this and re-open separate tickets if we want to implement https://github.com/kittinunf/Fuel/issues/225#issuecomment-328327731

1reaction
yoavstcommented, Sep 10, 2017

My Idea:

FuelBuilder / FuelManager:

  • Internal configuration for request (same as now. but if you want to rename it I’m not against it).

Fuel class + Fuel companion object:

  • Class that internally calls FuelManager and provides more friendly API for request.
  • One can build Fuel instance from provided FuelManager.
  • For backward compatibility and for simple cases, Fuel has companion object: Fuel that has FuelManager mutable field. So you could just call Fuel.get(...) if you need only a single Fuel instance.
val fuel = Fuel.of(fuelManager)
fuel.get("https://google.com").responseString() // custom fuelManager
Fuel.get("https://google.com").responseString() // default/singleton fuelManager

Request + MutableRequest:

  • A Pojo class for creating a request.
  • Does not contain any implementation detail (like Future, SSLSocketFactory…).
  • Instead, FuelManager config (headers, parameters, ssl,…) will be injected on Client.
  • We do need to find a way to pass the configuration (FuelManager). Maybe will have a internal field with FuelManager instance, and a public method on Fuel class fun apply(request: Request): MutableRequest (which will replace the instance).
  • We can also provide MutableRequest interface which you receive from Fuel.method(...) and is mutable. the Request you receive from responseX {} is immutable.
  • All the mutating methods of MutableRequest will become extension methods, though they will still be the preferred way to mutate a request.
  • One can edit MutableRequest as builder:
MutableRequest.apply {
 url = "https://www.google.com"
 parameters += "hello" to "world"
 headers += "user-agent" to "Fuel"
}

Request flow:

  1. Create FuelManager instance.
  2. Create Fuel instance from (1).
  3. Call fuel.method() on (2) instance to get MutableRequest instance and mutate it.
  4. Call responseX() on (3) instance.
  5. A class will merge FuelManager instance (1) and the MutableRequest (3) to a single Request.
  6. The request instance (5) will be passed to Client of (1) for executing.

Javascript support #134: Now it will be really easy to support Javascript.

  1. Make FuelManager an header class.
  2. Provide different impl classes for each platform.
  3. Provide different default Client for each platform.
  4. Classes with JVM features like ResponseDeserializable can also be different on each platform. Environment can be changed from callbackExecutor: Executor to fun callCallback(callback).

Should work 👋

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to refactor this legacy code snippet to make it extensible?
First thing I consider is that it is quite feasible to write automated tests for it. You should definitely do it before you...
Read more >
Design Debt - C2 wiki
Of course, DesignDebt will increase if you do not refactor, until the cost of adding new features is greater than it would be...
Read more >
When should you not refactor? - Stack Overflow
Given code with no tests, you may refactor it to to make it more testable. ... have better flow, and are more extensible...
Read more >
Tips for avoiding refactoring paralysis? : r/SatisfactoryGame
Here's a tip for satisfactory and software development. Just work on the problem you actually have, not in problems you might have in...
Read more >
Test-driven development - IBM Garage Practices
Your specific code become more general. The unit tests provide a safety net which supports the refactoring, because they make sure that the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found