package main import ( "context" "database/sql" "encoding/json" "fmt" "time" "github.com/kataras/iris/v12" "github.com/kataras/iris/v12/x/errors" "github.com/kataras/iris/v12/x/sqlx" _ "github.com/lib/pq" ) const ( host = "localhost" port = 5432 user = "postgres" password = "admin!123" dbname = "test" ) func main() { app := iris.New() db := mustConnectDB() mustCreateExtensions(context.Background(), db) mustCreateTables(context.Background(), db) app.Post("/", insert(db)) app.Get("/", list(db)) app.Get("/{event_id:uuid}", getByID(db)) /* curl --location --request POST 'http://localhost:8080' \ --header 'Content-Type: application/json' \ --data-raw '{ "name": "second_test_event", "data": { "key": "value", "year": 2022 } }' curl --location --request GET 'http://localhost:8080' curl --location --request GET 'http://localhost:8080/4fc0363f-1d1f-4a43-8608-5ed266485645' */ app.Listen(":8080") } func mustConnectDB() *sql.DB { connString := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbname) db, err := sql.Open("postgres", connString) if err != nil { panic(err) } err = db.Ping() if err != nil { panic(err) } return db } func mustCreateExtensions(ctx context.Context, db *sql.DB) { query := `CREATE EXTENSION IF NOT EXISTS pgcrypto;` _, err := db.ExecContext(ctx, query) if err != nil { panic(err) } } func mustCreateTables(ctx context.Context, db *sql.DB) { query := `CREATE TABLE IF NOT EXISTS "events" ( "id" uuid PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamp(6) DEFAULT now(), "name" text COLLATE "pg_catalog"."default", "data" jsonb );` _, err := db.ExecContext(ctx, query) if err != nil { panic(err) } sqlx.Register("events", Event{}) } type Event struct { ID string `json:"id"` CreatedAt time.Time `json:"created_at"` Name string `json:"name"` Data json.RawMessage `json:"data"` Presenter string `db:"-" json:"-"` } func insertEvent(ctx context.Context, db *sql.DB, evt Event) (id string, err error) { query := `INSERT INTO events(name,data) VALUES($1,$2) RETURNING id;` err = db.QueryRowContext(ctx, query, evt.Name, evt.Data).Scan(&id) return } func listEvents(ctx context.Context, db *sql.DB) ([]Event, error) { list := make([]Event, 0) query := `SELECT * FROM events ORDER BY created_at;` rows, err := db.QueryContext(ctx, query) if err != nil { return nil, err } // Not required. See sqlx.DefaultSchema.AutoCloseRows field. // defer rows.Close() if err = sqlx.Bind(&list, rows); err != nil { return nil, err } return list, nil } func getEvent(ctx context.Context, db *sql.DB, id string) (evt Event, err error) { query := `SELECT * FROM events WHERE id = $1 LIMIT 1;` err = sqlx.Query(ctx, db, &evt, query, id) return // // Same as: // // rows, err := db.QueryContext(ctx, query, id) // if err != nil { // return Event{}, err // } // // var evt Event // err = sqlx.Bind(&evt, rows) // // return evt, err } func insert(db *sql.DB) iris.Handler { return func(ctx iris.Context) { var evt Event if err := ctx.ReadJSON(&evt); err != nil { errors.InvalidArgument.Details(ctx, "unable to read body", err.Error()) return } id, err := insertEvent(ctx, db, evt) if err != nil { errors.Internal.LogErr(ctx, err) return } ctx.JSON(iris.Map{"id": id}) } } func list(db *sql.DB) iris.Handler { return func(ctx iris.Context) { events, err := listEvents(ctx, db) if err != nil { errors.Internal.LogErr(ctx, err) return } ctx.JSON(events) } } func getByID(db *sql.DB) iris.Handler { return func(ctx iris.Context) { eventID := ctx.Params().Get("event_id") evt, err := getEvent(ctx, db, eventID) if err != nil { errors.Internal.LogErr(ctx, err) return } ctx.JSON(evt) } }