diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index a446420fc31b9..fcea8168d0000 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -3000,6 +3000,7 @@ const docTemplate = `{ ], "summary": "Get template examples by organization", "operationId": "get-template-examples-by-organization", + "deprecated": true, "parameters": [ { "type": "string", @@ -3421,6 +3422,34 @@ const docTemplate = `{ } } }, + "/templates/examples": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Templates" + ], + "summary": "Get template examples", + "operationId": "get-template-examples", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.TemplateExample" + } + } + } + } + } + }, "/templates/{template}": { "get": { "security": [ diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index af6106bf23153..f519081f6d425 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -2630,6 +2630,7 @@ "tags": ["Templates"], "summary": "Get template examples by organization", "operationId": "get-template-examples-by-organization", + "deprecated": true, "parameters": [ { "type": "string", @@ -3005,6 +3006,30 @@ } } }, + "/templates/examples": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Templates"], + "summary": "Get template examples", + "operationId": "get-template-examples", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.TemplateExample" + } + } + } + } + } + }, "/templates/{template}": { "get": { "security": [ diff --git a/coderd/coderd.go b/coderd/coderd.go index 043176279194c..896918f1c6d76 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -871,7 +871,7 @@ func New(options *Options) *API { r.Route("/templates", func(r chi.Router) { r.Post("/", api.postTemplateByOrganization) r.Get("/", api.templatesByOrganization()) - r.Get("/examples", api.templateExamples) + r.Get("/examples", api.templateExamplesByOrganization) r.Route("/{templatename}", func(r chi.Router) { r.Get("/", api.templateByOrganizationAndName) r.Route("/versions/{templateversionname}", func(r chi.Router) { @@ -915,6 +915,7 @@ func New(options *Options) *API { apiKeyMiddleware, ) r.Get("/", api.fetchTemplates(nil)) + r.Get("/examples", api.templateExamples) r.Route("/{template}", func(r chi.Router) { r.Use( httpmw.ExtractTemplateParam(options.Database), diff --git a/coderd/templates.go b/coderd/templates.go index 5bf32871dcbc1..93a5943b40193 100644 --- a/coderd/templates.go +++ b/coderd/templates.go @@ -821,7 +821,8 @@ func (api *API) templateDAUs(rw http.ResponseWriter, r *http.Request) { // @Param organization path string true "Organization ID" format(uuid) // @Success 200 {array} codersdk.TemplateExample // @Router /organizations/{organization}/templates/examples [get] -func (api *API) templateExamples(rw http.ResponseWriter, r *http.Request) { +// @Deprecated Use /templates/examples instead +func (api *API) templateExamplesByOrganization(rw http.ResponseWriter, r *http.Request) { var ( ctx = r.Context() organization = httpmw.OrganizationParam(r) @@ -844,6 +845,33 @@ func (api *API) templateExamples(rw http.ResponseWriter, r *http.Request) { httpapi.Write(ctx, rw, http.StatusOK, ex) } +// @Summary Get template examples +// @ID get-template-examples +// @Security CoderSessionToken +// @Produce json +// @Tags Templates +// @Success 200 {array} codersdk.TemplateExample +// @Router /templates/examples [get] +func (api *API) templateExamples(rw http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + if !api.Authorize(r, policy.ActionRead, rbac.ResourceTemplate.AnyOrganization()) { + httpapi.ResourceNotFound(rw) + return + } + + ex, err := examples.List() + if err != nil { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error fetching examples.", + Detail: err.Error(), + }) + return + } + + httpapi.Write(ctx, rw, http.StatusOK, ex) +} + func (api *API) convertTemplates(templates []database.Template) []codersdk.Template { apiTemplates := make([]codersdk.Template, 0, len(templates)) diff --git a/coderd/templateversions_test.go b/coderd/templateversions_test.go index cd54bfdaeaba7..a03a1c619871e 100644 --- a/coderd/templateversions_test.go +++ b/coderd/templateversions_test.go @@ -1097,17 +1097,17 @@ func TestPreviousTemplateVersion(t *testing.T) { }) } -func TestTemplateExamples(t *testing.T) { +func TestStarterTemplates(t *testing.T) { t.Parallel() t.Run("OK", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, nil) - user := coderdtest.CreateFirstUser(t, client) + _ = coderdtest.CreateFirstUser(t, client) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - ex, err := client.TemplateExamples(ctx, user.OrganizationID) + ex, err := client.StarterTemplates(ctx) require.NoError(t, err) ls, err := examples.List() require.NoError(t, err) diff --git a/codersdk/templates.go b/codersdk/templates.go index cad6ef2ca49dc..56b3b3c0483ef 100644 --- a/codersdk/templates.go +++ b/codersdk/templates.go @@ -472,9 +472,16 @@ type AgentStatsReportResponse struct { TxBytes int64 `json:"tx_bytes"` } -// TemplateExamples lists example templates embedded in coder. -func (c *Client) TemplateExamples(ctx context.Context, organizationID uuid.UUID) ([]TemplateExample, error) { - res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/organizations/%s/templates/examples", organizationID), nil) +// TemplateExamples lists example templates available in Coder. +// +// Deprecated: Use StarterTemplates instead. +func (c *Client) TemplateExamples(ctx context.Context, _ uuid.UUID) ([]TemplateExample, error) { + return c.StarterTemplates(ctx) +} + +// StarterTemplates lists example templates available in Coder. +func (c *Client) StarterTemplates(ctx context.Context) ([]TemplateExample, error) { + res, err := c.Request(ctx, http.MethodGet, "/api/v2/templates/examples", nil) if err != nil { return nil, err } diff --git a/docs/api/templates.md b/docs/api/templates.md index f42c4306d01a8..1a47cb600096a 100644 --- a/docs/api/templates.md +++ b/docs/api/templates.md @@ -761,6 +761,60 @@ Status Code **200** To perform this operation, you must be authenticated. [Learn more](authentication.md). +## Get template examples + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/templates/examples \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /templates/examples` + +### Example responses + +> 200 Response + +```json +[ + { + "description": "string", + "icon": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "markdown": "string", + "name": "string", + "tags": ["string"], + "url": "string" + } +] +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | ----------------------------------------------------------------------- | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | array of [codersdk.TemplateExample](schemas.md#codersdktemplateexample) | + +