From d34c1b6825d3ca408aff3877ea48a97adc51f22f Mon Sep 17 00:00:00 2001 From: Ivan Fraixedes Date: Thu, 24 Aug 2023 18:28:00 +0200 Subject: [PATCH] private/apigen: Generate docs & typescript for example Generate the documentation and the typescript code for the example of that we have to generate an API through the API generator. The JSON Go struct field tags are needed because the typescript generator require them, otherwise it panics. The test had to be adjusted according to match the tags so Go consider the structs the same type, otherwise, it doesn't compile. Change-Id: I3e4ebff9174885c50ca2058b86b7ec60e025945c --- private/apigen/example/api.gen.go | 16 +++++--- private/apigen/example/apidocs.gen.md | 50 ++++++++++++++++++++++++ private/apigen/example/client-api.gen.ts | 31 +++++++++++++++ private/apigen/example/gen.go | 16 +++++--- private/apigen/gogen_test.go | 27 ++++++++----- 5 files changed, 119 insertions(+), 21 deletions(-) create mode 100644 private/apigen/example/apidocs.gen.md create mode 100644 private/apigen/example/client-api.gen.ts diff --git a/private/apigen/example/api.gen.go b/private/apigen/example/api.gen.go index a6e668ca5..98f047071 100644 --- a/private/apigen/example/api.gen.go +++ b/private/apigen/example/api.gen.go @@ -23,11 +23,13 @@ const dateLayout = "2006-01-02T15:04:05.999Z" var ErrTestapiAPI = errs.Class("example testapi api") type TestAPIService interface { - GenTestAPI(ctx context.Context, path string, id uuid.UUID, date time.Time, request struct{ Content string }) (*struct { - ID uuid.UUID - Date time.Time - PathParam string - Body string + GenTestAPI(ctx context.Context, path string, id uuid.UUID, date time.Time, request struct { + Content string "json:\"content\"" + }) (*struct { + ID uuid.UUID "json:\"id\"" + Date time.Time "json:\"date\"" + PathParam string "json:\"pathParam\"" + Body string "json:\"body\"" }, api.HTTPError) } @@ -90,7 +92,9 @@ func (h *TestAPIHandler) handleGenTestAPI(w http.ResponseWriter, r *http.Request return } - payload := struct{ Content string }{} + payload := struct { + Content string "json:\"content\"" + }{} if err = json.NewDecoder(r.Body).Decode(&payload); err != nil { api.ServeError(h.log, w, http.StatusBadRequest, err) return diff --git a/private/apigen/example/apidocs.gen.md b/private/apigen/example/apidocs.gen.md new file mode 100644 index 000000000..631db3ea8 --- /dev/null +++ b/private/apigen/example/apidocs.gen.md @@ -0,0 +1,50 @@ +# API Docs + +**Description:** + +**Version:** `v0` + +**List of endpoints:** +* TestAPI + * [](#e-31104e2390954bdc113e2444e69a0667) + +

+ + + +`POST /testapi/{path}` + +**Query Params:** + +| name | type | elaboration | +|---|---|---| +| `id` | `string` | UUID formatted as `00000000-0000-0000-0000-000000000000` | +| `date` | `string` | Date timestamp formatted as `2006-01-02T15:00:00Z` | + +**Path Params:** + +| name | type | elaboration | +|---|---|---| +| `path` | `string` | | + +**Request body:** + +```typescript +{ + content: 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 +} + +``` + diff --git a/private/apigen/example/client-api.gen.ts b/private/apigen/example/client-api.gen.ts new file mode 100644 index 000000000..f871182f4 --- /dev/null +++ b/private/apigen/example/client-api.gen.ts @@ -0,0 +1,31 @@ +// AUTOGENERATED BY private/apigen +// DO NOT EDIT. + +import { HttpClient } from '@/utils/httpClient'; +import { Time, UUID } from '@/types/common'; + +export class { + content: string; +} + +export class { + id: UUID; + date: Time; + pathParam: string; + body: string; +} + +export class testapiHttpApiV0 { + private readonly http: HttpClient = new HttpClient(); + private readonly ROOT_PATH: string = '/api/v0/testapi'; + + public async (request: , path: string, id: UUID, date: Time): Promise<> { + const path = `${this.ROOT_PATH}/${path}?id=${id}&date=${date}`; + const response = await this.http.post(path, JSON.stringify(request)); + if (response.ok) { + return response.json().then((body) => body as ); + } + const err = await response.json(); + throw new Error(err.error); + } +} diff --git a/private/apigen/example/gen.go b/private/apigen/example/gen.go index 987bb66bd..7b44d7f92 100644 --- a/private/apigen/example/gen.go +++ b/private/apigen/example/gen.go @@ -14,19 +14,21 @@ import ( ) func main() { - a := &apigen.API{PackageName: "example"} + a := &apigen.API{PackageName: "example", Version: "v0"} g := a.Group("TestAPI", "testapi") g.Post("/{path}", &apigen.Endpoint{ MethodName: "GenTestAPI", Response: struct { - ID uuid.UUID - Date time.Time - PathParam string - Body string + ID uuid.UUID `json:"id"` + Date time.Time `json:"date"` + PathParam string `json:"pathParam"` + Body string `json:"body"` + }{}, + Request: struct { + Content string `json:"content"` }{}, - Request: struct{ Content string }{}, QueryParams: []apigen.Param{ apigen.NewParam("id", uuid.UUID{}), apigen.NewParam("date", time.Time{}), @@ -37,4 +39,6 @@ func main() { }) a.MustWriteGo("api.gen.go") + a.MustWriteTS("client-api.gen.ts") + a.MustWriteDocs("apidocs.gen.md") } diff --git a/private/apigen/gogen_test.go b/private/apigen/gogen_test.go index 42ce738d7..857a48c94 100644 --- a/private/apigen/gogen_test.go +++ b/private/apigen/gogen_test.go @@ -31,10 +31,10 @@ type ( auth struct{} service struct{} response = struct { - ID uuid.UUID - Date time.Time - PathParam string - Body string + ID uuid.UUID `json:"id"` + Date time.Time `json:"date"` + PathParam string `json:"pathParam"` + Body string `json:"body"` } ) @@ -44,7 +44,15 @@ func (a auth) IsAuthenticated(ctx context.Context, r *http.Request, isCookieAuth func (a auth) RemoveAuthCookie(w http.ResponseWriter) {} -func (s service) GenTestAPI(ctx context.Context, pathParam string, id uuid.UUID, date time.Time, body struct{ Content string }) (*response, api.HTTPError) { +func (s service) GenTestAPI( + ctx context.Context, + pathParam string, + id uuid.UUID, + date time.Time, + body struct { + Content string `json:"content"` + }, +) (*response, api.HTTPError) { return &response{ ID: id, Date: date, @@ -118,10 +126,11 @@ func TestAPIServer(t *testing.T) { var actual map[string]string require.NoError(t, json.Unmarshal(resp, &actual)) - for _, key := range []string{"ID", "Date", "PathParam", "Body"} { + for _, key := range []string{"id", "date", "pathParam", "body"} { require.Contains(t, actual, key) } - require.Equal(t, expected.ID.String(), actual["ID"]) - require.Equal(t, expected.Date.Format(apigen.DateFormat), actual["Date"]) - require.Equal(t, expected.Body, actual["Body"]) + require.Equal(t, expected.ID.String(), actual["id"]) + require.Equal(t, expected.Date.Format(apigen.DateFormat), actual["date"]) + require.Equal(t, expected.PathParam, actual["pathParam"]) + require.Equal(t, expected.Body, actual["body"]) }