{"id":26745275,"url":"https://github.com/simplesurance/cfdns","last_synced_at":"2025-10-21T18:04:09.543Z","repository":{"id":207047067,"uuid":"718177066","full_name":"simplesurance/cfdns","owner":"simplesurance","description":"Go API for managing CloudFlare DNS","archived":false,"fork":false,"pushed_at":"2025-10-04T19:01:45.000Z","size":1822,"stargazers_count":2,"open_issues_count":3,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-10-04T19:04:34.397Z","etag":null,"topics":["cloudflare","golang"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simplesurance.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":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-11-13T14:43:14.000Z","updated_at":"2025-09-03T13:56:35.000Z","dependencies_parsed_at":"2024-01-02T16:26:26.009Z","dependency_job_id":"36ef7c56-b201-43a3-81d0-18a414f31ae5","html_url":"https://github.com/simplesurance/cfdns","commit_stats":null,"previous_names":["simplesurance/cfdns"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/simplesurance/cfdns","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simplesurance%2Fcfdns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simplesurance%2Fcfdns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simplesurance%2Fcfdns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simplesurance%2Fcfdns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simplesurance","download_url":"https://codeload.github.com/simplesurance/cfdns/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simplesurance%2Fcfdns/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280308521,"owners_count":26308494,"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","status":"online","status_checked_at":"2025-10-21T02:00:06.614Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["cloudflare","golang"],"created_at":"2025-03-28T08:16:09.177Z","updated_at":"2025-10-21T18:04:09.522Z","avatar_url":"https://github.com/simplesurance.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CFDNS\n[![Go Report Card](https://goreportcard.com/badge/github.com/simplesurance/cfdns)](https://goreportcard.com/report/github.com/simplesurance/cfdns)\n\n## About\n\nNon-Official GO CloudFlare DNS API client. It was created because\nthe official API is not stable and breaks its consumers multiple times\na year. Some of the breaks are immediately apparent because the compiler\nitself can find the problem, sometimes the expectation can't be detected\nautomatically, while when the returned error is changed, leading to\nunexpected behavior in code that might be mission-critical.\n\nThis library is being used on a system that manages dozens of domains with\nthousands of records, and makes hundreds of changes per day. It show up to\nbe reliable, and eliminating multiple issues that were present when the\nofficial library was being used.\n\nThe original library also has an implementation that requires an unbounded\namount of memory when listing records. This implementation is `O(1)` in\nmemory for all operations.\n\nExponential back-off is implemented and heavily tested.\n\nThis library was designed to support only the DNS service.\n\n## Project Status\n\nThis version is stable, being used in production. It will provide backwards\ncompatibility according to go module conventions.\n\n## How to Get\n\n```bash\ngo get github.com/simplesurance/cfdns@latest\n```\n## How to Use\n\n### Listing Records\n\nListing records uses the _Iterator_ pattern to completely abstract the\ncomplexity of pagination, while keeping constant memory usage, even when\nthe resulting list is arbitrarily large.\n\n```go\nctx := context.Background()\napitoken := os.Getenv(\"CFTOKEN\")\n\ncreds, err := cfdns.APIToken(apitoken)\nif err != nil {\n\tpanic(err)\n}\n\nclient := cfdns.NewClient(creds)\n\niter := client.ListZones(\u0026cfdns.ListZonesRequest{})\nfor {\n\tzone, err := iter.Next(ctx)\n\tif err != nil {\n\t\tif errors.Is(err, io.EOF) {\n\t\t\tbreak\n\t\t}\n\n\t\tpanic(err)\n\t}\n\n\tfmt.Printf(\"Found zone %s\\n\", zone.Name)\n}\n```\n\n### Create and Delete a DNS Record\n\nAll methods that do not return a list receive a context and a request\nstruct and return a struct and an error.\n\n```go\nctx := context.Background()\napitoken := os.Getenv(\"TEST_CF_APITOKEN\")\ntestZoneID := os.Getenv(\"TEST_CF_ZONE_ID\")\n\ncreds, err := cfdns.APIToken(apitoken)\nif err != nil {\n\tpanic(err)\n}\n\nclient := cfdns.NewClient(creds)\n\nresp, err := client.CreateRecord(ctx, \u0026cfdns.CreateRecordRequest{\n\tZoneID:  testZoneID,\n\tName:    \"example-record\",\n\tType:    \"CNAME\",\n\tContent: \"github.com\",\n\tProxied: false,\n\tComment: \"Created by cfdns example\",\n\tTTL:     time.Duration(30 * time.Minute),\n})\nif err != nil {\n\tpanic(err)\n}\n\nfmt.Printf(\"Created DNS record %s\", resp.Name)\n\n// cleanup\n_, _ = client.DeleteRecord(ctx, \u0026cfdns.DeleteRecordRequest{\n\tZoneID:   testZoneID,\n\tRecordID: resp.ID,\n})\n\n// Output: Created DNS record example-record.simplesurance.top\n```\n\n## Error Handling\n\nRules for errors returned are as follows:\n\n1. If the error response came from sending the HTTP response to the\n   CloudFlare, even if it is an invalid response, the error is\n   HTTPError;\n2. If the response is a valid CloudFlare API response, then the error\n   is also a CloudFlareError (so it is both HTTPError and CloudFlareError);\n3. If not valid HTTP response could be obtained from the server, then some\n   other error is returned.\n\nIn all cases, the caller MUST use `errors.As()` to get either the\n`HTTPError` or `CloudFlareError` object.\n\n### HTTPError\n\nAll errors that result from calling the CloudFlare REST API allow reading\nthe HTTP response that caused it.\n\n```go\nctx := context.Background()\napitoken := os.Getenv(\"TEST_CF_APITOKEN\")\ntestZoneID := os.Getenv(\"TEST_CF_ZONE_ID\")\n\ncreds, err := cfdns.APIToken(apitoken)\nif err != nil {\n\tpanic(err)\n}\n\nclient := cfdns.NewClient(creds)\n\n_, err = client.CreateRecord(ctx, \u0026cfdns.CreateRecordRequest{\n\tZoneID:  testZoneID,\n\tName:    \"invalid name\",\n\tType:    \"A\",\n\tContent: \"github.com\",\n\tComment: \"Created by cfdns example\",\n\tTTL:     30 * time.Minute,\n})\n\nhttpErr := cfdns.HTTPError{}\nif !errors.As(err, \u0026httpErr) {\n\tpanic(\"not an HTTP error\")\n}\n\nfmt.Printf(\"Got HTTP error %v\", httpErr.Code) // can also access response headers and raw response body\n\n// Output: Got HTTP error 400\n```\n\n### CloudFlareError\n\n```go\nctx := context.Background()\napitoken := os.Getenv(\"TEST_CF_APITOKEN\")\ntestZoneID := os.Getenv(\"TEST_CF_ZONE_ID\")\n\ncreds, err := cfdns.APIToken(apitoken)\nif err != nil {\n\tpanic(err)\n}\n\nclient := cfdns.NewClient(creds)\n\n_, err = client.CreateRecord(ctx, \u0026cfdns.CreateRecordRequest{\n\tZoneID:  testZoneID,\n\tName:    \"invalid name\",\n\tType:    \"A\",\n\tContent: \"github.com\",\n\tComment: \"Created by cfdns example\",\n\tTTL:     30 * time.Minute,\n})\n\ncfErr := cfdns.CloudFlareError{}\nif !errors.As(err, \u0026cfErr) {\n\tpanic(\"not a CloudFlareError\")\n}\n\nfmt.Printf(\"Got HTTP error %v\\n\", cfErr.HTTPError.Code) // can also access response headers and raw response body\n\nfor _, cfe := range cfErr.Errors {\n\tfmt.Printf(\"- CF error %d: %s\\n\", cfe.Code, cfe.Message) // can also access response headers and raw response body\n}\n\n// Output:\n// Got HTTP error 400\n// - CF error 9005: Content for A record must be a valid IPv4 address.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimplesurance%2Fcfdns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimplesurance%2Fcfdns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimplesurance%2Fcfdns/lists"}