From 6075488158fc1ea2db4bf1d280a3479ad916bd79 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Thu, 14 Sep 2023 11:36:02 -0500 Subject: [PATCH 1/8] feat: retry on 408 Request Timeout (#7) --- README.md | 4 ++-- internal/requestconfig/requestconfig.go | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e33e055..1466b15 100644 --- a/README.md +++ b/README.md @@ -233,8 +233,8 @@ client.HRIS.Directory.ListIndividuals( ## Retries Certain errors will be automatically retried 2 times by default, with a short exponential backoff. -Connection errors (for example, due to a network connectivity problem), 409 Conflict, 429 Rate Limit, -and >=500 Internal errors will all be retried by default. +Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, +429 Rate Limit, and >=500 Internal errors will all be retried by default. You can use the `WithMaxRetries` option to configure or disable this: diff --git a/internal/requestconfig/requestconfig.go b/internal/requestconfig/requestconfig.go index 8eeb5c3..db221a8 100644 --- a/internal/requestconfig/requestconfig.go +++ b/internal/requestconfig/requestconfig.go @@ -193,6 +193,7 @@ func (cfg *RequestConfig) Execute() error { } shouldRetry := err != nil || + res.StatusCode == http.StatusRequestTimeout || res.StatusCode == http.StatusConflict || res.StatusCode == http.StatusTooManyRequests || res.StatusCode >= http.StatusInternalServerError From 7107ce5b8411fa3b44c1de961ddaab4b8f17cf24 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Thu, 14 Sep 2023 18:17:04 -0400 Subject: [PATCH 2/8] fix(core): improve retry behavior and related docs (#9) --- README.md | 5 +- internal/requestconfig/requestconfig.go | 101 +++++++++++++++--------- 2 files changed, 66 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 1466b15..7de2ec6 100644 --- a/README.md +++ b/README.md @@ -202,7 +202,6 @@ if err != nil { if errors.As(err, &apierr) { println(string(apierr.DumpRequest(true))) // Prints the serialized HTTP request println(string(apierr.DumpResponse(true))) // Prints the serialized HTTP response - } panic(err.Error()) // GET "/employer/directory": 400 Bad Request { ... } } @@ -233,8 +232,8 @@ client.HRIS.Directory.ListIndividuals( ## Retries Certain errors will be automatically retried 2 times by default, with a short exponential backoff. -Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, -429 Rate Limit, and >=500 Internal errors will all be retried by default. +We retry by default all connection errors, 408 Request Timeout, 409 Conflict, 429 Rate Limit, +and >=500 Internal errors. You can use the `WithMaxRetries` option to configure or disable this: diff --git a/internal/requestconfig/requestconfig.go b/internal/requestconfig/requestconfig.go index db221a8..9780a19 100644 --- a/internal/requestconfig/requestconfig.go +++ b/internal/requestconfig/requestconfig.go @@ -6,6 +6,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "io" "math" @@ -158,18 +159,59 @@ func applyMiddleware(middleware middleware, next middlewareNext) middlewareNext } } -func (cfg *RequestConfig) Execute() error { - u, err := cfg.BaseURL.Parse(cfg.Request.URL.String()) +func shouldRetry(req *http.Request, res *http.Response) bool { + // If there is no way to recover the Body, then we shouldn't retry. + if req.Body != nil && req.GetBody == nil { + return false + } + + // If there is no response, that indicates that there is a connection error + // so we retry the request. + if res == nil { + return true + } + + // If the header explictly wants a retry behavior, respect that over the + // http status code. + if res.Header.Get("x-should-retry") == "true" { + return true + } + if res.Header.Get("x-should-retry") == "false" { + return false + } + + return res.StatusCode == http.StatusRequestTimeout || + res.StatusCode == http.StatusConflict || + res.StatusCode == http.StatusTooManyRequests || + res.StatusCode >= http.StatusInternalServerError +} + +func retryDelay(res *http.Response, retryCount int) time.Duration { + maxDelay := 5 * time.Second + delay := time.Duration(500 * float64(time.Millisecond) * math.Pow(2, float64(retryCount))) + if res != nil { + if parsed, err := strconv.ParseInt(res.Header.Get("Retry-After"), 10, 64); err == nil { + delay = time.Duration(parsed) * time.Second + } + } + if delay > maxDelay { + delay = maxDelay + } + jitter := rand.Int63n(int64(delay / 4)) + delay -= time.Duration(jitter) + return delay +} + +func (cfg *RequestConfig) Execute() (err error) { + cfg.Request.URL, err = cfg.BaseURL.Parse(cfg.Request.URL.String()) if err != nil { return err } - cfg.Request.URL = u if len(cfg.Buffer) != 0 && cfg.Request.Body == nil { - buf := bytes.NewReader(cfg.Buffer) cfg.Request.ContentLength = int64(len(cfg.Buffer)) - cfg.Request.Body = io.NopCloser(buf) cfg.Request.GetBody = func() (io.ReadCloser, error) { return io.NopCloser(bytes.NewReader(cfg.Buffer)), nil } + cfg.Request.Body, _ = cfg.Request.GetBody() } handler := cfg.HTTPClient.Do @@ -178,60 +220,45 @@ func (cfg *RequestConfig) Execute() error { } var res *http.Response - for i := 0; i <= cfg.MaxRetries; i += 1 { + for retryCount := 0; retryCount <= cfg.MaxRetries; retryCount += 1 { ctx := cfg.Request.Context() if cfg.RequestTimeout != time.Duration(0) { - nctx, cancel := context.WithTimeout(ctx, cfg.RequestTimeout) - ctx = nctx + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, cfg.RequestTimeout) defer cancel() } - req := cfg.Request.Clone(ctx) - res, err = handler(req) - if res == nil { - break - } - - shouldRetry := err != nil || - res.StatusCode == http.StatusRequestTimeout || - res.StatusCode == http.StatusConflict || - res.StatusCode == http.StatusTooManyRequests || - res.StatusCode >= http.StatusInternalServerError - - if res.Header.Get("x-should-retry") == "true" { - shouldRetry = true - } - if res.Header.Get("x-should-retry") == "false" { - shouldRetry = false + res, err = handler(cfg.Request.Clone(ctx)) + if errors.Is(err, context.Canceled) { + return err } - - if !shouldRetry || i >= cfg.MaxRetries { + if !shouldRetry(cfg.Request, res) || retryCount >= cfg.MaxRetries { break } - duration := time.Duration(500) * time.Millisecond * time.Duration(math.Exp(float64(i))) - if res != nil { - if parsed, err := strconv.ParseInt(res.Header.Get("Retry-After"), 10, 64); err == nil { - duration = time.Duration(parsed) * time.Second + // Prepare next request and wait for the retry delay + if cfg.Request.GetBody != nil { + cfg.Request.Body, err = cfg.Request.GetBody() + if err != nil { + return err } } - if duration > time.Duration(60)*time.Second { - duration = time.Duration(60) * time.Second - } - duration += time.Millisecond * time.Duration(-500+rand.Intn(1000)) - time.Sleep(duration) + + time.Sleep(retryDelay(res, retryCount)) } if err != nil { return err } - if res.StatusCode > 399 { + if res.StatusCode >= 400 { aerr := apierror.Error{Request: cfg.Request, Response: res, StatusCode: res.StatusCode} contents, err := io.ReadAll(res.Body) if err != nil { return err } + // If there is an APIError, re-populate the response body so that debugging + // utilities can conveniently dump the response without issue. res.Body = io.NopCloser(bytes.NewBuffer(contents)) err = aerr.UnmarshalJSON(contents) if err != nil { From 8e523098c127dda02f817677a114494fb7138367 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Fri, 15 Sep 2023 06:16:36 -0400 Subject: [PATCH 3/8] ci: configure release PR title (#10) --- release-please-config.json | 1 + 1 file changed, 1 insertion(+) diff --git a/release-please-config.json b/release-please-config.json index 5ab1370..7646ec7 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -8,6 +8,7 @@ "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "pull-request-header": "Automated Release PR", + "pull-request-title-pattern": "release: ${version}", "changelog-sections": [ { "type": "feat", From 90608ab0829df1b246b8c24cedda95a1572c8f62 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Fri, 15 Sep 2023 08:07:36 -0400 Subject: [PATCH 4/8] ci: fix handle-release-pr-title-edit workflow (#11) --- .github/workflows/handle-release-pr-title-edit.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/handle-release-pr-title-edit.yml b/.github/workflows/handle-release-pr-title-edit.yml index a7ad17c..9f3a7d6 100644 --- a/.github/workflows/handle-release-pr-title-edit.yml +++ b/.github/workflows/handle-release-pr-title-edit.yml @@ -9,8 +9,8 @@ jobs: update_pr_content: name: Update pull request content if: | - (github.event.type == 'edited' && github.event.changes.title.from != github.event.pull_request.title) || - (github.event.type == 'unlabeled' && github.event.label.name == 'autorelease: custom version') && + (github.event.action == 'edited' && github.event.changes.title.from != github.event.pull_request.title) || + (github.event.action == 'unlabeled' && github.event.label.name == 'autorelease: custom version') && github.event.pull_request.state == 'open' && github.event.sender.login != 'stainless-bot' && github.repository == 'Finch-API/finch-api-go' From 213405d52af5efd4593568a245ba27432e820033 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Tue, 19 Sep 2023 15:58:22 -0400 Subject: [PATCH 5/8] chore(api): remove deprecated & unused ATS API (#12) --- .stats.yml | 2 +- README.md | 18 +-- api.md | 56 -------- ats.go | 34 ----- atsapplication.go | 217 ------------------------------ atsapplication_test.go | 52 -------- atscandidate.go | 244 ---------------------------------- atscandidate_test.go | 52 -------- atsjob.go | 276 --------------------------------------- atsjob_test.go | 52 -------- atsoffer.go | 212 ------------------------------ atsoffer_test.go | 52 -------- atsstage.go | 81 ------------ atsstage_test.go | 31 ----- client.go | 2 - client_test.go | 4 +- paginationauto_test.go | 6 +- paginationmanual_test.go | 10 +- usage_test.go | 4 +- 19 files changed, 22 insertions(+), 1383 deletions(-) delete mode 100644 ats.go delete mode 100644 atsapplication.go delete mode 100644 atsapplication_test.go delete mode 100644 atscandidate.go delete mode 100644 atscandidate_test.go delete mode 100644 atsjob.go delete mode 100644 atsjob_test.go delete mode 100644 atsoffer.go delete mode 100644 atsoffer_test.go delete mode 100644 atsstage.go delete mode 100644 atsstage_test.go diff --git a/.stats.yml b/.stats.yml index d8ad62f..2d2fedb 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1 @@ -configured_endpoints: 27 +configured_endpoints: 18 diff --git a/README.md b/README.md index 7de2ec6..fd34832 100644 --- a/README.md +++ b/README.md @@ -49,11 +49,11 @@ func main() { client := finchgo.NewClient( option.WithAccessToken("my access token"), ) - candidate, err := client.ATS.Candidates.Get(context.TODO(), "") + page, err := client.HRIS.Directory.ListIndividuals(context.TODO(), finchgo.HRISDirectoryListIndividualsParams{}) if err != nil { panic(err.Error()) } - fmt.Printf("%+v\n", candidate.FirstName) + fmt.Printf("%+v\n", page) } ``` @@ -142,7 +142,7 @@ client := finchgo.NewClient( option.WithHeader("X-Some-Header", "custom_header_info"), ) -client.ATS.Candidates.Get(context.TODO(), ..., +client.HRIS.Directory.ListIndividuals(context.TODO(), ..., // Override the header option.WithHeader("X-Some-Header", "some_other_custom_header_info"), // Add an undocumented field to the request body, using sjson syntax @@ -159,11 +159,11 @@ This library provides some conveniences for working with paginated list endpoint You can use `.ListAutoPaging()` methods to iterate through items across all pages: ```go -iter := client.ATS.Jobs.ListAutoPaging(context.TODO(), finchgo.ATSJobListParams{}) +iter := client.HRIS.Directory.ListIndividualsAutoPaging(context.TODO(), finchgo.HRISDirectoryListIndividualsParams{}) // Automatically fetches more pages as needed. for iter.Next() { - job := iter.Current() - fmt.Printf("%+v\n", job) + directory := iter.Current() + fmt.Printf("%+v\n", directory) } if err := iter.Err(); err != nil { panic(err.Error()) @@ -174,10 +174,10 @@ Or you can use simple `.List()` methods to fetch a single page and receive a sta with additional helper methods like `.GetNextPage()`, e.g.: ```go -page, err := client.ATS.Jobs.List(context.TODO(), finchgo.ATSJobListParams{}) +page, err := client.HRIS.Directory.ListIndividuals(context.TODO(), finchgo.HRISDirectoryListIndividualsParams{}) for page != nil { - for _, job := range page.Jobs { - fmt.Printf("%+v\n", job) + for _, directory := range page.Individuals { + fmt.Printf("%+v\n", directory) } page, err = page.GetNextPage() } diff --git a/api.md b/api.md index f595eb0..aabcd9b 100644 --- a/api.md +++ b/api.md @@ -112,62 +112,6 @@ Methods: - client.HRIS.Benefits.Individuals.GetManyBenefits(ctx context.Context, benefitID string, query finchgo.HRISBenefitIndividualGetManyBenefitsParams) (finchgo.SinglePage[finchgo.IndividualBenefit], error) - client.HRIS.Benefits.Individuals.UnenrollMany(ctx context.Context, benefitID string, body finchgo.HRISBenefitIndividualUnenrollManyParams) (finchgo.SinglePage[finchgo.UnenrolledIndividual], error) -# ATS - -## Candidates - -Response Types: - -- finchgo.Candidate - -Methods: - -- client.ATS.Candidates.Get(ctx context.Context, candidateID string) (finchgo.Candidate, error) -- client.ATS.Candidates.List(ctx context.Context, query finchgo.ATSCandidateListParams) (finchgo.CandidatesPage, error) - -## Applications - -Response Types: - -- finchgo.Application - -Methods: - -- client.ATS.Applications.Get(ctx context.Context, applicationID string) (finchgo.Application, error) -- client.ATS.Applications.List(ctx context.Context, query finchgo.ATSApplicationListParams) (finchgo.ApplicationsPage, error) - -## Stages - -Response Types: - -- finchgo.Stage - -Methods: - -- client.ATS.Stages.List(ctx context.Context) (finchgo.SinglePage[finchgo.Stage], error) - -## Jobs - -Response Types: - -- finchgo.Job - -Methods: - -- client.ATS.Jobs.Get(ctx context.Context, jobID string) (finchgo.Job, error) -- client.ATS.Jobs.List(ctx context.Context, query finchgo.ATSJobListParams) (finchgo.JobsPage, error) - -## Offers - -Response Types: - -- finchgo.Offer - -Methods: - -- client.ATS.Offers.Get(ctx context.Context, offerID string) (finchgo.Offer, error) -- client.ATS.Offers.List(ctx context.Context, query finchgo.ATSOfferListParams) (finchgo.OffersPage, error) - # Providers Response Types: diff --git a/ats.go b/ats.go deleted file mode 100644 index 15ee704..0000000 --- a/ats.go +++ /dev/null @@ -1,34 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package finchgo - -import ( - "github.com/Finch-API/finch-api-go/option" -) - -// ATSService contains methods and other services that help with interacting with -// the Finch API. Note, unlike clients, this service does not read variables from -// the environment automatically. You should not instantiate this service directly, -// and instead use the [NewATSService] method instead. -type ATSService struct { - Options []option.RequestOption - Candidates *ATSCandidateService - Applications *ATSApplicationService - Stages *ATSStageService - Jobs *ATSJobService - Offers *ATSOfferService -} - -// NewATSService generates a new service that applies the given options to each -// request. These options are applied after the parent client's options (if there -// is one), and before any request-specific options. -func NewATSService(opts ...option.RequestOption) (r *ATSService) { - r = &ATSService{} - r.Options = opts - r.Candidates = NewATSCandidateService(opts...) - r.Applications = NewATSApplicationService(opts...) - r.Stages = NewATSStageService(opts...) - r.Jobs = NewATSJobService(opts...) - r.Offers = NewATSOfferService(opts...) - return -} diff --git a/atsapplication.go b/atsapplication.go deleted file mode 100644 index 48b05f9..0000000 --- a/atsapplication.go +++ /dev/null @@ -1,217 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package finchgo - -import ( - "context" - "fmt" - "net/http" - "net/url" - "time" - - "github.com/Finch-API/finch-api-go/internal/apijson" - "github.com/Finch-API/finch-api-go/internal/apiquery" - "github.com/Finch-API/finch-api-go/internal/param" - "github.com/Finch-API/finch-api-go/internal/requestconfig" - "github.com/Finch-API/finch-api-go/option" -) - -// ATSApplicationService contains methods and other services that help with -// interacting with the Finch API. Note, unlike clients, this service does not read -// variables from the environment automatically. You should not instantiate this -// service directly, and instead use the [NewATSApplicationService] method instead. -type ATSApplicationService struct { - Options []option.RequestOption -} - -// NewATSApplicationService generates a new service that applies the given options -// to each request. These options are applied after the parent client's options (if -// there is one), and before any request-specific options. -func NewATSApplicationService(opts ...option.RequestOption) (r *ATSApplicationService) { - r = &ATSApplicationService{} - r.Options = opts - return -} - -// Gets an application from an organization. -func (r *ATSApplicationService) Get(ctx context.Context, applicationID string, opts ...option.RequestOption) (res *Application, err error) { - opts = append(r.Options[:], opts...) - path := fmt.Sprintf("ats/applications/%s", applicationID) - err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return -} - -// Gets all of an organization's applications. -func (r *ATSApplicationService) List(ctx context.Context, query ATSApplicationListParams, opts ...option.RequestOption) (res *ApplicationsPage, err error) { - var raw *http.Response - opts = append(r.Options, opts...) - opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...) - path := "ats/applications" - cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, query, &res, opts...) - if err != nil { - return nil, err - } - err = cfg.Execute() - if err != nil { - return nil, err - } - res.SetPageConfig(cfg, raw) - return res, nil -} - -// Gets all of an organization's applications. -func (r *ATSApplicationService) ListAutoPaging(ctx context.Context, query ATSApplicationListParams, opts ...option.RequestOption) *ApplicationsPageAutoPager { - return NewApplicationsPageAutoPager(r.List(ctx, query, opts...)) -} - -type ApplicationsPage struct { - Applications []Application `json:"applications,required"` - Paging Paging `json:"paging,required"` - JSON applicationsPageJSON - cfg *requestconfig.RequestConfig - res *http.Response -} - -// applicationsPageJSON contains the JSON metadata for the struct -// [ApplicationsPage] -type applicationsPageJSON struct { - Applications apijson.Field - Paging apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *ApplicationsPage) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -// NextPage returns the next page as defined by this pagination style. When there -// is no next page, this function will return a 'nil' for the page value, but will -// not return an error -func (r *ApplicationsPage) GetNextPage() (res *ApplicationsPage, err error) { - // This page represents a response that isn't actually paginated at the API level - // so there will never be a next page. - cfg := (*requestconfig.RequestConfig)(nil) - if cfg == nil { - return nil, nil - } - var raw *http.Response - cfg.ResponseInto = &raw - cfg.ResponseBodyInto = &res - err = cfg.Execute() - if err != nil { - return nil, err - } - res.SetPageConfig(cfg, raw) - return res, nil -} - -func (r *ApplicationsPage) SetPageConfig(cfg *requestconfig.RequestConfig, res *http.Response) { - r.cfg = cfg - r.res = res -} - -type ApplicationsPageAutoPager struct { - page *ApplicationsPage - cur Application - idx int - run int - err error -} - -func NewApplicationsPageAutoPager(page *ApplicationsPage, err error) *ApplicationsPageAutoPager { - return &ApplicationsPageAutoPager{ - page: page, - err: err, - } -} - -func (r *ApplicationsPageAutoPager) Next() bool { - if r.page == nil || len(r.page.Applications) == 0 { - return false - } - if r.idx >= len(r.page.Applications) { - r.idx = 0 - r.page, r.err = r.page.GetNextPage() - if r.err != nil || r.page == nil { - return false - } - } - r.cur = r.page.Applications[r.idx] - r.run += 1 - r.idx += 1 - return true -} - -func (r *ApplicationsPageAutoPager) Current() Application { - return r.cur -} - -func (r *ApplicationsPageAutoPager) Err() error { - return r.err -} - -func (r *ApplicationsPageAutoPager) Index() int { - return r.run -} - -type Application struct { - ID string `json:"id,required" format:"uuid"` - CandidateID string `json:"candidate_id,required" format:"uuid"` - JobID string `json:"job_id,required" format:"uuid"` - OfferID string `json:"offer_id,required,nullable" format:"uuid"` - RejectedAt time.Time `json:"rejected_at,required,nullable" format:"date-time"` - RejectedReason ApplicationRejectedReason `json:"rejected_reason,required,nullable"` - Stage Stage `json:"stage,required,nullable"` - JSON applicationJSON -} - -// applicationJSON contains the JSON metadata for the struct [Application] -type applicationJSON struct { - ID apijson.Field - CandidateID apijson.Field - JobID apijson.Field - OfferID apijson.Field - RejectedAt apijson.Field - RejectedReason apijson.Field - Stage apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *Application) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -type ApplicationRejectedReason struct { - Text string `json:"text,nullable"` - JSON applicationRejectedReasonJSON -} - -// applicationRejectedReasonJSON contains the JSON metadata for the struct -// [ApplicationRejectedReason] -type applicationRejectedReasonJSON struct { - Text apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *ApplicationRejectedReason) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -type ATSApplicationListParams struct { - // Number of applications to return (defaults to all) - Limit param.Field[int64] `query:"limit"` - // Index to start from (defaults to 0) - Offset param.Field[int64] `query:"offset"` -} - -// URLQuery serializes [ATSApplicationListParams]'s query parameters as -// `url.Values`. -func (r ATSApplicationListParams) URLQuery() (v url.Values) { - return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ - ArrayFormat: apiquery.ArrayQueryFormatComma, - NestedFormat: apiquery.NestedQueryFormatBrackets, - }) -} diff --git a/atsapplication_test.go b/atsapplication_test.go deleted file mode 100644 index d44c71e..0000000 --- a/atsapplication_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package finchgo_test - -import ( - "context" - "errors" - "testing" - - finchgo "github.com/Finch-API/finch-api-go" - "github.com/Finch-API/finch-api-go/internal/testutil" - "github.com/Finch-API/finch-api-go/option" -) - -func TestATSApplicationGet(t *testing.T) { - if !testutil.CheckTestServer(t) { - return - } - client := finchgo.NewClient( - option.WithBaseURL("http://127.0.0.1:4010"), - option.WithAccessToken("AccessToken"), - ) - _, err := client.ATS.Applications.Get(context.TODO(), "string") - if err != nil { - var apierr *finchgo.Error - if errors.As(err, &apierr) { - t.Log(string(apierr.DumpRequest(true))) - } - t.Fatalf("err should be nil: %s", err.Error()) - } -} - -func TestATSApplicationListWithOptionalParams(t *testing.T) { - if !testutil.CheckTestServer(t) { - return - } - client := finchgo.NewClient( - option.WithBaseURL("http://127.0.0.1:4010"), - option.WithAccessToken("AccessToken"), - ) - _, err := client.ATS.Applications.List(context.TODO(), finchgo.ATSApplicationListParams{ - Limit: finchgo.F(int64(0)), - Offset: finchgo.F(int64(0)), - }) - if err != nil { - var apierr *finchgo.Error - if errors.As(err, &apierr) { - t.Log(string(apierr.DumpRequest(true))) - } - t.Fatalf("err should be nil: %s", err.Error()) - } -} diff --git a/atscandidate.go b/atscandidate.go deleted file mode 100644 index 078f5c8..0000000 --- a/atscandidate.go +++ /dev/null @@ -1,244 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package finchgo - -import ( - "context" - "fmt" - "net/http" - "net/url" - "time" - - "github.com/Finch-API/finch-api-go/internal/apijson" - "github.com/Finch-API/finch-api-go/internal/apiquery" - "github.com/Finch-API/finch-api-go/internal/param" - "github.com/Finch-API/finch-api-go/internal/requestconfig" - "github.com/Finch-API/finch-api-go/option" -) - -// ATSCandidateService contains methods and other services that help with -// interacting with the Finch API. Note, unlike clients, this service does not read -// variables from the environment automatically. You should not instantiate this -// service directly, and instead use the [NewATSCandidateService] method instead. -type ATSCandidateService struct { - Options []option.RequestOption -} - -// NewATSCandidateService generates a new service that applies the given options to -// each request. These options are applied after the parent client's options (if -// there is one), and before any request-specific options. -func NewATSCandidateService(opts ...option.RequestOption) (r *ATSCandidateService) { - r = &ATSCandidateService{} - r.Options = opts - return -} - -// Gets a candidate from an organization. A candidate represents an individual -// associated with one or more applications. -func (r *ATSCandidateService) Get(ctx context.Context, candidateID string, opts ...option.RequestOption) (res *Candidate, err error) { - opts = append(r.Options[:], opts...) - path := fmt.Sprintf("ats/candidates/%s", candidateID) - err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return -} - -// Gets all of an organization's candidates. A candidate represents an individual -// associated with one or more applications. -func (r *ATSCandidateService) List(ctx context.Context, query ATSCandidateListParams, opts ...option.RequestOption) (res *CandidatesPage, err error) { - var raw *http.Response - opts = append(r.Options, opts...) - opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...) - path := "ats/candidates" - cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, query, &res, opts...) - if err != nil { - return nil, err - } - err = cfg.Execute() - if err != nil { - return nil, err - } - res.SetPageConfig(cfg, raw) - return res, nil -} - -// Gets all of an organization's candidates. A candidate represents an individual -// associated with one or more applications. -func (r *ATSCandidateService) ListAutoPaging(ctx context.Context, query ATSCandidateListParams, opts ...option.RequestOption) *CandidatesPageAutoPager { - return NewCandidatesPageAutoPager(r.List(ctx, query, opts...)) -} - -type CandidatesPage struct { - Candidates []Candidate `json:"candidates,required"` - Paging Paging `json:"paging,required"` - JSON candidatesPageJSON - cfg *requestconfig.RequestConfig - res *http.Response -} - -// candidatesPageJSON contains the JSON metadata for the struct [CandidatesPage] -type candidatesPageJSON struct { - Candidates apijson.Field - Paging apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *CandidatesPage) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -// NextPage returns the next page as defined by this pagination style. When there -// is no next page, this function will return a 'nil' for the page value, but will -// not return an error -func (r *CandidatesPage) GetNextPage() (res *CandidatesPage, err error) { - // This page represents a response that isn't actually paginated at the API level - // so there will never be a next page. - cfg := (*requestconfig.RequestConfig)(nil) - if cfg == nil { - return nil, nil - } - var raw *http.Response - cfg.ResponseInto = &raw - cfg.ResponseBodyInto = &res - err = cfg.Execute() - if err != nil { - return nil, err - } - res.SetPageConfig(cfg, raw) - return res, nil -} - -func (r *CandidatesPage) SetPageConfig(cfg *requestconfig.RequestConfig, res *http.Response) { - r.cfg = cfg - r.res = res -} - -type CandidatesPageAutoPager struct { - page *CandidatesPage - cur Candidate - idx int - run int - err error -} - -func NewCandidatesPageAutoPager(page *CandidatesPage, err error) *CandidatesPageAutoPager { - return &CandidatesPageAutoPager{ - page: page, - err: err, - } -} - -func (r *CandidatesPageAutoPager) Next() bool { - if r.page == nil || len(r.page.Candidates) == 0 { - return false - } - if r.idx >= len(r.page.Candidates) { - r.idx = 0 - r.page, r.err = r.page.GetNextPage() - if r.err != nil || r.page == nil { - return false - } - } - r.cur = r.page.Candidates[r.idx] - r.run += 1 - r.idx += 1 - return true -} - -func (r *CandidatesPageAutoPager) Current() Candidate { - return r.cur -} - -func (r *CandidatesPageAutoPager) Err() error { - return r.err -} - -func (r *CandidatesPageAutoPager) Index() int { - return r.run -} - -// A candidate represents an individual associated with one or more applications. -type Candidate struct { - ID string `json:"id,required"` - // Array of Finch uuids corresponding to `application`s for this individual - ApplicationIDs []string `json:"application_ids,required"` - CreatedAt time.Time `json:"created_at,required" format:"date-time"` - Emails []CandidateEmail `json:"emails,required"` - FirstName string `json:"first_name,required,nullable"` - FullName string `json:"full_name,required,nullable"` - LastActivityAt time.Time `json:"last_activity_at,required" format:"date-time"` - LastName string `json:"last_name,required,nullable"` - PhoneNumbers []CandidatePhoneNumber `json:"phone_numbers,required"` - JSON candidateJSON -} - -// candidateJSON contains the JSON metadata for the struct [Candidate] -type candidateJSON struct { - ID apijson.Field - ApplicationIDs apijson.Field - CreatedAt apijson.Field - Emails apijson.Field - FirstName apijson.Field - FullName apijson.Field - LastActivityAt apijson.Field - LastName apijson.Field - PhoneNumbers apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *Candidate) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -type CandidateEmail struct { - Data string `json:"data,nullable"` - Type string `json:"type,nullable"` - JSON candidateEmailJSON -} - -// candidateEmailJSON contains the JSON metadata for the struct [CandidateEmail] -type candidateEmailJSON struct { - Data apijson.Field - Type apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *CandidateEmail) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -type CandidatePhoneNumber struct { - Data string `json:"data,nullable"` - Type string `json:"type,nullable"` - JSON candidatePhoneNumberJSON -} - -// candidatePhoneNumberJSON contains the JSON metadata for the struct -// [CandidatePhoneNumber] -type candidatePhoneNumberJSON struct { - Data apijson.Field - Type apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *CandidatePhoneNumber) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -type ATSCandidateListParams struct { - // Number of candidates to return (defaults to all) - Limit param.Field[int64] `query:"limit"` - // Index to start from (defaults to 0) - Offset param.Field[int64] `query:"offset"` -} - -// URLQuery serializes [ATSCandidateListParams]'s query parameters as `url.Values`. -func (r ATSCandidateListParams) URLQuery() (v url.Values) { - return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ - ArrayFormat: apiquery.ArrayQueryFormatComma, - NestedFormat: apiquery.NestedQueryFormatBrackets, - }) -} diff --git a/atscandidate_test.go b/atscandidate_test.go deleted file mode 100644 index 75b76f5..0000000 --- a/atscandidate_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package finchgo_test - -import ( - "context" - "errors" - "testing" - - finchgo "github.com/Finch-API/finch-api-go" - "github.com/Finch-API/finch-api-go/internal/testutil" - "github.com/Finch-API/finch-api-go/option" -) - -func TestATSCandidateGet(t *testing.T) { - if !testutil.CheckTestServer(t) { - return - } - client := finchgo.NewClient( - option.WithBaseURL("http://127.0.0.1:4010"), - option.WithAccessToken("AccessToken"), - ) - _, err := client.ATS.Candidates.Get(context.TODO(), "string") - if err != nil { - var apierr *finchgo.Error - if errors.As(err, &apierr) { - t.Log(string(apierr.DumpRequest(true))) - } - t.Fatalf("err should be nil: %s", err.Error()) - } -} - -func TestATSCandidateListWithOptionalParams(t *testing.T) { - if !testutil.CheckTestServer(t) { - return - } - client := finchgo.NewClient( - option.WithBaseURL("http://127.0.0.1:4010"), - option.WithAccessToken("AccessToken"), - ) - _, err := client.ATS.Candidates.List(context.TODO(), finchgo.ATSCandidateListParams{ - Limit: finchgo.F(int64(0)), - Offset: finchgo.F(int64(0)), - }) - if err != nil { - var apierr *finchgo.Error - if errors.As(err, &apierr) { - t.Log(string(apierr.DumpRequest(true))) - } - t.Fatalf("err should be nil: %s", err.Error()) - } -} diff --git a/atsjob.go b/atsjob.go deleted file mode 100644 index 76d8150..0000000 --- a/atsjob.go +++ /dev/null @@ -1,276 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package finchgo - -import ( - "context" - "fmt" - "net/http" - "net/url" - "time" - - "github.com/Finch-API/finch-api-go/internal/apijson" - "github.com/Finch-API/finch-api-go/internal/apiquery" - "github.com/Finch-API/finch-api-go/internal/param" - "github.com/Finch-API/finch-api-go/internal/requestconfig" - "github.com/Finch-API/finch-api-go/option" -) - -// ATSJobService contains methods and other services that help with interacting -// with the Finch API. Note, unlike clients, this service does not read variables -// from the environment automatically. You should not instantiate this service -// directly, and instead use the [NewATSJobService] method instead. -type ATSJobService struct { - Options []option.RequestOption -} - -// NewATSJobService generates a new service that applies the given options to each -// request. These options are applied after the parent client's options (if there -// is one), and before any request-specific options. -func NewATSJobService(opts ...option.RequestOption) (r *ATSJobService) { - r = &ATSJobService{} - r.Options = opts - return -} - -// Gets a job from an organization. -func (r *ATSJobService) Get(ctx context.Context, jobID string, opts ...option.RequestOption) (res *Job, err error) { - opts = append(r.Options[:], opts...) - path := fmt.Sprintf("ats/jobs/%s", jobID) - err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return -} - -// Gets all of an organization's jobs. -func (r *ATSJobService) List(ctx context.Context, query ATSJobListParams, opts ...option.RequestOption) (res *JobsPage, err error) { - var raw *http.Response - opts = append(r.Options, opts...) - opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...) - path := "ats/jobs" - cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, query, &res, opts...) - if err != nil { - return nil, err - } - err = cfg.Execute() - if err != nil { - return nil, err - } - res.SetPageConfig(cfg, raw) - return res, nil -} - -// Gets all of an organization's jobs. -func (r *ATSJobService) ListAutoPaging(ctx context.Context, query ATSJobListParams, opts ...option.RequestOption) *JobsPageAutoPager { - return NewJobsPageAutoPager(r.List(ctx, query, opts...)) -} - -type JobsPage struct { - Jobs []Job `json:"jobs,required"` - Paging Paging `json:"paging,required"` - JSON jobsPageJSON - cfg *requestconfig.RequestConfig - res *http.Response -} - -// jobsPageJSON contains the JSON metadata for the struct [JobsPage] -type jobsPageJSON struct { - Jobs apijson.Field - Paging apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *JobsPage) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -// NextPage returns the next page as defined by this pagination style. When there -// is no next page, this function will return a 'nil' for the page value, but will -// not return an error -func (r *JobsPage) GetNextPage() (res *JobsPage, err error) { - // This page represents a response that isn't actually paginated at the API level - // so there will never be a next page. - cfg := (*requestconfig.RequestConfig)(nil) - if cfg == nil { - return nil, nil - } - var raw *http.Response - cfg.ResponseInto = &raw - cfg.ResponseBodyInto = &res - err = cfg.Execute() - if err != nil { - return nil, err - } - res.SetPageConfig(cfg, raw) - return res, nil -} - -func (r *JobsPage) SetPageConfig(cfg *requestconfig.RequestConfig, res *http.Response) { - r.cfg = cfg - r.res = res -} - -type JobsPageAutoPager struct { - page *JobsPage - cur Job - idx int - run int - err error -} - -func NewJobsPageAutoPager(page *JobsPage, err error) *JobsPageAutoPager { - return &JobsPageAutoPager{ - page: page, - err: err, - } -} - -func (r *JobsPageAutoPager) Next() bool { - if r.page == nil || len(r.page.Jobs) == 0 { - return false - } - if r.idx >= len(r.page.Jobs) { - r.idx = 0 - r.page, r.err = r.page.GetNextPage() - if r.err != nil || r.page == nil { - return false - } - } - r.cur = r.page.Jobs[r.idx] - r.run += 1 - r.idx += 1 - return true -} - -func (r *JobsPageAutoPager) Current() Job { - return r.cur -} - -func (r *JobsPageAutoPager) Err() error { - return r.err -} - -func (r *JobsPageAutoPager) Index() int { - return r.run -} - -type Job struct { - ID string `json:"id,required" format:"uuid"` - ClosedAt time.Time `json:"closed_at,required,nullable" format:"date-time"` - CreatedAt time.Time `json:"created_at,required,nullable" format:"date-time"` - Department JobDepartment `json:"department,required"` - HiringTeam JobHiringTeam `json:"hiring_team,required"` - Name string `json:"name,required,nullable"` - Status JobStatus `json:"status,required,nullable"` - JSON jobJSON -} - -// jobJSON contains the JSON metadata for the struct [Job] -type jobJSON struct { - ID apijson.Field - ClosedAt apijson.Field - CreatedAt apijson.Field - Department apijson.Field - HiringTeam apijson.Field - Name apijson.Field - Status apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *Job) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -type JobDepartment struct { - Name string `json:"name,nullable"` - JSON jobDepartmentJSON -} - -// jobDepartmentJSON contains the JSON metadata for the struct [JobDepartment] -type jobDepartmentJSON struct { - Name apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *JobDepartment) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -type JobHiringTeam struct { - HiringManagers []JobHiringTeamHiringManager `json:"hiring_managers,nullable"` - Recruiters []JobHiringTeamRecruiter `json:"recruiters,nullable"` - JSON jobHiringTeamJSON -} - -// jobHiringTeamJSON contains the JSON metadata for the struct [JobHiringTeam] -type jobHiringTeamJSON struct { - HiringManagers apijson.Field - Recruiters apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *JobHiringTeam) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -type JobHiringTeamHiringManager struct { - Name string `json:"name"` - JSON jobHiringTeamHiringManagerJSON -} - -// jobHiringTeamHiringManagerJSON contains the JSON metadata for the struct -// [JobHiringTeamHiringManager] -type jobHiringTeamHiringManagerJSON struct { - Name apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *JobHiringTeamHiringManager) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -type JobHiringTeamRecruiter struct { - Name string `json:"name"` - JSON jobHiringTeamRecruiterJSON -} - -// jobHiringTeamRecruiterJSON contains the JSON metadata for the struct -// [JobHiringTeamRecruiter] -type jobHiringTeamRecruiterJSON struct { - Name apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *JobHiringTeamRecruiter) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -type JobStatus string - -const ( - JobStatusOpen JobStatus = "open" - JobStatusClosed JobStatus = "closed" - JobStatusOnHold JobStatus = "on_hold" - JobStatusDraft JobStatus = "draft" - JobStatusArchived JobStatus = "archived" -) - -type ATSJobListParams struct { - // Number of jobs to return (defaults to all) - Limit param.Field[int64] `query:"limit"` - // Index to start from (defaults to 0) - Offset param.Field[int64] `query:"offset"` -} - -// URLQuery serializes [ATSJobListParams]'s query parameters as `url.Values`. -func (r ATSJobListParams) URLQuery() (v url.Values) { - return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ - ArrayFormat: apiquery.ArrayQueryFormatComma, - NestedFormat: apiquery.NestedQueryFormatBrackets, - }) -} diff --git a/atsjob_test.go b/atsjob_test.go deleted file mode 100644 index ce22df7..0000000 --- a/atsjob_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package finchgo_test - -import ( - "context" - "errors" - "testing" - - finchgo "github.com/Finch-API/finch-api-go" - "github.com/Finch-API/finch-api-go/internal/testutil" - "github.com/Finch-API/finch-api-go/option" -) - -func TestATSJobGet(t *testing.T) { - if !testutil.CheckTestServer(t) { - return - } - client := finchgo.NewClient( - option.WithBaseURL("http://127.0.0.1:4010"), - option.WithAccessToken("AccessToken"), - ) - _, err := client.ATS.Jobs.Get(context.TODO(), "string") - if err != nil { - var apierr *finchgo.Error - if errors.As(err, &apierr) { - t.Log(string(apierr.DumpRequest(true))) - } - t.Fatalf("err should be nil: %s", err.Error()) - } -} - -func TestATSJobListWithOptionalParams(t *testing.T) { - if !testutil.CheckTestServer(t) { - return - } - client := finchgo.NewClient( - option.WithBaseURL("http://127.0.0.1:4010"), - option.WithAccessToken("AccessToken"), - ) - _, err := client.ATS.Jobs.List(context.TODO(), finchgo.ATSJobListParams{ - Limit: finchgo.F(int64(0)), - Offset: finchgo.F(int64(0)), - }) - if err != nil { - var apierr *finchgo.Error - if errors.As(err, &apierr) { - t.Log(string(apierr.DumpRequest(true))) - } - t.Fatalf("err should be nil: %s", err.Error()) - } -} diff --git a/atsoffer.go b/atsoffer.go deleted file mode 100644 index ae7bb4b..0000000 --- a/atsoffer.go +++ /dev/null @@ -1,212 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package finchgo - -import ( - "context" - "fmt" - "net/http" - "net/url" - "time" - - "github.com/Finch-API/finch-api-go/internal/apijson" - "github.com/Finch-API/finch-api-go/internal/apiquery" - "github.com/Finch-API/finch-api-go/internal/param" - "github.com/Finch-API/finch-api-go/internal/requestconfig" - "github.com/Finch-API/finch-api-go/option" -) - -// ATSOfferService contains methods and other services that help with interacting -// with the Finch API. Note, unlike clients, this service does not read variables -// from the environment automatically. You should not instantiate this service -// directly, and instead use the [NewATSOfferService] method instead. -type ATSOfferService struct { - Options []option.RequestOption -} - -// NewATSOfferService generates a new service that applies the given options to -// each request. These options are applied after the parent client's options (if -// there is one), and before any request-specific options. -func NewATSOfferService(opts ...option.RequestOption) (r *ATSOfferService) { - r = &ATSOfferService{} - r.Options = opts - return -} - -// Get a single offer from an organization. -func (r *ATSOfferService) Get(ctx context.Context, offerID string, opts ...option.RequestOption) (res *Offer, err error) { - opts = append(r.Options[:], opts...) - path := fmt.Sprintf("ats/offers/%s", offerID) - err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return -} - -// Get all offers put out by an organization. -func (r *ATSOfferService) List(ctx context.Context, query ATSOfferListParams, opts ...option.RequestOption) (res *OffersPage, err error) { - var raw *http.Response - opts = append(r.Options, opts...) - opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...) - path := "ats/offers" - cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, query, &res, opts...) - if err != nil { - return nil, err - } - err = cfg.Execute() - if err != nil { - return nil, err - } - res.SetPageConfig(cfg, raw) - return res, nil -} - -// Get all offers put out by an organization. -func (r *ATSOfferService) ListAutoPaging(ctx context.Context, query ATSOfferListParams, opts ...option.RequestOption) *OffersPageAutoPager { - return NewOffersPageAutoPager(r.List(ctx, query, opts...)) -} - -type OffersPage struct { - Offers []Offer `json:"offers,required"` - Paging Paging `json:"paging,required"` - JSON offersPageJSON - cfg *requestconfig.RequestConfig - res *http.Response -} - -// offersPageJSON contains the JSON metadata for the struct [OffersPage] -type offersPageJSON struct { - Offers apijson.Field - Paging apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *OffersPage) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -// NextPage returns the next page as defined by this pagination style. When there -// is no next page, this function will return a 'nil' for the page value, but will -// not return an error -func (r *OffersPage) GetNextPage() (res *OffersPage, err error) { - // This page represents a response that isn't actually paginated at the API level - // so there will never be a next page. - cfg := (*requestconfig.RequestConfig)(nil) - if cfg == nil { - return nil, nil - } - var raw *http.Response - cfg.ResponseInto = &raw - cfg.ResponseBodyInto = &res - err = cfg.Execute() - if err != nil { - return nil, err - } - res.SetPageConfig(cfg, raw) - return res, nil -} - -func (r *OffersPage) SetPageConfig(cfg *requestconfig.RequestConfig, res *http.Response) { - r.cfg = cfg - r.res = res -} - -type OffersPageAutoPager struct { - page *OffersPage - cur Offer - idx int - run int - err error -} - -func NewOffersPageAutoPager(page *OffersPage, err error) *OffersPageAutoPager { - return &OffersPageAutoPager{ - page: page, - err: err, - } -} - -func (r *OffersPageAutoPager) Next() bool { - if r.page == nil || len(r.page.Offers) == 0 { - return false - } - if r.idx >= len(r.page.Offers) { - r.idx = 0 - r.page, r.err = r.page.GetNextPage() - if r.err != nil || r.page == nil { - return false - } - } - r.cur = r.page.Offers[r.idx] - r.run += 1 - r.idx += 1 - return true -} - -func (r *OffersPageAutoPager) Current() Offer { - return r.cur -} - -func (r *OffersPageAutoPager) Err() error { - return r.err -} - -func (r *OffersPageAutoPager) Index() int { - return r.run -} - -type Offer struct { - ID string `json:"id,required" format:"uuid"` - ApplicationID string `json:"application_id,required" format:"uuid"` - CandidateID string `json:"candidate_id,required" format:"uuid"` - CreatedAt time.Time `json:"created_at,required" format:"date-time"` - JobID string `json:"job_id,required" format:"uuid"` - Status OfferStatus `json:"status,required"` - UpdatedAt time.Time `json:"updated_at,required" format:"date-time"` - JSON offerJSON -} - -// offerJSON contains the JSON metadata for the struct [Offer] -type offerJSON struct { - ID apijson.Field - ApplicationID apijson.Field - CandidateID apijson.Field - CreatedAt apijson.Field - JobID apijson.Field - Status apijson.Field - UpdatedAt apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *Offer) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -type OfferStatus string - -const ( - OfferStatusSigned OfferStatus = "signed" - OfferStatusRejected OfferStatus = "rejected" - OfferStatusDraft OfferStatus = "draft" - OfferStatusApprovalSent OfferStatus = "approval-sent" - OfferStatusApproved OfferStatus = "approved" - OfferStatusSent OfferStatus = "sent" - OfferStatusSentManually OfferStatus = "sent-manually" - OfferStatusOpened OfferStatus = "opened" - OfferStatusArchived OfferStatus = "archived" -) - -type ATSOfferListParams struct { - // Number of offers to return (defaults to all) - Limit param.Field[int64] `query:"limit"` - // Index to start from (defaults to 0) - Offset param.Field[int64] `query:"offset"` -} - -// URLQuery serializes [ATSOfferListParams]'s query parameters as `url.Values`. -func (r ATSOfferListParams) URLQuery() (v url.Values) { - return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ - ArrayFormat: apiquery.ArrayQueryFormatComma, - NestedFormat: apiquery.NestedQueryFormatBrackets, - }) -} diff --git a/atsoffer_test.go b/atsoffer_test.go deleted file mode 100644 index a644a41..0000000 --- a/atsoffer_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package finchgo_test - -import ( - "context" - "errors" - "testing" - - finchgo "github.com/Finch-API/finch-api-go" - "github.com/Finch-API/finch-api-go/internal/testutil" - "github.com/Finch-API/finch-api-go/option" -) - -func TestATSOfferGet(t *testing.T) { - if !testutil.CheckTestServer(t) { - return - } - client := finchgo.NewClient( - option.WithBaseURL("http://127.0.0.1:4010"), - option.WithAccessToken("AccessToken"), - ) - _, err := client.ATS.Offers.Get(context.TODO(), "string") - if err != nil { - var apierr *finchgo.Error - if errors.As(err, &apierr) { - t.Log(string(apierr.DumpRequest(true))) - } - t.Fatalf("err should be nil: %s", err.Error()) - } -} - -func TestATSOfferListWithOptionalParams(t *testing.T) { - if !testutil.CheckTestServer(t) { - return - } - client := finchgo.NewClient( - option.WithBaseURL("http://127.0.0.1:4010"), - option.WithAccessToken("AccessToken"), - ) - _, err := client.ATS.Offers.List(context.TODO(), finchgo.ATSOfferListParams{ - Limit: finchgo.F(int64(0)), - Offset: finchgo.F(int64(0)), - }) - if err != nil { - var apierr *finchgo.Error - if errors.As(err, &apierr) { - t.Log(string(apierr.DumpRequest(true))) - } - t.Fatalf("err should be nil: %s", err.Error()) - } -} diff --git a/atsstage.go b/atsstage.go deleted file mode 100644 index 43a211a..0000000 --- a/atsstage.go +++ /dev/null @@ -1,81 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package finchgo - -import ( - "context" - "net/http" - - "github.com/Finch-API/finch-api-go/internal/apijson" - "github.com/Finch-API/finch-api-go/internal/requestconfig" - "github.com/Finch-API/finch-api-go/internal/shared" - "github.com/Finch-API/finch-api-go/option" -) - -// ATSStageService contains methods and other services that help with interacting -// with the Finch API. Note, unlike clients, this service does not read variables -// from the environment automatically. You should not instantiate this service -// directly, and instead use the [NewATSStageService] method instead. -type ATSStageService struct { - Options []option.RequestOption -} - -// NewATSStageService generates a new service that applies the given options to -// each request. These options are applied after the parent client's options (if -// there is one), and before any request-specific options. -func NewATSStageService(opts ...option.RequestOption) (r *ATSStageService) { - r = &ATSStageService{} - r.Options = opts - return -} - -// Get all job stages for an organization. Depending on the system, some jobs may -// have stages specific to that job. Other job stages may apply broadly to all jobs -// in the system. Use the `job_id` to determine whether a job applies specifically -// to a job. -func (r *ATSStageService) List(ctx context.Context, opts ...option.RequestOption) (res *shared.SinglePage[Stage], err error) { - var raw *http.Response - opts = append(r.Options, opts...) - opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...) - path := "ats/stages" - cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, nil, &res, opts...) - if err != nil { - return nil, err - } - err = cfg.Execute() - if err != nil { - return nil, err - } - res.SetPageConfig(cfg, raw) - return res, nil -} - -// Get all job stages for an organization. Depending on the system, some jobs may -// have stages specific to that job. Other job stages may apply broadly to all jobs -// in the system. Use the `job_id` to determine whether a job applies specifically -// to a job. -func (r *ATSStageService) ListAutoPaging(ctx context.Context, opts ...option.RequestOption) *shared.SinglePageAutoPager[Stage] { - return shared.NewSinglePageAutoPager(r.List(ctx, opts...)) -} - -type Stage struct { - ID string `json:"id" format:"uuid"` - // The job id that this stage applies to, if applicable. Not all systems enumerate - // stages specific to jobs. - JobID string `json:"job_id,nullable" format:"uuid"` - Name string `json:"name,nullable"` - JSON stageJSON -} - -// stageJSON contains the JSON metadata for the struct [Stage] -type stageJSON struct { - ID apijson.Field - JobID apijson.Field - Name apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *Stage) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} diff --git a/atsstage_test.go b/atsstage_test.go deleted file mode 100644 index d0364c0..0000000 --- a/atsstage_test.go +++ /dev/null @@ -1,31 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package finchgo_test - -import ( - "context" - "errors" - "testing" - - finchgo "github.com/Finch-API/finch-api-go" - "github.com/Finch-API/finch-api-go/internal/testutil" - "github.com/Finch-API/finch-api-go/option" -) - -func TestATSStageList(t *testing.T) { - if !testutil.CheckTestServer(t) { - return - } - client := finchgo.NewClient( - option.WithBaseURL("http://127.0.0.1:4010"), - option.WithAccessToken("AccessToken"), - ) - _, err := client.ATS.Stages.List(context.TODO()) - if err != nil { - var apierr *finchgo.Error - if errors.As(err, &apierr) { - t.Log(string(apierr.DumpRequest(true))) - } - t.Fatalf("err should be nil: %s", err.Error()) - } -} diff --git a/client.go b/client.go index 1a501e0..42096b5 100644 --- a/client.go +++ b/client.go @@ -14,7 +14,6 @@ import ( type Client struct { Options []option.RequestOption HRIS *HRISService - ATS *ATSService Providers *ProviderService Account *AccountService Webhooks *WebhookService @@ -40,7 +39,6 @@ func NewClient(opts ...option.RequestOption) (r *Client) { r = &Client{Options: opts} r.HRIS = NewHRISService(opts...) - r.ATS = NewATSService(opts...) r.Providers = NewProviderService(opts...) r.Account = NewAccountService(opts...) r.Webhooks = NewWebhookService(opts...) diff --git a/client_test.go b/client_test.go index 8d2cb89..9867fd9 100644 --- a/client_test.go +++ b/client_test.go @@ -20,7 +20,7 @@ func TestCancel(t *testing.T) { ) cancelCtx, cancel := context.WithCancel(context.Background()) cancel() - res, err := client.ATS.Candidates.Get(cancelCtx, "") + res, err := client.HRIS.Directory.ListIndividuals(cancelCtx, finchgo.HRISDirectoryListIndividualsParams{}) if err == nil || res != nil { t.Error("Expected there to be a cancel error and for the response to be nil") } @@ -44,7 +44,7 @@ func TestCancelDelay(t *testing.T) { time.Sleep(time.Millisecond * time.Duration(2)) cancel() }() - res, err := client.ATS.Candidates.Get(cancelCtx, "") + res, err := client.HRIS.Directory.ListIndividuals(cancelCtx, finchgo.HRISDirectoryListIndividualsParams{}) if err == nil || res != nil { t.Error("Expected there to be a cancel error and for the response to be nil") } diff --git a/paginationauto_test.go b/paginationauto_test.go index a5b47da..ef96b4b 100644 --- a/paginationauto_test.go +++ b/paginationauto_test.go @@ -19,11 +19,11 @@ func TestAutoPagination(t *testing.T) { option.WithBaseURL("http://127.0.0.1:4010"), option.WithAccessToken("AccessToken"), ) - iter := client.ATS.Jobs.ListAutoPaging(context.TODO(), finchgo.ATSJobListParams{}) + iter := client.HRIS.Directory.ListIndividualsAutoPaging(context.TODO(), finchgo.HRISDirectoryListIndividualsParams{}) // Prism mock isn't going to give us real pagination for i := 0; i < 3 && iter.Next(); i++ { - job := iter.Current() - t.Logf("%+v\n", job) + directory := iter.Current() + t.Logf("%+v\n", directory) } if err := iter.Err(); err != nil { t.Fatalf("err should be nil: %s", err.Error()) diff --git a/paginationmanual_test.go b/paginationmanual_test.go index 7dad9cc..4bb05e9 100644 --- a/paginationmanual_test.go +++ b/paginationmanual_test.go @@ -19,12 +19,12 @@ func TestManualPagination(t *testing.T) { option.WithBaseURL("http://127.0.0.1:4010"), option.WithAccessToken("AccessToken"), ) - page, err := client.ATS.Jobs.List(context.TODO(), finchgo.ATSJobListParams{}) + page, err := client.HRIS.Directory.ListIndividuals(context.TODO(), finchgo.HRISDirectoryListIndividualsParams{}) if err != nil { t.Fatalf("err should be nil: %s", err.Error()) } - for _, job := range page.Jobs { - t.Logf("%+v\n", job) + for _, directory := range page.Individuals { + t.Logf("%+v\n", directory) } // Prism mock isn't going to give us real pagination page, err = page.GetNextPage() @@ -32,8 +32,8 @@ func TestManualPagination(t *testing.T) { t.Fatalf("err should be nil: %s", err.Error()) } if page != nil { - for _, job := range page.Jobs { - t.Logf("%+v\n", job) + for _, directory := range page.Individuals { + t.Logf("%+v\n", directory) } } } diff --git a/usage_test.go b/usage_test.go index b939337..710fda8 100644 --- a/usage_test.go +++ b/usage_test.go @@ -19,9 +19,9 @@ func TestUsage(t *testing.T) { option.WithBaseURL("http://127.0.0.1:4010"), option.WithAccessToken("AccessToken"), ) - candidate, err := client.ATS.Candidates.Get(context.TODO(), "") + page, err := client.HRIS.Directory.ListIndividuals(context.TODO(), finchgo.HRISDirectoryListIndividualsParams{}) if err != nil { t.Error(err) } - t.Logf("%+v\n", candidate.FirstName) + t.Logf("%+v\n", page) } From 4b23c2831725bbe854d88fb2e399dd16fa88a8b0 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Thu, 21 Sep 2023 12:25:03 -0400 Subject: [PATCH 6/8] docs(README): fix variable names in some examples (#13) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fd34832..57a74a0 100644 --- a/README.md +++ b/README.md @@ -162,8 +162,8 @@ You can use `.ListAutoPaging()` methods to iterate through items across all page iter := client.HRIS.Directory.ListIndividualsAutoPaging(context.TODO(), finchgo.HRISDirectoryListIndividualsParams{}) // Automatically fetches more pages as needed. for iter.Next() { - directory := iter.Current() - fmt.Printf("%+v\n", directory) + individualInDirectory := iter.Current() + fmt.Printf("%+v\n", individualInDirectory) } if err := iter.Err(); err != nil { panic(err.Error()) From 3030c7354f856084304a175ac637c99e0517b0f7 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Fri, 22 Sep 2023 10:04:46 -0400 Subject: [PATCH 7/8] docs(api.md): rename Top Level to client name (#14) --- api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api.md b/api.md index aabcd9b..d611d76 100644 --- a/api.md +++ b/api.md @@ -1,4 +1,4 @@ -# Top Level +# finchgo # HRIS From 64707d0be7348cee75be9b82440dcc35b135a7d7 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Fri, 22 Sep 2023 10:04:58 -0400 Subject: [PATCH 8/8] release: 0.0.3 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 24 ++++++++++++++++++++++++ README.md | 2 +- internal/version.go | 2 +- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c7159c1..28e831b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.0.2" + ".": "0.0.3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 63f1183..ae24503 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## 0.0.3 (2023-09-22) + +Full Changelog: [v0.0.2...v0.0.3](https://github.com/Finch-API/finch-api-go/compare/v0.0.2...v0.0.3) + +### Features + +* retry on 408 Request Timeout ([#7](https://github.com/Finch-API/finch-api-go/issues/7)) ([6075488](https://github.com/Finch-API/finch-api-go/commit/6075488158fc1ea2db4bf1d280a3479ad916bd79)) + + +### Bug Fixes + +* **core:** improve retry behavior and related docs ([#9](https://github.com/Finch-API/finch-api-go/issues/9)) ([7107ce5](https://github.com/Finch-API/finch-api-go/commit/7107ce5b8411fa3b44c1de961ddaab4b8f17cf24)) + + +### Chores + +* **api:** remove deprecated & unused ATS API ([#12](https://github.com/Finch-API/finch-api-go/issues/12)) ([213405d](https://github.com/Finch-API/finch-api-go/commit/213405d52af5efd4593568a245ba27432e820033)) + + +### Documentation + +* **api.md:** rename Top Level to client name ([#14](https://github.com/Finch-API/finch-api-go/issues/14)) ([3030c73](https://github.com/Finch-API/finch-api-go/commit/3030c7354f856084304a175ac637c99e0517b0f7)) +* **README:** fix variable names in some examples ([#13](https://github.com/Finch-API/finch-api-go/issues/13)) ([4b23c28](https://github.com/Finch-API/finch-api-go/commit/4b23c2831725bbe854d88fb2e399dd16fa88a8b0)) + ## 0.0.2 (2023-09-14) Full Changelog: [v0.0.1...v0.0.2](https://github.com/Finch-API/finch-api-go/compare/v0.0.1...v0.0.2) diff --git a/README.md b/README.md index 57a74a0..205f874 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Or to pin the version: ```sh -go get -u 'github.com/Finch-API/finch-api-go@v0.0.2' +go get -u 'github.com/Finch-API/finch-api-go@v0.0.3' ``` diff --git a/internal/version.go b/internal/version.go index d56a5ff..1a2f43a 100644 --- a/internal/version.go +++ b/internal/version.go @@ -2,4 +2,4 @@ package internal -const PackageVersion = "0.0.2" // x-release-please-version +const PackageVersion = "0.0.3" // x-release-please-version