Skip to content

Wrap operation methods in specialized methods (1 success response, 1 content type) #145

@MahdiBM

Description

@MahdiBM

Here's an example of some code i'm repeating again and again in Penny:

func getFilesChanges() async throws -> [FileDiff] {
    let response = try await githubClient.pulls_list_files(.init(
        path: .init(...),
        body: .init(...)
    ))

    guard case let .ok(ok) = response,
            case let .json(json) = ok.body else {
        throw Errors.httpRequestFailed(response: response)
    }

    return json
}

I think this function should roughly look like this. optimally:

func getFilesChanges() async throws -> [FileDiff] {
    try await githubClient.pulls_list_files(
        path1: ...,
        path2: ...,
        body: .init(...)
    ).decode()
}

So let's analyze how the second function is better:

  • It's a single step so easier to use.
  • Cleaner, so nicer to read. Doesn't need weird case let or nested switch statements.
  • It is still what 99% of users want anyway.
  • It also decode() the response only after requested by user.
    • I prefer this as sometimes you don't need the response at all, but it's lower on the priority list.
  • The decode() function itself is supposed to throw a proper error if the response isn't a success response.
    • There can be another decodeError() function or the like to not check for success of the request considering one might be in fact trying to decode the error response.

What i mentioned above is basically what i've tried and implemented in DiscordBM, and i've really liked, which is achieved by:

  • A base HTTP-response type
  • Another HTTP-response type that wraps the base one.
    • Only thing extra it has is that it takes a generic parameter.
      • So it can automatically decode() the response to that type when needed.
    • This is purely for ease of usage by users. So they don't need to specify the decode type or make one.
  • Then the DiscordClient functions will return one of those types (for the most part), depending on if Discord's response is documented to have a body.

There are somethings worth noting:

  • One negative thing about this approach is that it requires a ton of work when done manually.
    • Luckily, this doesn't apply to this package as this a code-generation package.
  • Secondly, it might be too much too ask for this library.
    • It's not fair to compare it DiscordBM to this library as this library is supposed to implement the full scope of the OpenAPI spec.

I still think a lot of this is achievable in relatively short term, and almost all of it in long term.

Right now there is no way for one to make the decoding process easier for themselves.
For example if all json responses conformed to a single protocol, i could have at least set up some functions to ease my work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/generatorAffects: plugin, CLI, config file.kind/usabilityUsability of generated code, ergonomics.status/needs-designNeeds further discussion and a concrete proposal.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions