diff --git a/private/apigen/example/api.gen.go b/private/apigen/example/api.gen.go index e2ac2008f..e876f1e1b 100644 --- a/private/apigen/example/api.gen.go +++ b/private/apigen/example/api.gen.go @@ -16,6 +16,7 @@ import ( "storj.io/common/uuid" "storj.io/storj/private/api" + "storj.io/storj/private/apigen/example/myapi" ) const dateLayout = "2006-01-02T15:04:05.999Z" @@ -23,6 +24,7 @@ const dateLayout = "2006-01-02T15:04:05.999Z" var ErrDocsAPI = errs.Class("example docs api") type DocumentsService interface { + GetOne(ctx context.Context, path string) (*myapi.Document, api.HTTPError) UpdateContent(ctx context.Context, path string, id uuid.UUID, date time.Time, request struct { Content string "json:\"content\"" }) (*struct { @@ -50,11 +52,44 @@ func NewDocuments(log *zap.Logger, mon *monkit.Scope, service DocumentsService, } docsRouter := router.PathPrefix("/api/v0/docs").Subrouter() + docsRouter.HandleFunc("/{path}", handler.handleGetOne).Methods("GET") docsRouter.HandleFunc("/{path}", handler.handleUpdateContent).Methods("POST") return handler } +func (h *DocumentsHandler) handleGetOne(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + var err error + defer h.mon.Task()(&ctx)(&err) + + w.Header().Set("Content-Type", "application/json") + + path, ok := mux.Vars(r)["path"] + if !ok { + api.ServeError(h.log, w, http.StatusBadRequest, errs.New("missing path route param")) + return + } + + ctx, err = h.auth.IsAuthenticated(ctx, r, true, true) + if err != nil { + h.auth.RemoveAuthCookie(w) + api.ServeError(h.log, w, http.StatusUnauthorized, err) + return + } + + retVal, httpErr := h.service.GetOne(ctx, path) + if httpErr.Err != nil { + api.ServeError(h.log, w, httpErr.Status, httpErr.Err) + return + } + + err = json.NewEncoder(w).Encode(retVal) + if err != nil { + h.log.Debug("failed to write json GetOne response", zap.Error(ErrDocsAPI.Wrap(err))) + } +} + func (h *DocumentsHandler) handleUpdateContent(w http.ResponseWriter, r *http.Request) { ctx := r.Context() var err error diff --git a/private/apigen/example/apidocs.gen.md b/private/apigen/example/apidocs.gen.md index 0ed0420c8..45b173ab4 100644 --- a/private/apigen/example/apidocs.gen.md +++ b/private/apigen/example/apidocs.gen.md @@ -7,8 +7,34 @@

List of Endpoints

* Documents + * [Get One](#documents-get-one) * [Update Content](#documents-update-content) +

Get One (go to full list)

+ +Get one document with the specified version + +`GET /api/v0/docs/{path}` + +**Path Params:** + +| name | type | elaboration | +|---|---|---| +| `path` | `string` | | + +**Response body:** + +```typescript +{ + id: string // UUID formatted as `00000000-0000-0000-0000-000000000000` + date: string // Date timestamp formatted as `2006-01-02T15:00:00Z` + pathParam: string + body: string + version: number +} + +``` +

Update Content (go to full list)

Update the content of the document with the specified path and ID if the last update is before the indicated date diff --git a/private/apigen/example/client-api.gen.ts b/private/apigen/example/client-api.gen.ts index 9756d4c28..b414c9f63 100644 --- a/private/apigen/example/client-api.gen.ts +++ b/private/apigen/example/client-api.gen.ts @@ -4,6 +4,14 @@ import { HttpClient } from '@/utils/httpClient'; import { Time, UUID } from '@/types/common'; +export class Document { + id: UUID; + date: Time; + pathParam: string; + body: string; + version: number; +} + export class UpdateContentRequest { content: string; } @@ -19,6 +27,16 @@ export class docsHttpApiV0 { private readonly http: HttpClient = new HttpClient(); private readonly ROOT_PATH: string = '/api/v0/docs'; + public async GetOne(path: string): Promise { + const fullPath = `${this.ROOT_PATH}/${path}`; + const response = await this.http.get(fullPath); + if (response.ok) { + return response.json().then((body) => body as Document); + } + const err = await response.json(); + throw new Error(err.error); + } + public async UpdateContent(request: UpdateContentRequest, path: string, id: UUID, date: Time): Promise { const u = new URL(`${this.ROOT_PATH}/${path}`); u.searchParams.set('id', id); diff --git a/private/apigen/example/gen.go b/private/apigen/example/gen.go index 65b9c72ca..05dcd4f97 100644 --- a/private/apigen/example/gen.go +++ b/private/apigen/example/gen.go @@ -11,6 +11,7 @@ import ( "storj.io/common/uuid" "storj.io/storj/private/apigen" + "storj.io/storj/private/apigen/example/myapi" ) func main() { @@ -18,6 +19,16 @@ func main() { g := a.Group("Documents", "docs") + g.Get("/{path}", &apigen.Endpoint{ + Name: "Get One", + Description: "Get one document with the specified version", + MethodName: "GetOne", + Response: myapi.Document{}, + PathParams: []apigen.Param{ + apigen.NewParam("path", ""), + }, + }) + g.Post("/{path}", &apigen.Endpoint{ Name: "Update Content", Description: "Update the content of the document with the specified path and ID if the last update is before the indicated date", diff --git a/private/apigen/example/myapi/types.go b/private/apigen/example/myapi/types.go new file mode 100644 index 000000000..ab0e2479e --- /dev/null +++ b/private/apigen/example/myapi/types.go @@ -0,0 +1,19 @@ +// Copyright (C) 2023 Storj Labs, Inc. +// See LICENSE for copying information. + +package myapi + +import ( + "time" + + "storj.io/common/uuid" +) + +// Document is a retrieved document. +type Document struct { + ID uuid.UUID `json:"id"` + Date time.Time `json:"date"` + PathParam string `json:"pathParam"` + Body string `json:"body"` + Version uint `json:"version"` +} diff --git a/private/apigen/gogen.go b/private/apigen/gogen.go index 79d2ebb92..a64b2ded7 100644 --- a/private/apigen/gogen.go +++ b/private/apigen/gogen.go @@ -42,7 +42,12 @@ func (a *API) generateGo() ([]byte, error) { getPackageName := func(path string) string { pathPackages := strings.Split(path, "/") - return pathPackages[len(pathPackages)-1] + name := pathPackages[len(pathPackages)-1] + if name == "main" { + panic(errs.New(`invalid package name. Your types cannot be defined in a package named "main"`)) + } + + return name } imports := struct { diff --git a/private/apigen/gogen_test.go b/private/apigen/gogen_test.go index 41a4136bc..f7d698880 100644 --- a/private/apigen/gogen_test.go +++ b/private/apigen/gogen_test.go @@ -25,6 +25,7 @@ import ( "storj.io/storj/private/api" "storj.io/storj/private/apigen" "storj.io/storj/private/apigen/example" + "storj.io/storj/private/apigen/example/myapi" ) type ( @@ -44,6 +45,13 @@ func (a auth) IsAuthenticated(ctx context.Context, r *http.Request, isCookieAuth func (a auth) RemoveAuthCookie(w http.ResponseWriter) {} +func (s service) GetOne( + ctx context.Context, + pathParam string, +) (*myapi.Document, api.HTTPError) { + return &myapi.Document{}, api.HTTPError{} +} + func (s service) UpdateContent( ctx context.Context, pathParam string,