{"id":30523853,"url":"https://github.com/marcboeker/mega","last_synced_at":"2025-08-26T20:51:38.339Z","repository":{"id":62867390,"uuid":"451258781","full_name":"marcboeker/mega","owner":"marcboeker","description":"Go + Graphql + Ent + Echo Boilerplate","archived":false,"fork":false,"pushed_at":"2023-02-23T12:09:42.000Z","size":160,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-06-20T08:19:53.084Z","etag":null,"topics":["api","go","graphql","orm","rest"],"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/marcboeker.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":"2022-01-23T23:35:26.000Z","updated_at":"2024-04-16T06:08:52.000Z","dependencies_parsed_at":"2024-06-20T07:22:06.318Z","dependency_job_id":"3917998d-7240-4b57-a091-5599e4b36264","html_url":"https://github.com/marcboeker/mega","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/marcboeker/mega","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcboeker%2Fmega","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcboeker%2Fmega/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcboeker%2Fmega/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcboeker%2Fmega/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marcboeker","download_url":"https://codeload.github.com/marcboeker/mega/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcboeker%2Fmega/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272254475,"owners_count":24901049,"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-08-26T02:00:07.904Z","response_time":60,"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":["api","go","graphql","orm","rest"],"created_at":"2025-08-26T20:51:30.474Z","updated_at":"2025-08-26T20:51:38.321Z","avatar_url":"https://github.com/marcboeker.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Go + Graphql + Ent + Echo Boilerplate\n\nIt took me a while to figure out how I can use [GraphQL](https://github.com/99designs/gqlgen) with the [ent ORM](https://entgo.io/) and\nserve the GraphQL endpoint via the [Echo framework](https://echo.labstack.com/).\n\nI also wanted [proper configuration management](https://github.com/spf13/viper) and a clean structure for my\napplication logic. It also should be easily testable, because I only write tests if it's convenient.\n\nThat's why I came up with **Mega** which could stand for something like\n\"**M**erge **e**nt with **G**raphQL **a**wesomeness\" or \"**M**y **e**arliest **G**o **a**dventures\".\n\n## What's inside the box\n\n- Go (of course)\n- GraphQL via [gqlgen](https://github.com/99designs/gqlgen)\n- [ent](https://entgo.io/) as an ORM\n- [Echo web framework](https://echo.labstack.com/)\n- [Wire](https://github.com/google/wire) for dependency injection\n- [Viper](https://github.com/spf13/viper) for configuration management\n- [Testify](https://github.com/stretchr/testify) for making testing easy\n- [Make](https://www.gnu.org/software/make/manual/make.html) for automation\n\nThe challenge was to glue everything as modular as possible together to make replacing single components easy. I'm also not a fan of reflection, so the used libraries like ent, gqlgen, and Wire generate the necessary code instead. It adds little overhead, as you always have to run `make ent|graphql|wire` after each modification. But it adds a lot of type safety and makes developing so much easier.\n\n## Give me some structure\n\nOne of the advantages of Go is its flexibility when it comes to structuring your application. It could also be challenging and requires continuous refactoring as your application grows.\n\nI've worked on several web applications using Go in the past and tried a lot of different approaches. From throwing everything in one package (hey my PHP friends from the past) to making anything as modular as possible (waving over to the Java guys).\n\nI've tried [clean architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) and also domain-driven design. Both have pros and cons, but they felt too overkill for most of my Go projects. So I've ended up with the idea of encapsulating my application logic into small services that have a well-defined interface, are easily testable, and can be used with a variety of API frontends like REST, GraphQL, or gRPC.\n\n### Services to the rescue\n\nAll my application logic is contained in different [services](https://github.com/marcboeker/mega/tree/master/service). Each service provides an [interface](https://github.com/marcboeker/mega/tree/master/service/user/service.go) to describe its API. Each service should but must not contain a [test suite](https://github.com/marcboeker/mega/tree/master/service/user/service_test.go).\n\nIf you have a closer look at a service, you could see the following components:\n\n```\ntype Service interface {\n\tGet(ctx context.Context, id uuid.UUID) (*ent.User, error)\n\tCreate(ctx context.Context, user model.AddUserInput) (*ent.User, error)\n}\n```\n\nThe `Service` interface defines all the offered methods. It also helps to decouple your code if you reference via interfaces instead of specific types.\n\n```\ntype User struct {\n\tclient *db.Client\n}\n```\n\nThe `User` struct bundles all service methods together and contains the needed dependencies for the service. If you need to send emails, you could, for example, inject a mailer dependency that provides functionality to send mails.\n\n```\nfunc New(client *db.Client) Service {\n\treturn \u0026User{client: client}\n}\n```\n\nThe `New` method simply acts as an initializer.\n\n```\nfunc (s *User) Get(ctx context.Context, id uuid.UUID) (*ent.User, error) {\n\treturn s.client.User.Get(ctx, id)\n}\n```\n\nAnd last but not least, the `Get` method on the `User` struct is the actual application logic.\n\n## Getting started\n\nI've decided to use `make` for automating all the tasks. That's why all commands can be run via `make`.\n\n- `make ent` - Generates the required code from your defined models.\n- `make graphql` - Generates the GraphQL resolvers and models from the schema.\n- `make wire` - Generates the dependency injection code.\n- `make all` - Executes the `ent`, `graphql`, and `wire` task all together.\n- `make run` - Starts the web server.\n- `make test` - Executes all tests.\n\nAfter each modification of the GraphQL schema, the models or the dependency graph you need to run either `make ent|graphql|wire` or `make all`.\n\n### Defining your GraphQl schema\n\nThe schema is located under the `/graph/schema` directory. It contains two different types of files. The \"main\" schema in `schema.graphqls` contains common types like a `Timestamp`.\nAnd the service-specific schemas like `user.graphqls` contain the query and mutation definitions for the respective service.\nSplitting your schema into multiple files also makes it much easier to implement the resolvers later, as they only contain your service-specific queries and mutations and not those of the whole application.\n\n### Configuration\n\nAs I'm using Viper as configuration management, it is easy to have specific configurations for different environments. Just copy the `config.yaml` in the repository's root and adapt the setting for a different environment.\n\nThe default `make run` command takes the default config file named `config.yml` in the repo's root.\n\nTo use your own config file, simply supply the `-config mynewconfig.yml` argument to the `go run` command.\n\n`go run cmd/main.go -config dev.yml`\n\n### First steps\n\nIf you execute `make run`, it will start the server on http://127.0.0.1:8080. The default GraphQL query endpoint is under [127.0.0.1:8080/query](http://127.0.0.1:8080/query). There is also a GraphQL playground which is available via [127.0.0.1:8080/playground](http://127.0.0.1:8080/playground).\n\nTo insert your first user, simply run the following mutation:\n\n```\nmutation {\n  createUser(user: {name: \"Foo\", age: 10}) {\n    id,\n    createdAt\n  }\n}\n```\n\nIt will return the following response:\n\n```\n{\n  \"data\": {\n    \"createUser\": {\n      \"id\": \"da612c7d-494c-4164-9afc-d353c3e923cf\",\n      \"createdAt\": \"2022-01-24T00:09:11+01:00\"\n    }\n  }\n}\n```\n\nYou can see a new user with the ID `da612c7d-494c-4164-9afc-d353c3e923cf` is created.\n\nTo query for that user, you can use the following query:\n\n```\nquery {\n  user(id: \"39b066c7-4b34-4a41-9d21-0b55b16ff0eb\") {\n    id\n    createdAt\n  }\n}\n```\n\nAnd it returns the same response as the mutation above:\n\n```\n{\n  \"data\": {\n    \"user\": {\n      \"id\": \"39b066c7-4b34-4a41-9d21-0b55b16ff0eb\",\n      \"createdAt\": \"2022-01-24T00:17:02+01:00\"\n    }\n  }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcboeker%2Fmega","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcboeker%2Fmega","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcboeker%2Fmega/lists"}