{"id":25478649,"url":"https://github.com/bastianrob/go-thennable","last_synced_at":"2025-11-06T12:30:28.791Z","repository":{"id":57518279,"uuid":"152578379","full_name":"bastianrob/go-thennable","owner":"bastianrob","description":null,"archived":false,"fork":false,"pushed_at":"2019-08-04T14:57:31.000Z","size":14,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2024-09-23T09:09:35.020Z","etag":null,"topics":["codeflow","error-handling","golang"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bastianrob.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-10-11T11:08:24.000Z","updated_at":"2019-07-15T09:58:30.000Z","dependencies_parsed_at":"2022-09-26T18:01:39.382Z","dependency_job_id":null,"html_url":"https://github.com/bastianrob/go-thennable","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bastianrob%2Fgo-thennable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bastianrob%2Fgo-thennable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bastianrob%2Fgo-thennable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bastianrob%2Fgo-thennable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bastianrob","download_url":"https://codeload.github.com/bastianrob/go-thennable/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239493707,"owners_count":19647995,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["codeflow","error-handling","golang"],"created_at":"2025-02-18T14:53:25.382Z","updated_at":"2025-11-06T12:30:28.689Z","avatar_url":"https://github.com/bastianrob.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# go-thennable\n\nWith this package, you can chain a series of functions to build a pipeline\n\n## Using thennable for error handling / control flow\n\nConsider the following example\n\n```go\nfunc main() {\n    resultOfDoingThis, err := DoThis()\n    if err != nil {\n        //log the error\n        return\n    }\n\n    resultOfDoingThat err := DoThat(resultOfDoingThis)\n    if err != nil {\n        //log the error\n        return\n    }\n\n    resultOfDoingAnother err := DoAnother(resultOfDoingThat)\n    if err != nil {\n        //log the error\n        return\n    }\n}\n```\n\nThe above example is the idiomatic way of error handling in go.\nSome like it, but most hate it because we need to manually check and return from error one by one.\n\nNow consider the following example using thennable\n\n```go\nfunc main() {\n    result, err := thennable.Start().\n        Then(DoThis).\n        Then(DoThat).\n        Then(DoAnother).\n        End()\n}\n```\n\nIn the above example, `err` will either be from `DoThis`, `DoThat`, or `DoAnother` function.\n\n* `DoThat` and `DoAnother` won't be executed if `DoThis` produce an error.\n* `DoAnother` won't be executed if `DoThat` produce an error.\n* Or you can bypass the error and keep running next function by setting `BreakOnError(true)` in the thennable pipeline. ()\n\nTo handle error can either write extra lines like:\n\n```go\n    if err != nil {\n        //log the error\n        return\n    }\n```\n\nor better yet, you can use the built in `Handle` function so the code will looks like:\n\n```go\nfunc GlobalErrorHandler(err error) {\n    log.Println(err)\n}\n\nfunc main() {\n    result, err := thennable.Start().\n        Then(DoThis).\n        Then(DoThat).\n        Then(DoAnother).\n        Handle(GlobalErrorHandler)\n        End()\n}\n```\n\n## Example 1\n\n```go\nimport (\n    \"fmt\"\n    thennable \"github.com/bastianrob/go-thennable\"\n)\n\nfunc AddOne(num int) (int, error) {\n    return num + 1, nil\n}\n\nfunc Decide(num int) (string, error) {\n    if num == 1 {\n        return \"one\", nil\n    else {\n        return \"not one\", nil\n    }\n}\n\nfunc main() {\n    result, err := thennable.Start(0). //start with zero\n        Then(AddOne). //0+1\n        Then(Decide). //1 = one\n        End()\n    str := result[0].(string)\n    fmt.Printf(\"Res: %v, Str: %s, Err: %v\", result, str, err)\n    //Res: [one], Str: one, Err: \u003cnil\u003e\n}\n```\n\n## Example 2: Inlining\n\n```go\nimport (\n    \"fmt\"\n    thennable \"github.com/bastianrob/go-thennable\"\n)\n\nfunc main() {\n    result, err := thennable.Start(1). //start with 1\n        Then(func (one int) (int, int, error) {\n            return one, 2, nil\n        }). //return 1, 2\n        Then(func (one, two int) (int, int, int, error) {\n            return one, two, 3, nil\n        }) //return 1, 2, 3\n        End()\n    fmt.Printf(\"Res: %v, Str: %s, Err: %v\", result, str, err)\n    //Res: [1 2 3], Err: \u003cnil\u003e\n}\n```\n\n## Example 3: Error Occurred\n\n```go\nimport (\n    \"fmt\"\n    \"errors\"\n    thennable \"github.com/bastianrob/go-thennable\"\n)\n\nfunc AddOne(num int) (int, error) {\n    return num + 1, nil\n}\n\nfunc main() {\n    result, err := thennable.Start(1). //start with 1\n        Then(AddOne). //1 + 1\n        Then(func (two int) (int, error) {\n            return two, errors.New(\"Whooops, something happened\")\n        }). //return 2, error\n        Then(AddOne). //skipped\n        Then(AddOne). //skipped\n        End()\n\n    fmt.Printf(\"Res: %v, Str: %s, Err: %v\", result, str, err)\n    //Res: [2], Err: Whooops, something happened\n}\n```\n\n## Example 4: Recover from error\n\n```go\nimport (\n    \"fmt\"\n    \"errors\"\n    thennable \"github.com/bastianrob/go-thennable\"\n)\n\nfunc AddOne(num int) (int, error) {\n    return num + 1, nil\n}\n\nfunc main() {\n    result, err := thennable.Start(1). //start with 1\n        BreakOnError(false). //Pipeline keeps going when error happens\n        Then(AddOne). //1 + 1\n        Then(func (two int) error {\n            return errors.New(\"Whooops, something happened\")\n        }).           //return error\n        Supply(8)      //resuply the pipeline with 8\n        Then(AddOne). //8 + 1\n        Then(AddOne). //9 + 1\n        End()\n\n    fmt.Printf(\"Res: %v, Str: %s, Err: %v\", result, str, err)\n    //Res: [10], Err: nil\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbastianrob%2Fgo-thennable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbastianrob%2Fgo-thennable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbastianrob%2Fgo-thennable/lists"}