Skip to content

Commit

Permalink
Next generation (big PR) (#4)
Browse files Browse the repository at this point in the history
* wip

* big commit (wip)

* Spring API meeting 2 progress

https: //github.com/acmcsufoss/i/issues/18
Co-Authored-By: Akanksh Jagadish <[email protected]>
Co-Authored-By: John Carlo Manuel <[email protected]>

---------

Co-authored-by: Akanksh Jagadish <[email protected]>
Co-authored-by: John Carlo Manuel <[email protected]>
  • Loading branch information
3 people authored Feb 21, 2024
1 parent 7586c34 commit 889a0ff
Show file tree
Hide file tree
Showing 16 changed files with 992 additions and 0 deletions.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,33 @@
# api.acmcsuf.com

ACM at CSUF club API for managing events, announcements, forms, and other services!

## Develop

### Start API server

```sh
go run cmd/api/main.go
```

### Generate code

```sh
go generate ./...
```

### Run tests

```sh
go test ./...
```

### Format code

```sh
go fmt ./...
```

---

Developed with 💚 by [**@acmcsufoss**](https://github.com/acmcsufoss)
80 changes: 80 additions & 0 deletions cmd/api/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package main

import (
"context"
"database/sql"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"

"github.com/acmcsufoss/api.acmcsuf.com/internal/api"
"github.com/acmcsufoss/api.acmcsuf.com/internal/db/sqlite"
)

func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// Set up signal handling for graceful shutdown.
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)
go func() {
<-signalChan
log.Println("Shutting down the server...")
cancel()
}()

// Set up the database connection.
uri, ok := os.LookupEnv("DATABASE_URL")
if !ok {
log.Fatal("DATABASE_URL must be set")
}

d, err := sql.Open("sqlite", uri)
if err != nil {
log.Fatalf("Error opening SQLite database: %v", err)
}

// if err := sqlite.Migrate(ctx, db); err != nil {
// return nil, errors.Wrap(err, "cannot migrate sqlite db")
// }
//
// return sqliteStore{
// q: sqlite.New(db),
// db: db,
// ctx: ctx,
// }, nil

q := sqlite.New(d)
if err != nil {
log.Fatalf("Error creating SQLite store: %v", err)
}
defer func() {
if err := d.Close(); err != nil {
log.Fatalf("Error closing SQLite store: %v", err)
}
}()

// Initialize and start the HTTP server.
handler := api.New(q)
port, ok := os.LookupEnv("PORT")
if !ok {
port = "8080"
}

serverAddr := fmt.Sprintf(":%s", port)
go func() {
fmt.Printf("Server started on http://127.0.0.1%s\n", serverAddr)
if err := http.ListenAndServe(serverAddr, handler); err != nil && err != http.ErrServerClosed {
log.Fatal(err)
}
}()

// Wait for shutdown signal.
<-ctx.Done()

log.Println("Server shut down.")
}
22 changes: 22 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module github.com/acmcsufoss/api.acmcsuf.com

go 1.21.3

require (
github.com/pkg/errors v0.9.1
github.com/swaggest/openapi-go v0.2.45
github.com/swaggest/rest v0.2.61
github.com/swaggest/swgui v1.8.0
github.com/swaggest/usecase v1.3.1
)

require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/go-chi/chi/v5 v5.0.10 // indirect
github.com/santhosh-tekuri/jsonschema/v3 v3.1.0 // indirect
github.com/swaggest/form/v5 v5.1.1 // indirect
github.com/swaggest/jsonschema-go v0.3.64 // indirect
github.com/swaggest/refl v1.3.0 // indirect
github.com/vearutop/statigz v1.4.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
57 changes: 57 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/bool64/dev v0.2.25/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/dev v0.2.32 h1:DRZtloaoH1Igky3zphaUHV9+SLIV2H3lsf78JsJHFg0=
github.com/bool64/dev v0.2.32/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E=
github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc=
github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/santhosh-tekuri/jsonschema/v3 v3.1.0 h1:levPcBfnazlA1CyCMC3asL/QLZkq9pa8tQZOH513zQw=
github.com/santhosh-tekuri/jsonschema/v3 v3.1.0/go.mod h1:8kzK2TC0k0YjOForaAHdNEa7ik0fokNa2k30BKJ/W7Y=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ=
github.com/swaggest/assertjson v1.9.0/go.mod h1:b+ZKX2VRiUjxfUIal0HDN85W0nHPAYUbYH5WkkSsFsU=
github.com/swaggest/form/v5 v5.1.1 h1:ct6/rOQBGrqWUQ0FUv3vW5sHvTUb31AwTUWj947N6cY=
github.com/swaggest/form/v5 v5.1.1/go.mod h1:X1hraaoONee20PMnGNLQpO32f9zbQ0Czfm7iZThuEKg=
github.com/swaggest/jsonschema-go v0.3.64 h1:HyB41fkA4XP0BZkqWfGap5i2JtRHQGXG/21dGDPbyLM=
github.com/swaggest/jsonschema-go v0.3.64/go.mod h1:DYuKqdpms/edvywsX6p1zHXCZkdwB28wRaBdFCe3Duw=
github.com/swaggest/openapi-go v0.2.45 h1:LOMAEleKVLg4E86lSCyioJK7ltjWRx50AaP4LZIbJ+Q=
github.com/swaggest/openapi-go v0.2.45/go.mod h1:/ykzNtS1ZO7X43OnEtyisMktxCiawQLyGd08rkjV68U=
github.com/swaggest/refl v1.3.0 h1:PEUWIku+ZznYfsoyheF97ypSduvMApYyGkYF3nabS0I=
github.com/swaggest/refl v1.3.0/go.mod h1:3Ujvbmh1pfSbDYjC6JGG7nMgPvpG0ehQL4iNonnLNbg=
github.com/swaggest/rest v0.2.61 h1:K2cc3yGTX5i6dkxszS8lH9DmRlqDRl2XWaRxxBpP/Jk=
github.com/swaggest/rest v0.2.61/go.mod h1:nQGcwz5pD3LGxMXAz0swBTSFHxAWgAh3QnMh7Q4lRvo=
github.com/swaggest/swgui v1.8.0 h1:dPu8TsYIOraaObAkyNdoiLI8mu7nOqQ6SU7HOv254rM=
github.com/swaggest/swgui v1.8.0/go.mod h1:YBaAVAwS3ndfvdtW8A4yWDJpge+W57y+8kW+f/DqZtU=
github.com/swaggest/usecase v1.3.1 h1:JdKV30MTSsDxAXxkldLNcEn8O2uf565khyo6gr5sS+w=
github.com/swaggest/usecase v1.3.1/go.mod h1:cae3lDd5VDmM36OQcOOOdAlEDg40TiQYIp99S9ejWqA=
github.com/vearutop/statigz v1.4.0 h1:RQL0KG3j/uyA/PFpHeZ/L6l2ta920/MxlOAIGEOuwmU=
github.com/vearutop/statigz v1.4.0/go.mod h1:LYTolBLiz9oJISwiVKnOQoIwhO1LWX1A7OECawGS8XE=
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
51 changes: 51 additions & 0 deletions internal/api/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package api

import (
"github.com/swaggest/openapi-go/openapi3"
"github.com/swaggest/rest/response/gzip"
"github.com/swaggest/rest/web"
swgui "github.com/swaggest/swgui/v5emb"

"github.com/acmcsufoss/api.acmcsuf.com/internal/api/services"
"github.com/acmcsufoss/api.acmcsuf.com/internal/api/services/events"
"github.com/acmcsufoss/api.acmcsuf.com/internal/api/services/resources"
"github.com/acmcsufoss/api.acmcsuf.com/internal/db/sqlite"
)

func New(q *sqlite.Queries) *web.Service {
s := web.NewService(openapi3.NewReflector())

// Init API documentation schema.
s.OpenAPISchema().SetTitle("Basic Example")
s.OpenAPISchema().SetDescription("This app showcases a trivial REST API.")
s.OpenAPISchema().SetVersion("v0.0.1")

// Setup middlewares.
s.Wrap(
gzip.Middleware, // Response compression with support for direct gzip pass through.
)

// Add use case handler to router.
// s.Get("/hello/{name}", helloWorld())
useAll(s, q)

// Swagger UI endpoint at /docs.
s.Docs("/docs", swgui.New)

return s
}

func useAll(s *web.Service, q *sqlite.Queries) {
use("/resources", resources.New(q), s)
use("/events", events.New(q), s)
}

func use(path string, s services.Service, ss *web.Service) {
ss.Get(path, s.Resources())
ss.Post(path, s.PostResources())
ss.Post(path, s.BatchPostResources())
ss.Get(path+"/{id}", s.Resource())
ss.Post(path+"/{id}", s.PostResource())
ss.Post(path+"/{id}", s.BatchPostResource())
ss.Delete(path+"/{id}", s.DeleteResource())
}
47 changes: 47 additions & 0 deletions internal/api/services/events/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package events

import (
"github.com/swaggest/usecase"

"github.com/acmcsufoss/api.acmcsuf.com/internal/api/services"
"github.com/acmcsufoss/api.acmcsuf.com/internal/db/sqlite"
)

var _ services.Service = EventsService{}

type EventsService struct {
q *sqlite.Queries
}

func New(q *sqlite.Queries) *EventsService {
return &EventsService{q}
}

func (s EventsService) Resources() usecase.IOInteractor {
panic("implement me")
// s.q.GetResourceList(context.TODO(), "")
}

func (s EventsService) PostResources() usecase.IOInteractor {
panic("implement me")
}

func (s EventsService) BatchPostResources() usecase.IOInteractor {
panic("implement me")
}

func (s EventsService) Resource() usecase.IOInteractor {
panic("implement me")
}

func (s EventsService) PostResource() usecase.IOInteractor {
panic("implement me")
}

func (s EventsService) BatchPostResource() usecase.IOInteractor {
panic("implement me")
}

func (s EventsService) DeleteResource() usecase.IOInteractor {
panic("implement me")
}
29 changes: 29 additions & 0 deletions internal/api/services/interfaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package services

import (
"github.com/swaggest/usecase"
)

// Service is the interface of API endpoints for a resource service.
type Service interface {
// Resources gets a list of paginated resource resources.
Resources() usecase.IOInteractor

// PostResources creates a new resource resource.
PostResources() usecase.IOInteractor

// BatchPostResources creates multiple new resource resources.
BatchPostResources() usecase.IOInteractor

// Resource gets a single resource resource.
Resource() usecase.IOInteractor

// PostResource creates a new resource resource.
PostResource() usecase.IOInteractor

// BatchPostResource creates multiple new resource resources.
BatchPostResource() usecase.IOInteractor

// DeleteResource deletes a single resource resource.
DeleteResource() usecase.IOInteractor
}
Loading

0 comments on commit 889a0ff

Please sign in to comment.