Goxgen
Create your project based on GraphQL SDL
Install / Use
/learn @goxgen/GoxgenREADME
goxgen
Your One-Stop Solution for GraphQL Application Generation
<p style="text-align: center"> <img src="docs/images/logo.png" width="200px" alt=""> </p>goxgen is a powerful library designed to simplify the creation of GraphQL applications. By defining your domain and API interface through a single syntax, You can quickly generate a fully-functional GraphQL server. Beyond that, goxgen also provides support for ORM(GORM) and a Command-Line Interface for server operations.
Built upon the
gqlgenframework,goxgenextends its capabilities to offer a more streamlined developer experience.
🌟 Features
- 📝 Single Syntax for Domain and API: Define your domain and API interface in GraphQL schema language.
- 📊 GraphQL: Schema-based application generation
- 🎛️ ORM Support: Seamlessly integrates with various ORM systems like GORM and ENT.
- ⚙️ CLI Support: Comes with a CLI tool to spin up your server application in no time.
- 📚 Domain Driven Design: Extensible project structure
- 🛡️ Future-Ready: Plans to roll out UI for admin back-office, along with comprehensive authentication and authorization features.
Schema definition
goxgen using a directives for business logic and domain definition.
All schema files in xgen has this format schema.{some_name}.graphql, for example schema.user.graphql
Resource directives
Resource directives is a main directives for domain resource definition.
@Resource- Your domain resource@Field- Field of resource
Action Directives
@Action- Action that can be done for single resource@ListAction- Action that can be done for bulk resources@ActionField- Field of action or list action
🚀 Quick Start
👣 Step-by-step guide
📄 Creating the necessary files
You should create two files in your project
- Standard
gen.gofile withgo:generatedirectivepackage main //go:generate go run -mod=mod github.com/goxgen/goxgen - Xgen config file
xgenc.go//go:build ignore // +build ignore package main import ( "context" "fmt" "github.com/goxgen/goxgen/plugins/cli" "github.com/goxgen/goxgen/projects/basic" "github.com/goxgen/goxgen/projects/gorm" "github.com/goxgen/goxgen/xgen" ) func main() { xg := xgen.NewXgen( xgen.WithPackageName("github.com/goxgen/goxgen/cmd/internal/integration"), xgen.WithProject( "myproject", basic.NewProject(), ), xgen.WithProject( "gorm_advanced", gorm.NewProject( gorm.WithBasicProjectOption(basic.WithTestDir("tests")), ), ), xgen.WithProject( "gorm_example", gorm.NewProject( gorm.WithBasicProjectOption(basic.WithTestDir("tests")), ), ), xgen.WithPlugin(cli.NewPlugin()), ) err := xg.Generate(context.Background()) if err != nil { fmt.Println(err) } }
Then run go generate command, and goxgen will generate project structure
go generate
📁 Structure of a generated project
After running go generate command, goxgen will generate project structure like this
├── gorm_advanced
│ ├── generated
│ │ ├── server
│ │ ├── generated_gqlgen.go
│ │ ├── generated_gqlgen_models.go
│ │ ├── generated_xgen_directives.graphql
│ │ ├── generated_xgen_gorm.go
│ │ ├── generated_xgen_introspection.go
│ │ ├── generated_xgen_introspection.graphql
│ │ ├── generated_xgen_mappers.go
│ │ └── generated_xgen_sortable.go
│ ├── tests
│ │ ├── default-tests.yaml
│ │ ├── user-lifecycle.yaml
│ │ └── user-pagination.yaml
│ ├── graphql.config.yml
│ ├── resolver.go
│ ├── schema.main.graphql
│ └── schema.resolver.go
├── gorm_example
│ ├── generated
│ │ ├── server
│ │ ├── generated_gqlgen.go
│ │ ├── generated_gqlgen_models.go
│ │ ├── generated_xgen_directives.graphql
│ │ ├── generated_xgen_gorm.go
│ │ ├── generated_xgen_introspection.go
│ │ ├── generated_xgen_introspection.graphql
│ │ ├── generated_xgen_mappers.go
│ │ └── generated_xgen_sortable.go
│ ├── tests
│ │ ├── default-tests.yaml
│ │ └── user-lifecycle.yaml
│ ├── graphql.config.yml
│ ├── resolver.go
│ ├── schema.phone.graphql
│ ├── schema.resolver.go
│ └── schema.user.graphql
├── myproject
│ ├── generated
│ │ ├── server
│ │ ├── generated_gqlgen.go
│ │ ├── generated_gqlgen_models.go
│ │ ├── generated_xgen_directives.graphql
│ │ ├── generated_xgen_introspection.go
│ │ ├── generated_xgen_introspection.graphql
│ │ ├── generated_xgen_mappers.go
│ │ └── generated_xgen_sortable.go
│ ├── tests
│ │ └── default-tests.yaml
│ ├── graphql.config.yml
│ ├── resolver.go
│ ├── schema.main.graphql
│ ├── schema.resolver.go
│ ├── schema.todo.graphql
│ └── schema.users.graphql
├── .env
├── .env.default
├── .gitignore
├── gen.go
├── generated_xgen_cli.go
├── gorm_advanced.db
├── gorm_example.db
├── gormproj.db
└── xgenc.go
Note:
generateddirectories can be ignored in git. But you can add it to git if you want.
📑 Providing schema
Check the schema definition section for more information.
You should provide a schema for each project and run go generate again.
Gorm example
Let's focus on gorm_example, which uses the GORM ORM.
The connection to the GORM database can be configured from the gqlgen standard resolver.go file in the gorm_example directory.
resolver.gois designed to support your custom dependency injection (DI) and any services you've provided.
package gorm_example
import (
"github.com/goxgen/goxgen/cmd/internal/integration/gorm_example/generated"
"github.com/goxgen/goxgen/plugins/cli/settings"
"gorm.io/gorm"
"embed"
"fmt"
)
//go:embed tests/*
var TestsFS embed.FS
type Resolver struct {
DB *gorm.DB
}
func NewResolver(sts *settings.EnvironmentSettings) (*Resolver, error) {
r := &Resolver{}
db, err := generated.NewGormDB(sts)
if err != nil {
return nil, fmt.Errorf("failed to create gorm db: %w", err)
}
r.DB = db
return r, nil
}
Creating a example schema for resources
schema.user.graphql
# Define the User resource(entity) and its fields
# Enable DB mapping for the resource
type User
@Resource(Name: "user", DB: {Table: "user"})
{
id: ID! @Field(Label: "ID", DB: {Column: "id", PrimaryKey: true})
name: String! @Field(Label: "Text", DB: {Column: "name", Unique: true})
phoneNumbers: [Phone!]! @Field(Label: "Phone Numbers", DB: {})
}
# User input type for create and update actions
# Define the actions for the resource
input UserInput
@Action(Resource: "user", Action: CREATE_MUTATION, Route: "new")
@Action(Resource: "user", Action: UPDATE_MUTATION, Route: "update")
{
id: ID @ActionField(Label: "ID", MapTo: ["User.ID"])
name: String @ActionField(Label: "Name", MapTo: ["User.Name"])
phones: [PhoneNumberInput!] @ActionField(Label: "Phone Numbers", MapTo: ["User.PhoneNumbers"])
}
# User input type for browse action
input BrowseUserInput
@ListAction(Resource: "user", Action: BROWSE_QUERY, Route: "list", Pagination: true, Sort: {Default: [{by: "name", direction: ASC}]})
{
id: ID @ActionField(Label: "ID", MapTo: ["User.ID"])
name: String @ActionField(Label: "Name", MapTo: ["User.Name"])
}
schema.phone.graphql
type Phone
@Resource(Name: "phone_number", DB: {Table: "phone_number"})
{
id: ID! @Field(Label: "ID", DB: {Column: "id", PrimaryKey: true})
number: String! @Field(Label: "Number", DB: {Column: "number"})
user: User! @Field(Label: "User", DB: {})
}
input PhoneNumberInput
@Action(Resource: "phone_number", Action: CREATE_MUTATION, Route: "new")
@Action(Resource: "phone_number", Action: UPDATE_MUTATION, Route: "update")
{
id: ID @ActionField(Label: "ID", MapTo: ["Phone.ID"])
number: String @ActionField(Label: "Name", MapTo: ["Phone.Number"])
user: UserInput @ActionField(Label: "User", MapTo: ["Phone.User"])
}
After writing a custom schema You should run again gogen command.
go generate
After regenerating the code, the schema.resolver.go file will be updated based on your schema.
You can find the resolver functions for each field in the schema.resolver.go file.
"Create User" mutation resolver
func (r *mutationResolver) UserCreate(ctx context.Context, input *generated.UserInput) (*generated.User, error) {
u, err := input.ToUserModel(ctx)
if err != nil {
return nil, err
}
res := r.DB.Preload(clause.Associations).Create(u)
if res.Error != nil {
return nil, res.Error
}
return u, nil
}
"Browse User" query resolver
func (r *queryResolver) UserBrowse(ctx context.Context, where *generated.BrowseUserInput, pagination *generated.XgenPaginationInput, sort *generated.UserSortInput) ([]*generated.User, error) {
var users []*generated.User
u, err := where.ToUserModel(ctx)
if err != nil {
return nil, err
}
res := r.DB.
Preload(clause.Associations).
Scopes(
generated.Paginate(pagination), // passing `pagination` to the xgen `generated.Paginate` scope
generated.Sort(sort), // passing `sort` to the xgen `generated.Sort` scope
).
Where(&[]*generated.User{u}).
Find(&user
Related Skills
node-connect
342.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
xurl
342.0kA CLI tool for making authenticated requests to the X (Twitter) API. Use this skill when you need to post tweets, reply, quote, search, read posts, manage followers, send DMs, upload media, or interact with any X API v2 endpoint.
frontend-design
84.7kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
342.0kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
