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" within Ent), and all of the mutation side-effects (called "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!
The final version of the code below can be found on GitHub.
Start by creating a new Go project:
Invoke the ent code generator and create two schemas: User, Pet:
Your project should now look like this:
Next, add the
elk package to our project:
elk uses the
Ent extension API to
integrate with Ent’s code-generation. This requires that we use the
entc (ent codegen) package as
described here. Follow the next three steps to enable it and to
configure Ent to work with the
1. Create a new Go file named
ent/entc.go and paste the following content:
2. Edit the
ent/generate.go file to execute the
elk uses some external packages in its generated code. Currently, you have to get those packages manually once
when setting up
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.
Generating HTTP CRUD Handlers with
To generate the fully-working HTTP handlers we need first create an Ent schema definition. Open and
We added two fields to our
ent.Schema just defines the fields of our entity. To
generate runnable code from our schema, run:
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:
Next, let’s see how to create an actual RESTful HTTP server that can manage your Pet entities. Create a file
main.go and add the following content:
Next, start the server:
Congratulations! We now have a running server serving the Pets API. We could ask the server for a list of all pets in the database, but there are none yet. Let’s create one first:
You should get this response:
If you head over to the terminal where the server is running you can also see
elks built in logging:
elk uses zap for logging. To learn more about it, have a look at its documentation.
To illustrate more of
elks features, let’s extend our graph. Edit
We have now created a One-To-Many relation between the Pet and User schemas: A pet belongs to a user, and a user can have multiple pets.
Rerun the code generator:
Do not forget to register the
UserHandler on our router. Just add the following lines to
After restarting the server we can create a
User that owns the previously created Pet named Kuro:
The server returns the following response:
From the output we can see that the user has been created, but the edges are empty.
elk does not include edges in its
output by default. You can configure
elk to render edges using a feature called "serialization groups". Annotate your
schemas with the
elk.Annotation structs. Edit
ent/schema/user.go and add those:
elk.Annotations added to the fields and edges tell elk to eager-load them and add them to the payload if the "
user" group is requested. The
elk.SchemaAnnotation is used to make the read-operation of the
UserHandler request "
user". Note, that any fields that do not have a serialization group attached are included by default. Edges, however,
are excluded, unless configured otherwise.
Next, let’s regenerate the code once again, and restart the server. You should now see the pets of a user rendered if you read a resource:
Our current schemas allow to set a negative age for pets or users and we can create pets without an owner (as we did
with Kuro). Ent has built-in support for basic validation. In some
cases you may want to validate requests made against your API before passing their payload to Ent.
uses this package to define validation rules and validate data. We can
create separate validation rules for Create and Update operations using
elk.Annotation. In our example, let’s assume
that we want our Pet schema to only allow ages greater than zero and to disallow creating a pet without an owner.
Next, regenerate the code and restart the server. To test our new validation rules, let’s try to create a pet with invalid age and without an owner:
elk returns a detailed response that includes information about which validations failed:
Note the uppercase field names. The validator package uses the structs field name to generate its validation errors, but you can simply override this, as stated in the example .
If you do not define any validation rules,
elk will not include the validation-code in its generated output.
request validation is especially useful if you'd wanted to do cross-field-validation.
We hope you agree that
elk has some useful features already, but there are still many exciting things to come. The
next version of
elk will include::
- Fully working flutter frontend to administrate your nodes
- Integration of Ent’s validation in the current request validator
- More transport formats (currently only JSON)
This post has shown just a small part of what
elk can do. To see some more examples of what you can do with it, head
over to the project’s README on GitHub. I hope that with
elk-powered Ent, you and your fellow developers can automate
some repetitive tasks that go into building RESTful APIs and focus on more meaningful work.
elk is in an early stage of development, we welcome any suggestion or feedback and if you are willing to help we'd be
very glad. The GitHub Issues is a wonderful place for you to reach out for
help, feedback, suggestions and contribution.
MasseElch is a software engineer from the windy, flat, north of Germany. When not hiking with his dog Kuro (who has his own Instagram channel 😱) or playing hide-and-seek with his son, he drinks coffee and enjoys coding.