{"id":16372598,"url":"https://github.com/hedhyw/semerr","last_synced_at":"2025-03-21T01:31:42.689Z","repository":{"id":38309002,"uuid":"418185747","full_name":"hedhyw/semerr","owner":"hedhyw","description":"A way of dealing with Golang errors","archived":false,"fork":false,"pushed_at":"2024-12-29T09:43:56.000Z","size":2962,"stargazers_count":5,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-17T19:39:47.905Z","etag":null,"topics":["errors","go","golang","golang-errors","golang-library","golang-package","grpc","http"],"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/hedhyw.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-17T16:14:28.000Z","updated_at":"2025-02-12T06:39:29.000Z","dependencies_parsed_at":"2023-10-02T03:21:44.956Z","dependency_job_id":"fed5983b-c02a-47d6-9bf7-73a3b2a6a8aa","html_url":"https://github.com/hedhyw/semerr","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hedhyw%2Fsemerr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hedhyw%2Fsemerr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hedhyw%2Fsemerr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hedhyw%2Fsemerr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hedhyw","download_url":"https://codeload.github.com/hedhyw/semerr/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244721224,"owners_count":20498911,"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":["errors","go","golang","golang-errors","golang-library","golang-package","grpc","http"],"created_at":"2024-10-11T03:11:55.781Z","updated_at":"2025-03-21T01:31:42.029Z","avatar_url":"https://github.com/hedhyw.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- File is generated by \"github.com/hedhyw/semerr\"; DO NOT EDIT. --\u003e\n\n# semerr\n\n![Version](https://img.shields.io/github/v/tag/hedhyw/semerr)\n![Build Status](https://github.com/hedhyw/semerr/actions/workflows/check.yml/badge.svg)\n[![Go Report Card](https://goreportcard.com/badge/github.com/hedhyw/semerr)](https://goreportcard.com/report/github.com/hedhyw/semerr)\n[![Coverage Status](https://coveralls.io/repos/github/hedhyw/semerr/badge.svg?branch=main)](https://coveralls.io/github/hedhyw/semerr?branch=main)\n[![PkgGoDev](https://pkg.go.dev/badge/github.com/hedhyw/semerr)](https://pkg.go.dev/github.com/hedhyw/semerr?tab=doc)\n\nPackage `semerr` helps to work with errors in Golang. It supports go 1.20 [errors.Join](https://pkg.go.dev/errors#Join).\n\n\u003cimg alr=\"Go Bug\" src=\"https://raw.githubusercontent.com/ashleymcnamara/gophers/master/GO_BUG.png\" width=\"100px\"\u003e\n\n## Status errors\n\nThose errors are based on HTTP status names, but they are designed to be\ntransport-independent. For example `semerr.NewNotFoundError(err)` indicates\nthat something is not found\n(and it is possible to extract HTTP status -\u003e `404` and gRPC status -\u003e `5` if required).\n\nSmall example:\n```go\n// Repository layer.\n\ntype RedisUserRepo struct {}\n\nfunc (r RedisUserRepo) Get(ctx context.Context, id string) (entity.User, error) {\n    u, err := r.client.Get(id)\n\n    switch {\n    case err == nil:\n        return u, nil\n    case errors.Is(err, redis.ErrNil):\n        return entity.User{}, semerr.NewNotFoundError(err)\n    default:\n        return entity.User{}, fmt.Errorf(\"getting user: %w\", err)\n    }\n}\n\n// Domain layer.\n\nfunc (c *Core) CreateOrder(ctx context.Context, order entity.Order) (err error)\n    user, err := c.userRepo.GetCurrentUser(ctx)\n    switch {\n    case err == nil:\n        // OK. Go on.\n    case errors.As(err, \u0026semerr.NotFoundError{}):\n        // Repository can have any implementation and we should NOT know about\n        // `sql.ErrNoRows`, `redis.Nil`, `mongo.NoKey`, so we just compare the `err` to\n        // `semerr.NotFoundError`.\n        //\n        // We still can check `errors.Is(err, redis.Nil)` if we want,\n        // because the `err` is just wrapped without any modifications!\n        //\n        // Also we can change meaning by rewrapping the `err`. Check the next line:\n        return fmt.Errorf(\"getting user: %w\", semerr.NewUnauthorizedError(err))\n    default:\n        return fmt.Errorf(\"getting user: %w\" ,err)\n    }\n    \n    // ...\n}\n\n// Transport layer.\n\nfunc (s *Server) handleCreateOrder(w http.ResponseWriter, r *http.Request) {\n    ctx := r.Context()\n\n    /* ... */\n\n    err := s.core.CreateOrder(ctx, order)\n    if err != nil {\n        // Respond with the correct status.\n        w.WriteHeader(httperr.Code(err))\n\n        // It is better to organize a helper for `err` responding.\n\n        return\n    }\n\n    w.WriteHeader(http.StatusOK)\n}\n```\n\n## Mechanics\n\n```go\nerrOriginal := errors.New(\"some error\")\nerrWrapped := semerr.NewBadRequestError(errOriginal) // The text will be the same.\nerrJoined := errors.Join(errOriginal, errWrapped) // It supports joined errors.\n\nfmt.Println(errWrapped) // \"some error\"\nfmt.Println(httperr.Code(errWrapped)) // http.StatusBadRequest\nfmt.Println(httperr.Code(errJoined)) // http.StatusBadRequest\nfmt.Println(grpcerr.Code(errWrapped)) // codes.InvalidArgument\nfmt.Println(grpcerr.Code(errJoined)) // codes.InvalidArgument\nfmt.Println(errors.Is(err, errOriginal)) // true\nfmt.Println(semerr.NewBadRequestError(nil)) // nil\nfmt.Println(httperr.Wrap(errOriginal, http.StatusBadRequest)) // = semerr.NewBadRequestError(errOriginal)\n```\n\n## Const error\n\nAn error that can be defined as `const`.\n\n```go\nvar errMutable error = errors.New(\"mutable error\") // Do not like this?\nconst errImmutable semerr.Error = \"immutable error\" // So use this.\n```\n\n## Also see\n```go\nerr := errors.New(\"some error\")\n\n// It indicates that the server did not receive a complete request\n// message within the time that it was prepared to wait.\n// HTTP: Request Timeout (408); GRPC: Canceled (1).\nerr = semerr.NewStatusRequestTimeoutError(err)\n\n// It indicates that the server encountered an unexpected\n// condition that prevented it from fulfilling the request.\n// HTTP: Internal Server Error (500); GRPC: Unknown (2).\nerr = semerr.NewInternalServerError(err)\n\n// It indicates that the server cannot or will not process the\n// request due to something that is perceived to be a client error.\n// HTTP: Bad Request (400); GRPC: InvalidArgument (3).\nerr = semerr.NewBadRequestError(err)\n\n// It indicates indicates that the origin server is refusing\n// to service the request because the content is in a format\n// not supported by this method on the target resource.\n// HTTP: Unsupported Media Type (415); GRPC: InvalidArgument (3).\nerr = semerr.NewUnsupportedMediaTypeError(err)\n\n// It indicates that the server, while acting as a gateway or\n// proxy, did not receive a timely response from an upstream\n// server it needed to access in order to complete the request.\n// HTTP: Gateway Timeout (504); GRPC: DeadlineExceeded (4).\nerr = semerr.NewStatusGatewayTimeoutError(err)\n\n// It indicates that the origin server did not find a current\n// representation for the target resource or is not willing to\n// disclose that one exists.\n// HTTP: Not Found (404); GRPC: NotFound (5).\nerr = semerr.NewNotFoundError(err)\n\n// It indicates that the request could not be completed due to\n// a conflict with the current state of the target resource.\n// HTTP: Conflict (409); GRPC: AlreadyExists (6).\nerr = semerr.NewConflictError(err)\n\n// It indicates that the server understood the request but\n// refuses to fulfill it.\n// HTTP: Forbidden (403); GRPC: PermissionDenied (7).\nerr = semerr.NewForbiddenError(err)\n\n// It indicates the user has sent too many requests in a given\n// amount of time.\n// HTTP: Too Many Requests (429); GRPC: ResourceExhausted (8).\nerr = semerr.NewTooManyRequestsError(err)\n\n// It indicates that the server is refusing to process\n// a request because the request content is larger than\n// the server \n// HTTP: Request Entity Too Large (413); GRPC: OutOfRange (11).\nerr = semerr.NewRequestEntityTooLargeError(err)\n\n// It indicates that the server does not support\n// the functionality required to fulfill the request.\n// HTTP: Not Implemented (501); GRPC: Unimplemented (12).\nerr = semerr.NewUnimplementedError(err)\n\n// It indicates that the server is not ready to handle\n// the request.\n// HTTP: Service Unavailable (503); GRPC: Unavailable (14).\nerr = semerr.NewServiceUnavailableError(err)\n\n// It indicates that the request has not been applied because\n// it lacks valid authentication credentials for the target\n// resource.\n// HTTP: Unauthorized (401); GRPC: Unauthenticated (16).\nerr = semerr.NewUnauthorizedError(err)\n```\n\n## Contributing\n\nPull requests are welcomed. If you want to add a new meaning error then\nedit the file\n[internal/cmd/generator/errors.yaml](internal/cmd/generator/errors.yaml)\nand generate a new code, for this run `make`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhedhyw%2Fsemerr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhedhyw%2Fsemerr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhedhyw%2Fsemerr/lists"}