ariga / ogent Goto Github PK
View Code? Open in Web Editor NEWEnt Extension to integrate ogen
Home Page: https://entgo.io/blog/2022/02/15/generate-rest-crud-with-ent-and-ogen/
License: Apache License 2.0
Ent Extension to integrate ogen
Home Page: https://entgo.io/blog/2022/02/15/generate-rest-crud-with-ent-and-ogen/
License: Apache License 2.0
Unable to start server with entities that have immutable fields.
Reproducible steps
Hi again,
According to the ent docs, you can override the id field to be something other than an int.
If you use a Field with just an id field, it fails to compile:
// Fields of the Model.
func (Model) Fields() []ent.Field {
return []ent.Field{
field.String("id"),
}
}
...
❯ go generate ./...
❯ go run -mod=mod main.go
# todo/ent/ogent
ent/ogent/ogent.go:31:61: undefined: CreateModelReq
ent/ogent/ogent.go:93:61: undefined: UpdateModelReq
If you add some other fields, it compiles, but POST fails:
func (Model) Fields() []ent.Field {
return []ent.Field{
field.String("id"),
field.Time("created_at").
Optional().
Default(time.Now),
field.String("name").
Optional(),
}
}
...
❯ curl -X POST http://localhost:8080/models -H "Content-Type: application/json" -d '{"id": "fdsa90fds-890fgs", "name": "test"}'
{"error_message":"NOT NULL constraint failed: models.id"}%
If I'm doing something wrong I apologise. If not, it would be great to get support for overriding IDs.
Any workaround in the meantime?
When I try to use Ogent with Enum , I am getting Errors.
I have hosted an example at https://github.com/chasak/enumeg
Here is part of schema file.
func (Video) Fields() []ent.Field {
return []ent.Field{
field.String("title"),
field.Enum("videotype").Values("live", "video", "playlist"),
}
}
This generates the following response
func NewGroupVideosList(e *ent.Video) *GroupVideosList {
if e == nil {
return nil
}
return &GroupVideosList{
ID: e.ID,
Title: e.Title,
Videotype: e.Videotype,
}
}
The error is on Videotype: e.Videotype,
line due to the mismatched types. Take a look at GroupVideosList
type GroupVideosList struct {
ID int "json:\"id\""
Title string "json:\"title\""
Videotype GroupVideosListVideotype "json:\"videotype\""
}
type GroupVideosListVideotype string
const (
GroupVideosListVideotypeLive GroupVideosListVideotype = "live"
GroupVideosListVideotypeVideo GroupVideosListVideotype = "video"
GroupVideosListVideotypePlaylist GroupVideosListVideotype = "playlist"
)
and ent.Video
type Video struct {
config `json:"-"`
// ID of the ent.
ID int `json:"id,omitempty"`
// Title holds the value of the "title" field.
Title string `json:"title,omitempty"`
// Videotype holds the value of the "videotype" field.
Videotype video.Videotype `json:"videotype,omitempty"`
// Edges holds the relations/edges for other nodes in the graph.
// The values are being populated by the VideoQuery when eager-loading is set.
Edges VideoEdges `json:"edges"`
group_videos *int
}
// Videotype defines the type for the "videotype" enum field.
type Videotype string
// Videotype values.
const (
VideotypeLive Videotype = "live"
VideotypeVideo Videotype = "video"
VideotypePlaylist Videotype = "playlist"
)
The error is happeing due to not doing explicit typecasting and can be solved by
Videotype: GroupVideosListVideotype(e.Videotype),
func NewGroupVideosList(e *ent.Video) *GroupVideosList {
if e == nil {
return nil
}
return &GroupVideosList{
ID: e.ID,
Title: e.Title,
Videotype: GroupVideosListVideotype(e.Videotype),
}
}
Same Issue with handler Function
func (h *OgentHandler) CreateVideo(ctx context.Context, req CreateVideoReq) (CreateVideoRes, error) {
b := h.client.Video.Create()
// Add all fields.
b.SetTitle(req.Title)
b.SetVideotype(req.Videotype)
}
also here
func (h *OgentHandler) UpdateVideo(ctx context.Context, req UpdateVideoReq, params UpdateVideoParams) (UpdateVideoRes, error) {
b := h.client.Video.UpdateOneID(params.ID)
// Add all fields.
if v, ok := req.Title.Get(); ok {
b.SetTitle(v)
}
if v, ok := req.Videotype.Get(); ok {
b.SetVideotype(v)
}
Thanks.
The go.mod lists 1.17.
However when I run this after following the README:
❯ go generate ./...
/Users/phil/go/pkg/mod/github.com/ogen-go/[email protected]/json/ip.go:4:2: package net/netip is not in GOROOT (/opt/homebrew/Cellar/go/1.17.6/libexec/src/net/netip)
ent/generate.go:3: running "go": exit status 1
It works fine with 1.18.
I'd tried to install ogent
as described in Getting started section of blog post.
$ go get entgo.io/contrib/entoas@master ariga.io/ogent@master
go: downloading entgo.io/contrib v0.2.1-0.20220218155233-55ffdd80c70b
go get ariga.io/ogent@master: unrecognized import path "ariga.io/ogent": parse https://ariga.io/ogent?go-get=1: no go-import meta tags ()
But it seems module path is wrong, it should be github.com/ariga/ogent@main
:
$ go get -v github.com/ariga/ogent@main
go: downloading github.com/ariga/ogent v0.0.0-20220217081816-c4d586fc1c16
...
I'm not sure if this is an ogent thing, or an ogen thing, however it would be nice if page
and itemsPerPage
were sanitized to be > 1
and < math.MaxInt32
, or handled as a bad request. Right now, if the integer for either is below 1, or above the maximum integer size, it will throw an error, which requires intercepting, validating which error it is, and responding accordingly. Because this would be required for every implementation using ogent
, feel like it should be implemented here.
It seems as though ogent generates a PATCH endpoint that clears all of the edges for the entity if they are not specified in the request body. For example, if you create a user
POST /users
{
"name": "Ankush Gola",
"phone_number": 123-456-7890,
"friends": [
1,
2,
3,
]
}
And then later update this user:
PATCH /users/1
{
"name": "Ankush Gola",
"phone_number": 098-765-4321,
}
The "friends" get deleted. I looked at the autogenerated code for the update endpoints, and it does seem like the edges are being cleared if they aren't specified. This did not happen with elk.
https://pkg.go.dev/github.com/ariga/ogent
Documentation not displayed due to license restrictions.
Is there an easy way to have a prefix added to all rest calls?
/endpoint
-> /prefix/endpoint
A schema I'm working with has a few ent fields of type Strings or Ints (an array in OAS). Right now, codegen baila with a confusing error that I've narrowed down to no support for these types.
Is that something you've just not got around to (in which case, shall I submit a PR once I have coded it) or is it a conscious decision for another reason?
Thanks in advance!
The OpenTelemetry configuration generates the following imports:
import (
"net/http"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/instrument/syncint64"
"go.opentelemetry.io/otel/trace"
ht "github.com/ogen-go/ogen/http"
"github.com/ogen-go/ogen/middleware"
"github.com/ogen-go/ogen/ogenerrors"
"github.com/ogen-go/ogen/otelogen"
)
The package go.opentelemetry.io/otel/metric/instrument/syncint64
, however, is deprecated: https://pkg.go.dev/go.opentelemetry.io/otel/metric/instrument/syncint64
Deprecated: Use the instruments provided by go.opentelemetry.io/otel/metric/instrument instead.
The package should be updated to remove this deprecated dependency.
It seems that fields that are nillable aren't supported. Are there any plans to support them in the future?
Ogen has different casing rules than ent/entoas. If you have a field with any of the following, generation will fail because the ent/entoas casing is different.
rules = [...]string{
"ACL", "API", "ASCII", "AWS", "CPU", "CSS", "DNS", "EOF", "GB", "GUID",
"HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "KB", "LHS", "MAC", "MB",
"QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SQL", "SSH", "SSO", "TLS",
"TTL", "UI", "UID", "URI", "URL", "UTF8", "UUID", "VM", "XML", "XMPP",
"XSRF", "XSS", "SMS", "CDN", "TCP", "UDP", "DC", "PFS", "P2P",
"SHA256", "SHA1", "MD5", "SRP", "2FA", "OAuth", "OAuth2",
"PNG", "JPG", "GIF", "MP4", "WEBP",
}
For instance, having a field called "md5" results in ret.Md5 = e.Md5
, but it should generate ret.MD5 = e.Md5
.
I looked for an easy way to convert a string to the ogen format, but it doesn't seem like there are any exported functions from ogen to apply the naming rules.
I am going to work around it by adding a lookup table in my fork, but I'm not sure if that is the full solution to the issue.
I'm not sure of your issue processes, so please let me know if I need to do something else/different.
Including the entoas.Skip(true)
annotation on a field or edge causes the generated handlers to not be able to compile:
# entdemo/ent/ogent
ent/ogent/ogent.go:35:20: req.Password undefined (type *CreateUserReq has no field or method Password)
ent/ogent/ogent.go:109:18: req.Password undefined (type *UpdateUserReq has no field or method Password)
ent/ogent/responses.go:14:6: ret.Password undefined (type UserCreate has no field or method Password)
ent/ogent/responses.go:43:6: ret.Password undefined (type UserList has no field or method Password)
ent/ogent/responses.go:72:6: ret.Password undefined (type UserRead has no field or method Password)
ent/ogent/responses.go:101:6: ret.Password undefined (type UserUpdate has no field or method Password)
ent/ogent/responses.go:130:6: ret.Password undefined (type UserChildrenList has no field or method Password)
ent/ogent/responses.go:159:6: ret.Password undefined (type UserParentRead has no field or method Password)
ent/ogent/responses.go:188:6: ret.Password undefined (type UserSecretChildrenList has no field or method Password)
ent/ogent/responses.go:217:6: ret.Password undefined (type UserSecretParentRead has no field or method Password)
ent/ogent/responses.go:217:6: too many errors
I have a branch on my fork that fixes this issue for ogent: https://github.com/swalkerhppr/ogent/tree/skip-fix
It fixes skipping fields, but skipping edges makes the resulting ogen server not fully implemented:
./main.go:24:29: cannot use ogent.NewOgentHandler(client) (value of type *ogent.OgentHandler) as ogent.Handler value in argument to ogent.NewServer: *ogent.OgentHandler does not implement ogent.Handler (missing method ListUserSecretChildren)
Which I believe is an entoas issue as the openapi.json schema still has secret_parent and secret_children in it. Further research is needed for that.
// ent/schema/user.go
package schema
import (
"entgo.io/contrib/entoas"
"entgo.io/ent"
"entgo.io/ent/schema/edge"
"entgo.io/ent/schema/field"
)
// User holds the schema definition for the User entity.
type User struct {
ent.Schema
}
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("username"),
field.String("password").
Annotations(
entoas.Skip(true), // Skip the "password" field
),
}
}
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("secret_children", User.Type).
Annotations(
entoas.Skip(true), // Skip the "secret_children" edge
).
From("secret_parent").
Unique().
Annotations(
entoas.Skip(true), // Skip the "secret_parent" edge
),
edge.To("children", User.Type).
From("parent").
Unique(),
}
}
// main.go
package main
import (
"context"
"log"
"net/http"
"ogent-test/ent"
"ogent-test/ent/ogent"
_ "github.com/mattn/go-sqlite3"
)
func main() {
client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
if err != nil {
log.Fatalf("failed opening connection to sqlite: %v", err)
}
defer client.Close()
if err := client.Schema.Create(context.Background()); err != nil {
log.Fatalf("failed creating schema resources: %v", err)
}
srv, _ := ogent.NewServer(ogent.NewOgentHandler(client))
log.Println("Starting server...")
if err := http.ListenAndServe(":8080", srv); err != nil {
log.Fatal(err)
}
}
go generate ./...
grep -ir "password\|secret" ent/ogent
should show no references to password, secret_children nor secret_parentgo run .
should work compile/runcurrently metric.NewNoopMeterProvider() changed to nonrecording.NewNoopMeterProvider().
undefined: metric.Int64Counter.
many errors in generated files in ogent directory.
In "ogent/ogent/helper/list/sub"
, subtemplates are called on $.Type
instead of $.Scope.Edge.Type
:
Line 18 in 493e109
It should be:
{{- template "ogent/ogent/helper/list/paginate" $.Scope.Edge.Type -}}
{{- if hasTemplate "ogent/ogent/helper/list/filter" }}{{ template "ogent/ogent/helper/list/filter" $.Scope.Edge.Type }}{{ end -}}
The current implementation makes it impossible to override the paginate
and filter
templates (without a workaround) when trying to use the actual type.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.