rework: change api prefix to /api/v7/
- add and test GetMembre - add `IsMembreID(string) bool` function BREAKING: Rename routes to `/api/v7/...` scheme
This commit is contained in:
parent
e847f693e0
commit
c7c64674c7
6 changed files with 212 additions and 45 deletions
17
client.go
17
client.go
|
@ -58,3 +58,20 @@ func (c APIClient) InsertMembres(membres ...Membre) (amountInserted int64, err e
|
||||||
|
|
||||||
return response.Data.MembresInserted, nil
|
return response.Data.MembresInserted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c APIClient) GetMembre(membreID string) (membre Membre, err error) {
|
||||||
|
var request MembreGETRequest
|
||||||
|
request.Param.MembreID = membreID
|
||||||
|
|
||||||
|
response, err := request.Request(c.Voki)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if code, message := response.StatusCode(), response.Message; code >= 400 {
|
||||||
|
err = fmt.Errorf("%d: %s", code, message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Data.Membre, nil
|
||||||
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ func TestAPI(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
//TODO create or replace schema
|
//TODO create or replace schema
|
||||||
|
|
||||||
t.Run("insert programmes",
|
t.Run("insert programmes",
|
||||||
func(t *testing.T) {
|
func(t *testing.T) {
|
||||||
programmes := []Programme{
|
programmes := []Programme{
|
||||||
|
@ -52,10 +53,8 @@ func TestAPI(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
//TODO insert membres
|
|
||||||
t.Run("insert membres",
|
testMembres := []Membre{
|
||||||
func(t *testing.T) {
|
|
||||||
membres := []Membre{
|
|
||||||
{
|
{
|
||||||
ID: "0000000",
|
ID: "0000000",
|
||||||
FirstName: "Test",
|
FirstName: "Test",
|
||||||
|
@ -70,13 +69,55 @@ func TestAPI(t *testing.T) {
|
||||||
ProgrammeID: "200.10",
|
ProgrammeID: "200.10",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err := apiClient.InsertMembres(membres...)
|
|
||||||
|
t.Run("insert membres",
|
||||||
|
func(t *testing.T) {
|
||||||
|
_, err := apiClient.InsertMembres(testMembres...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
//TODO get membre
|
|
||||||
//TODO update membre prefered name
|
|
||||||
//TODO get membres
|
|
||||||
|
|
||||||
|
t.Run("get membre",
|
||||||
|
func(t *testing.T) {
|
||||||
|
membre, err := apiClient.GetMembre(testMembres[0].ID)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
want := testMembres[0].LastName
|
||||||
|
got := membre.LastName
|
||||||
|
|
||||||
|
if want != got {
|
||||||
|
t.Errorf("want=%s got=%s", want, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("get invalid membre",
|
||||||
|
func(t *testing.T) {
|
||||||
|
_, err := apiClient.GetMembre("invalid")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("`invalid` should not have been accepted as value to GetMembre, but did")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//TODO update membre prefered name
|
||||||
|
/*
|
||||||
|
t.Run("",
|
||||||
|
func(t *testing.T) {
|
||||||
|
if err := apiClient.UpdateMembrePreferedName(testMembres[0].ID, "User, Galaxy"); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
//TODO get membres
|
||||||
|
/*
|
||||||
|
t.Run("get membres, max 50",
|
||||||
|
func(t *testing.T) {
|
||||||
|
membres, err := apiClient.GetMembres(50)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
45
db.go
45
db.go
|
@ -111,29 +111,42 @@ VALUES ($1, $2) ON CONFLICT DO NOTHING;`,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
func (d *PostgresClient) GetMembre(membreID string) (membre Membre, err error) {
|
||||||
func (d *PostgresClient) GetMembre(membreID string) (Membre, error) {
|
select {
|
||||||
var membre Membre
|
case <-d.Ctx.Done():
|
||||||
|
err = fmt.Errorf("PostgresClient.Ctx closed: %s", d.Ctx.Err())
|
||||||
rows, err := d.Pool.Queryx("SELECT * FROM membres WHERE id = $1 LIMIT 1;", membreID)
|
return
|
||||||
if err != nil {
|
default:
|
||||||
return membre, err
|
if err = d.Pool.QueryRow(d.Ctx, `
|
||||||
}
|
SELECT
|
||||||
|
"membres".id,
|
||||||
for rows.Next() {
|
"membres".last_name,
|
||||||
err := rows.StructScan(&membre)
|
"membres".first_name,
|
||||||
if err != nil {
|
"membres".prefered_name,
|
||||||
return membre, err
|
"membres".programme_id
|
||||||
}
|
FROM
|
||||||
|
"membres"
|
||||||
|
WHERE
|
||||||
|
"membres".id = $1
|
||||||
|
LIMIT
|
||||||
|
1;
|
||||||
|
`, membreID).Scan(
|
||||||
|
&membre.ID,
|
||||||
|
&membre.LastName,
|
||||||
|
&membre.FirstName,
|
||||||
|
&membre.PreferedName,
|
||||||
|
&membre.ProgrammeID,
|
||||||
|
); err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if membre.ID == "" {
|
if membre.ID == "" {
|
||||||
return membre, fmt.Errorf("No membre by that id was found")
|
return membre, fmt.Errorf("Aucun membre trouvé avec numéro '%s'", membre.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return membre, nil
|
return membre, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
func (d *PostgresClient) UpdateMembreName(membreID, newName string) (int64, error) {
|
func (d *PostgresClient) UpdateMembreName(membreID, newName string) (int64, error) {
|
||||||
|
|
16
entity.go
16
entity.go
|
@ -1,5 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import "unicode"
|
||||||
|
|
||||||
type Programme struct {
|
type Programme struct {
|
||||||
ID string `db:"id" json:"programme_id" csv:"programme_id"`
|
ID string `db:"id" json:"programme_id" csv:"programme_id"`
|
||||||
Name string `db:"name" json:"nom_programme" csv:"nom_programme"`
|
Name string `db:"name" json:"nom_programme" csv:"nom_programme"`
|
||||||
|
@ -12,3 +14,17 @@ type Membre struct {
|
||||||
PreferedName string `db:"prefered_name" json:"prefered_name" csv:"prefered_name"`
|
PreferedName string `db:"prefered_name" json:"prefered_name" csv:"prefered_name"`
|
||||||
ProgrammeID string `db:"programme_id" json:"programme_id" csv:"programme_id"`
|
ProgrammeID string `db:"programme_id" json:"programme_id" csv:"programme_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsMembreID(membre_id string) bool {
|
||||||
|
if len(membre_id) != 7 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, character := range membre_id {
|
||||||
|
if !unicode.IsDigit(character) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
47
request.go
47
request.go
|
@ -23,7 +23,7 @@ func (request HealthGETRequest) Request(v *voki.Voki) (response HealthGETRespons
|
||||||
|
|
||||||
statusCode, body, err := v.CallAndParse(
|
statusCode, body, err := v.CallAndParse(
|
||||||
http.MethodGet,
|
http.MethodGet,
|
||||||
"/api/health/",
|
"/api/v7/health/",
|
||||||
nil,
|
nil,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
|
@ -64,7 +64,7 @@ func (request ProgrammesPOSTRequest) Request(v *voki.Voki) (response ProgrammesP
|
||||||
|
|
||||||
statusCode, body, err := v.CallAndParse(
|
statusCode, body, err := v.CallAndParse(
|
||||||
http.MethodPost,
|
http.MethodPost,
|
||||||
"/api/programmes/",
|
"/api/v7/programme/",
|
||||||
&buf,
|
&buf,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
|
@ -105,7 +105,7 @@ func (request MembresPOSTRequest) Request(v *voki.Voki) (response MembresPOSTRes
|
||||||
|
|
||||||
statusCode, body, err := v.CallAndParse(
|
statusCode, body, err := v.CallAndParse(
|
||||||
http.MethodPost,
|
http.MethodPost,
|
||||||
"/api/membres/",
|
"/api/v7/membre/",
|
||||||
&buf,
|
&buf,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
|
@ -120,3 +120,44 @@ func (request MembresPOSTRequest) Request(v *voki.Voki) (response MembresPOSTRes
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ voki.Requester[MembreGETResponse] = MembreGETRequest{}
|
||||||
|
|
||||||
|
type MembreGETRequest struct {
|
||||||
|
Param struct {
|
||||||
|
MembreID string `json:"membre_id" param:"membre_id"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (request MembreGETRequest) Complete() bool {
|
||||||
|
return request.Param.MembreID != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (request MembreGETRequest) Request(v *voki.Voki) (response MembreGETResponse, err error) {
|
||||||
|
if !request.Complete() {
|
||||||
|
err = fmt.Errorf("Incomplete MembreGETRequest")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if id := request.Param.MembreID; !IsMembreID(id) {
|
||||||
|
err = fmt.Errorf("MembreID '%s' invalide", id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
statusCode, body, err := v.CallAndParse(
|
||||||
|
http.MethodGet,
|
||||||
|
fmt.Sprintf("/api/v7/membre/%s/", request.Param.MembreID),
|
||||||
|
nil,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("code=%d err=%s", statusCode, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.SetStatusCode(statusCode)
|
||||||
|
if err = json.Unmarshal(body, &response); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
45
routes.go
45
routes.go
|
@ -12,7 +12,7 @@ import (
|
||||||
func addRoutes(e *echo.Echo, db *PostgresClient) error {
|
func addRoutes(e *echo.Echo, db *PostgresClient) error {
|
||||||
_ = db
|
_ = db
|
||||||
|
|
||||||
apiPath := "/api"
|
apiPath := "/api/v7"
|
||||||
apiGroup := e.Group(apiPath)
|
apiGroup := e.Group(apiPath)
|
||||||
p := pave.New()
|
p := pave.New()
|
||||||
if err := pave.EchoRegister[HealthGETRequest](
|
if err := pave.EchoRegister[HealthGETRequest](
|
||||||
|
@ -47,7 +47,7 @@ func addRoutes(e *echo.Echo, db *PostgresClient) error {
|
||||||
&p,
|
&p,
|
||||||
apiPath,
|
apiPath,
|
||||||
http.MethodPost,
|
http.MethodPost,
|
||||||
"/programmes/",
|
"/programme/",
|
||||||
"Insert programmes",
|
"Insert programmes",
|
||||||
"ProgrammesPOST", func(c echo.Context) error {
|
"ProgrammesPOST", func(c echo.Context) error {
|
||||||
var request, response = ProgrammesPOSTRequest{}, ProgrammesPOSTResponse{}
|
var request, response = ProgrammesPOSTRequest{}, ProgrammesPOSTResponse{}
|
||||||
|
@ -90,7 +90,7 @@ func addRoutes(e *echo.Echo, db *PostgresClient) error {
|
||||||
&p,
|
&p,
|
||||||
apiPath,
|
apiPath,
|
||||||
http.MethodPost,
|
http.MethodPost,
|
||||||
"/membres/",
|
"/membre/",
|
||||||
"Insert membres",
|
"Insert membres",
|
||||||
"MembresPOST", func(c echo.Context) error {
|
"MembresPOST", func(c echo.Context) error {
|
||||||
var request, response = MembresPOSTRequest{}, MembresPOSTResponse{}
|
var request, response = MembresPOSTRequest{}, MembresPOSTResponse{}
|
||||||
|
@ -127,5 +127,44 @@ func addRoutes(e *echo.Echo, db *PostgresClient) error {
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := pave.EchoRegister[MembreGETRequest](
|
||||||
|
apiGroup,
|
||||||
|
&p,
|
||||||
|
apiPath,
|
||||||
|
http.MethodGet,
|
||||||
|
"/membre/:membre_id/",
|
||||||
|
"Get membre",
|
||||||
|
"MembreGET", func(c echo.Context) error {
|
||||||
|
var request, response = MembreGETRequest{}, MembreGETResponse{}
|
||||||
|
|
||||||
|
request.Param.MembreID = c.Param("membre_id")
|
||||||
|
|
||||||
|
if !request.Complete() {
|
||||||
|
var response voki.ResponseBadRequest
|
||||||
|
response.Message = "Incomplete MembreGET request received"
|
||||||
|
return c.JSON(response.StatusCode(), response)
|
||||||
|
}
|
||||||
|
|
||||||
|
membre, err := db.GetMembre(request.Param.MembreID)
|
||||||
|
if err != nil {
|
||||||
|
var response voki.ResponseBadRequest
|
||||||
|
response.Message = fmt.Sprintf("db: %s", err)
|
||||||
|
return c.JSON(response.StatusCode(), response)
|
||||||
|
}
|
||||||
|
response.Data.Membre = membre
|
||||||
|
|
||||||
|
if err := response.SetStatusCode(http.StatusOK); err != nil {
|
||||||
|
var response voki.ResponseInternalServerError
|
||||||
|
response.Message = fmt.Sprintf("handler: %s", err)
|
||||||
|
return c.JSON(response.StatusCode(), response)
|
||||||
|
}
|
||||||
|
|
||||||
|
response.Message = "ok"
|
||||||
|
return c.JSON(response.StatusCode(), response)
|
||||||
|
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue