--- title: Generate a fully-working Go CRUD HTTP API with Ent author: MasseElch authorURL: "https://github.com/masseelch" authorImageURL: "https://avatars.githubusercontent.com/u/12862103?v=4" --- When we say that one of the core principles of Ent is "Schema as Code", we mean by that more than "Ent's DSL for defining entities and their edges is done using regular Go code". Ent's unique approach, compared to many other ORMs, is to express all of the logic related to an entity, as code, directly in the schema definition. With Ent, developers can write all authorization logic (called "[Privacy](https://entgo.io/docs/privacy)" within Ent), and all of the mutation side-effects (called "[Hooks](https://entgo.io/docs/hooks)" within Ent) directly on the schema. Having everything in the same place can be very convenient, but its true power is revealed when paired with code generation. If schemas are defined this way, it becomes possible to generate code for fully-working production-grade servers automatically. If we move the responsibility for authorization decisions and custom side effects from the RPC layer to the data layer, the implementation of the basic CRUD (Create, Read, Update and Delete) endpoints becomes generic to the extent that it can be machine-generated. This is exactly the idea behind the popular GraphQL and gRPC Ent extensions. Today, we would like to present a new Ent extension named `elk` that can automatically generate fully-working, RESTful API endpoints from your Ent schemas. `elk` strives to automate all of the tedious work of setting up the basic CRUD endpoints for every entity you add to your graph, including logging, validation of the request body, eager loading relations and serializing, all while leaving reflection out of sight and maintaining type-safety. Let’s get started! ### Getting Started The final version of the code below can be found on [GitHub](https://github.com/masseelch/elk-example). Start by creating a new Go project: ```shell mkdir elk-example cd elk-example go mod init elk-example ``` Invoke the ent code generator and create two schemas: User, Pet: ```shell go run -mod=mod entgo.io/ent/cmd/ent new Pet User ``` Your project should now look like this: ``` . ├── ent │ ├── generate.go │ └── schema │ ├── pet.go │ └── user.go ├── go.mod └── go.sum ``` Next, add the `elk` package to our project: ```shell go get -u github.com/masseelch/elk ``` `elk` uses the Ent [extension API](https://github.com/ent/ent/blob/a19a89a141cf1a5e1b38c93d7898f218a1f86c94/entc/entc.go#L197) to integrate with Ent’s code-generation. This requires that we use the `entc` (ent codegen) package as described [here](https://entgo.io/docs/code-gen#use-entc-as-a-package). Follow the next three steps to enable it and to configure Ent to work with the `elk` extension: 1\. Create a new Go file named `ent/entc.go` and paste the following content: ```go // +build ignore package main import ( "log" "entgo.io/ent/entc" "entgo.io/ent/entc/gen" "github.com/masseelch/elk" ) func main() { ex, err := elk.NewExtension( elk.GenerateSpec("openapi.json"), elk.GenerateHandlers(), ) if err != nil { log.Fatalf("creating elk extension: %v", err) } err = entc.Generate("./schema", &gen.Config{}, entc.Extensions(ex)) if err != nil { log.Fatalf("running ent codegen: %v", err) } } ``` 2\. Edit the `ent/generate.go` file to execute the `ent/entc.go` file: ```go package ent //go:generate go run -mod=mod entc.go ``` 3/. `elk` uses some external packages in its generated code. Currently, you have to get those packages manually once when setting up `elk`: ```shell go get github.com/mailru/easyjson github.com/masseelch/render github.com/go-chi/chi/v5 go.uber.org/zap ``` With these steps complete, all is set up for using our `elk`-powered ent! To learn more about Ent, how to connect to different types of databases, run migrations or work with entities head over to the [Setup Tutorial](https://entgo.io/docs/tutorial-setup/). ### Generating HTTP CRUD Handlers with `elk` To generate the fully-working HTTP handlers we need first create an Ent schema definition. Open and edit `ent/schema/pet.go`: ```go package schema import ( "entgo.io/ent" "entgo.io/ent/schema/field" ) // Pet holds the schema definition for the Pet entity. type Pet struct { ent.Schema } // Fields of the Pet. func (Pet) Fields() []ent.Field { return []ent.Field{ field.String("name"), field.Int("age"), } } ``` We added two fields to our `Pet` entity: `name` and `age`. The `ent.Schema` just defines the fields of our entity. To generate runnable code from our schema, run: ```shell go generate ./... ``` Observe that in addition to the files Ent would normally generate, another directory named `ent/http` was created. These files were generated by the `elk` extension and contain the code for the generated HTTP handlers. For example, here is some of the generated code for a read-operation on the Pet entity: ```go const ( PetCreate Routes = 1 << iota PetRead PetUpdate PetDelete PetList PetRoutes = 1<