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 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 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,