Skip to content

Commit

Permalink
Go Ent Commit Refs (#48)
Browse files Browse the repository at this point in the history
* Add commit refs for go ent

* update addtl refs

* Update based on commit sha

* Fix crawl issues

---------

Co-authored-by: Nikko Miu <nikko@miu.guru>
  • Loading branch information
nikkomiu and Nikko Miu authored Sep 13, 2024
1 parent 4603ec8 commit 59ead33
Show file tree
Hide file tree
Showing 19 changed files with 790 additions and 272 deletions.
2 changes: 2 additions & 0 deletions .vscode/ltex.dictionary.en-US.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ NOUVEAU
ExploitDB
keyslot
Keyslot
func
ent
2 changes: 1 addition & 1 deletion assets/css/highlight.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ table:hover .copy-button {
}

.highlight pre {
@apply overflow-x-auto whitespace-pre border border-fuchsia-900 px-4 py-3;
@apply overflow-x-auto overflow-y-hidden whitespace-pre border border-fuchsia-900 px-4 py-3;
}
4 changes: 2 additions & 2 deletions assets/js/action/code.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ function highlightLines(parent, addLines, remLines, isTableNum = false) {
elem = reparentCodeTableNumber(lineElems[l - 1]);
}

elem?.classList.add("bg-green-950/80", "text-green-500");
elem?.classList.add("bg-green-950/30", "text-green-500");
});

remLines.forEach((l) => {
Expand All @@ -95,7 +95,7 @@ function highlightLines(parent, addLines, remLines, isTableNum = false) {
elem.classList.add("text-red-500");
}

elem?.classList.add("bg-red-950/80", "text-red-500");
elem?.classList.add("bg-red-950/30", "text-red-500");
});
}

Expand Down
14 changes: 10 additions & 4 deletions content/guides/golang-graphql-ent/01-project-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ set up my remote, as well as commit and push my initial code.
git init .
```

{{< commit-ref repo="nikkomiu/gentql" sha="202d14dd3f05a8c643665f82fca49cd061ebd831" />}}

## Create the Root Command

Lets, start by creating `cmd/cmd.go` where we will define the root level command for the app.
This app will have multiple subcommands, so to make our lives a bit easier I'm going to use the
This app will have multiple sub-commands, so to make our lives a bit easier I'm going to use the
[cobra](https://github.com/spf13/cobra) package to manage commands, flags, autocomplete, help, etc.

```go {file="cmd/cmd.go"}
Expand Down Expand Up @@ -116,7 +118,7 @@ func runAPI(cmd *cobra.Command, args []string) error {

In this we created an `apiCmd` where the **Use** property is the name of the command you'll run in the CLI
and **Run** is the method we will use to execute the command if it's called.
Then in the `init()` method, we register the `apiCmd` with the `rootCmd` as a subcommand.
Then in the `init()` method, we register the `apiCmd` with the `rootCmd` as a sub-command.
Finally, we define the `runAPI() error` method where, for now, we will just print `hello api`.

## Initial main.go
Expand Down Expand Up @@ -149,10 +151,12 @@ We will end up coming back to this file to expand on why we create and pass the
Until that time, basically we just create a new `context.Context` passing it into our `cmd.Execute(context.Context) error`
method and handle any error that comes back by printing it out to the console and returning with a status of 1.

{{< commit-ref repo="nikkomiu/gentql" sha="903b150ed23eb6f9f471f495aa2eddb4c1654195" />}}

## Test our CLI

Since we are using Cobra, we get some useful things out of the box. We can run the app with our `api` subcommand now to
see the `fmt.Println()` that we put above since we registered this subcommand with the `rootCmd`:
Since we are using Cobra, we get some useful things out of the box. We can run the app with our `api` sub-command now to
see the `fmt.Println()` that we put above since we registered this sub-command with the `rootCmd`:

```bash
go run . api
Expand Down Expand Up @@ -234,6 +238,8 @@ Flags:
Use "gentql [command] --help" for more information about a command.
```

{{< commit-ref repo="nikkomiu/gentql" sha="a296fe4980a1ad52be4aa5809a82e1c10b27008c" />}}

## Conclusion

We now have our project set up using Cobra for managing the CLI parts of the app for us and are ready to start adding
Expand Down
52 changes: 42 additions & 10 deletions content/guides/golang-graphql-ent/02-gqlgen-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ that we have that file created we can add them to the `go.mod` by running:
go mod tidy
```

{{< commit-ref repo="nikkomiu/gentql" sha="a19a97599f243b6af71c0e8d34514b8156f86e95" />}}
{{< commit-ref repo="nikkomiu/gentql" sha="32316ad914b98b7e1ba2df13102519d7f478e493" />}}

## Initialize gqlgen

Expand Down Expand Up @@ -87,7 +87,7 @@ resolver:
layout: follow-schema
dir: gql
package: gql
filename_template: "{name}.resolvers.go"
filename_template: "{name}.go"
omit_template_comment: false

models:
Expand All @@ -104,8 +104,8 @@ models:
- github.com/99designs/gqlgen/graphql.Int32
```
I'm making a handful of changes that make it a little bit cleaner. This is all personal preference so don't feel like
you need to follow this:
I'm making a handful of changes that make it a bit cleaner. This is all personal preference so don't feel like you need
to follow this:
- I prefer all of my top-level packages to be three letters (`gql` in our case). It's not a requirement by any
means, it's just a convention that the community has tended to adopt.
Expand All @@ -126,9 +126,9 @@ type Query {
}
```

This file will contain all of the definitions that aren't tied to a specific resource and are generally used in many
of the schema files. For now though, we're just going to create the handler to [query](https://graphql.org/learn/queries/)
our GraphQL instance a "hello world" example.
This file will contain all the definitions that aren't tied to a specific resource and are generally used in many of the
schema files. For now though, we're just going to create the handler to [query](https://graphql.org/learn/queries/) our
GraphQL instance a "hello world" example.

Now that we've updated our schema file we can generate our code again:

Expand Down Expand Up @@ -170,7 +170,7 @@ gql/model/*_gen.go
gql/generated.go
```

{{< commit-ref repo="nikkomiu/gentql" sha="cb0d64bbeef6959e89939293e82a8208330405e9" />}}
{{< commit-ref repo="nikkomiu/gentql" sha="f053e4d38fc682d76d8c9e595f386ec11fefed69" />}}

## Create the Resolver

Expand Down Expand Up @@ -249,6 +249,8 @@ Since we added Chi for the HTTP router, we need to update our dependencies:
go mod tidy
```

{{< commit-ref repo="nikkomiu/gentql" sha="dddac1b450a88a33d50568011070e3848616a27a" />}}

## Testing our Endpoint

We can start our API now and test our `hello(name)` query. Run the following from your terminal:
Expand Down Expand Up @@ -284,9 +286,9 @@ This error is coming from our resolver method. When we generated our code there
for the `hello(name)`. Currently, this method is set to cause the app to `panic()` but the GraphQL server will properly
catch the panic within our resolver to keep it contained to just the single request.

Open the `gql/common.resolvers.go` file and update the `Hello(context.Context, string)` method:
Open the `gql/common.go` file and update the `Hello(context.Context, string)` method:

```go {file="gql/common.resolvers.go"}
```go {file="gql/common.go"}
// Hello is the resolver for the hello field.
func (r *queryResolver) Hello(ctx context.Context, name string) (string, error) {
return fmt.Sprintf("Hello, %s!", name), nil
Expand All @@ -304,6 +306,8 @@ and re-run the query in your browser to get back the response we were hoping for
}
```

{{< commit-ref repo="nikkomiu/gentql" sha="2e423fa3d1646c51ddaa281bedb7486e5d9a215e" />}}

## Adding Chi Middleware

Chi includes middleware with it. Some of them are useful to have enabled by default. Let's add them to our API now:
Expand Down Expand Up @@ -338,6 +342,34 @@ import (

{{</ callout >}}

{{< commit-ref repo="nikkomiu/gentql" sha="f668594ea774caba4d03cf4e496f6c60e1e8434f" />}}

## (Optional) Remove gqlgen Notice

If you notice, the `common.go` schema file contains a comment at the top which says that the file is auto generated.

```go {file="gql/common.go"}
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
// Code generated by github.com/99designs/gqlgen version v0.17.49
```

On GitHub this may cause the web-based diff viewer to see these files as auto-generated files that don't need review
when creating PRs. Since this isn't actually the case for these files, let's tell gqlgen to stop generating these
comments since they contain implementation logic for our resolvers. Add the following to the `gqlgen.yml`:

```yaml {file="gqlgen.yml"}
omit_gqlgen_file_notice: true
```

And regenerate the code:

```bash
go generate ./...
```

{{< commit-ref repo="nikkomiu/gentql" sha="0452d82bcbcfa6bbf6038aa0fd681ab423921e35" />}}

## Conclusion

You should now have your GraphQL API endpoints created and wired into your app CLI. We also explored how Go methods
Expand Down
45 changes: 33 additions & 12 deletions content/guides/golang-graphql-ent/03-ent-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ scaffolding our app to work with it. We can simply create our first entity using
go run -mod=mod entgo.io/ent/cmd/ent new Note
```

{{< callout type=warning >}}
You may get an error when generating this if your version of Go isn't up-to-date. If this is the case, update your Go
installation. If you're using Dev Containers, you'll need to update the version in the Dev Container `Dockerfile`:

```dockerfile {file=".devcontainer/Dockerfile",add_lines=1,rem_lines=2}
FROM golang:1.23-alpine
FROM golang:1.22-alpine
```

Make sure to use the version specified in the error and don't just update to `1.23`.

{{</ callout >}}

With our newly created schema file, we can update the fields for the `Note` schema in the `ent/schema/note.go` file:

```go {file="ent/schema/note.go"}
Expand All @@ -49,7 +62,7 @@ For our example `Note` schema we have:
- `createdAt` with a default value of `time.Now`
- `updatedAt` with a default value of `time.Now` and `time.Now` when the record is updated.

With this changed, we can now generate the database client as well as all of the model code needed to use our new schema.
With this changed, we can now generate the database client as well as all the model code needed to use our new schema.

## Generate Code

Expand All @@ -65,7 +78,7 @@ updating and deleting, and even migrating the schema for us when there are chang

## (Optional) Hide Generated File from VS Code

Generally, I don't care to see all of the generated files in my workspace so just like before with the gqlgen files, I'm
Generally, I don't care to see all the generated files in my workspace so just like before with the gqlgen files, I'm
going to hide them from my VS Code explorer.

Update the `files.exclude` in `.vscode/settings.json` to exclude the Ent generated files:
Expand Down Expand Up @@ -97,6 +110,8 @@ ent/*
!ent/schema/
```

{{< commit-ref repo="nikkomiu/gentql" sha="eb76dd0623b78df8d1180d36be4f47b67cb3e201" />}}

## Initialize Client

There are a bunch of ways that we can initialize the ent client and manage its lifecycle. For our app, we are going to
Expand Down Expand Up @@ -173,11 +188,13 @@ running:
go mod tidy
```
{{< commit-ref repo="nikkomiu/gentql" sha="016bc1c238f4afb792d623bd7999f6adabb4dba4" />}}
## Database Migrations
Since `ent` works against [T-SQL](https://en.wikipedia.org/wiki/Transact-SQL) databases, we will want to have support
for migrating our database schema when we modify the schema. To support this from the CLI of our app, we're going to
create a new Cobra subcommand in `cmd/migrate.go`:
create a new Cobra sub-command in `cmd/migrate.go`:

```go {file="cmd/migrate.go"}
package cmd
Expand Down Expand Up @@ -211,7 +228,7 @@ func runMigrate(cmd *cobra.Command, args []string) error {
}
```

This is similar to the API subcommand from a Cobra perspective. However, in the `runMigrate()` we just open the database
This is similar to the API sub-command from a Cobra perspective. However, in the `runMigrate()` we just open the database
client and call `Create()` on the schema. This will create or update the database schema based on what is currently in
the database.

Expand Down Expand Up @@ -259,7 +276,7 @@ func init() {
func runMigrate(cmd *cobra.Command, args []string) error {
dryRun, err := cmd.Flags().GetBool("dry")
if err != nil {
return
return err
}
entClient, err := ent.Open("postgres", os.Getenv("DATABASE_URL"))
Expand Down Expand Up @@ -302,18 +319,20 @@ Flags:
Also, because we set up the flag with a variable reference the variable will automatically be set when it is set by
someone using the CLI.

{{< commit-ref repo="nikkomiu/gentql" sha="4a4118b47551fa9fc20a95f1f80c63bbc385e972" />}}

## Perform First Migration

Now that we have the migration subcommand set up we need to migrate our database to the latest version so we can begin
Now that we have the migration sub-command set up we need to migrate our database to the latest version, so we can begin
to use the newly added Note schema:

```bash
go run . migrate
```

{{< callout type=note >}}
If you don't run the migrate before continuing you will get an error when trying to use the schema for the first time
in a later section. However, the error for this tends to be pretty verbose so you should get that you just need to run
If you don't run the `migrate` before continuing you will get an error when trying to use the schema for the first time
in a later section. However, the error for this tends to be pretty verbose, so you should get that you just need to run
migrations at that time.
{{</ callout >}}
Expand Down Expand Up @@ -374,25 +393,27 @@ generated files in the `.vscode/settings.json` to exclude them from the explorer
```json {file=".vscode/settings.json"}
"ent/{gql_*.go}": true,
"ent/{note/,note.go}": true
"ent/{note}{/,.go}": true
```
This part is generally following along with the [GraphQL Integration](https://entgo.io/docs/graphql) page of ent's
documentation. We will continue to advance past this initial setup document. However, it (along with the
[GraphQL Tutorial](https://entgo.io/docs/tutorial-todo-gql)) are great resources that will expand on what we are doing
here.

{{< commit-ref repo="nikkomiu/gentql" sha="fb673ea5409ea524951640004ea20b57c3207e72" />}}

## Conclusion

Now we should have `ent` set up for our app, the first schema defined, and database migrations working in the CLI.

{{< callout type=note >}}
I don't get into it much in this guide, however, `ent` is technically a graph database adapter. Having ent designed to
work with graph databases allows for some very intersting and complex graph traversals over our data to query for data
in an easy to use way.
work with graph databases allows for some very interesting and complex graph traversals over our data to query for data
in an easy-to-use way.
For more information on ent, take a look at [their documentation](https://entgo.io/docs/getting-started).
{{</ callout >}}
Next we're going to look at wiring `ent` to `gqlgen` so we don't have to manually manage the connection between the
Next we're going to look at wiring `ent` to `gqlgen`, so we don't have to manually manage the connection between the
ent and gqlgen models, as well as some other GraphQL concepts that are recommended.
Loading

0 comments on commit 59ead33

Please sign in to comment.