Skip to content

chore: switch to generated types #1394

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 12, 2022
8 changes: 4 additions & 4 deletions codersdk/organizations.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ type Organization struct {
// CreateTemplateVersionRequest enables callers to create a new Template Version.
type CreateTemplateVersionRequest struct {
// TemplateID optionally associates a version with a template.
TemplateID uuid.UUID `json:"template_id"`
TemplateID uuid.UUID `json:"template_id,omitempty"`

StorageMethod database.ProvisionerStorageMethod `json:"storage_method" validate:"oneof=file,required"`
StorageSource string `json:"storage_source" validate:"required"`
Provisioner database.ProvisionerType `json:"provisioner" validate:"oneof=terraform echo,required"`
// ParameterValues allows for additional parameters to be provided
// during the dry-run provision stage.
ParameterValues []CreateParameterRequest `json:"parameter_values"`
ParameterValues []CreateParameterRequest `json:"parameter_values,omitempty"`
}

// CreateTemplateRequest provides options when creating a template.
Expand All @@ -45,7 +45,7 @@ type CreateTemplateRequest struct {
// template works. There is no reason the data-model cannot support
// empty templates, but it doesn't make sense for users.
VersionID uuid.UUID `json:"template_version_id" validate:"required"`
ParameterValues []CreateParameterRequest `json:"parameter_values"`
ParameterValues []CreateParameterRequest `json:"parameter_values,omitempty"`
}

// CreateWorkspaceRequest provides options for creating a new workspace.
Expand All @@ -54,7 +54,7 @@ type CreateWorkspaceRequest struct {
Name string `json:"name" validate:"username,required"`
// ParameterValues allows for additional parameters to be provided
// during the initial provision.
ParameterValues []CreateParameterRequest `json:"parameter_values"`
ParameterValues []CreateParameterRequest `json:"parameter_values,omitempty"`
}

func (c *Client) Organization(ctx context.Context, id uuid.UUID) (Organization, error) {
Expand Down
4 changes: 2 additions & 2 deletions codersdk/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ const (
)

type UsersRequest struct {
Search string `json:"search"`
Search string `json:"search,omitempty"`
// Filter users by status
Status string `json:"status"`
Status string `json:"status,omitempty"`
Pagination
}

Expand Down
4 changes: 2 additions & 2 deletions codersdk/workspaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ type Workspace struct {

// CreateWorkspaceBuildRequest provides options to update the latest workspace build.
type CreateWorkspaceBuildRequest struct {
TemplateVersionID uuid.UUID `json:"template_version_id"`
TemplateVersionID uuid.UUID `json:"template_version_id,omitempty"`
Transition database.WorkspaceTransition `json:"transition" validate:"oneof=create start stop delete,required"`
DryRun bool `json:"dry_run"`
DryRun bool `json:"dry_run,omitempty"`
ProvisionerState []byte `json:"state,omitempty"`
}

Expand Down
3 changes: 1 addition & 2 deletions scripts/apitypings/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This main.go generates typescript types from the codersdk types in Go.
# Features

- Supports Go types
- [x] Basics (string/int/etc)
- [x] Basics (string/int/etc)
- [x] Maps
- [x] Slices
- [x] Enums
Expand Down Expand Up @@ -36,5 +36,4 @@ type InternalType struct {

# Future Ideas

- Should `omitempty` in the `json` tag indicate optional?
- Use a yaml config for overriding certain types
6 changes: 3 additions & 3 deletions site/src/api/api.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import axios from "axios"
import { getApiKey, login, logout } from "./api"
import { APIKeyResponse, LoginResponse } from "./types"
import * as TypesGen from "./typesGenerated"

// Mock the axios module so that no real network requests are made, but rather
// we swap in a resolved or rejected value
Expand All @@ -12,7 +12,7 @@ describe("api.ts", () => {
describe("login", () => {
it("should return LoginResponse", async () => {
// given
const loginResponse: LoginResponse = {
const loginResponse: TypesGen.LoginWithPasswordResponse = {
session_token: "abc_123_test",
}
const axiosMockPost = jest.fn().mockImplementationOnce(() => {
Expand Down Expand Up @@ -87,7 +87,7 @@ describe("api.ts", () => {
describe("getApiKey", () => {
it("should return APIKeyResponse", async () => {
// given
const apiKeyResponse: APIKeyResponse = {
const apiKeyResponse: TypesGen.GenerateAPIKeyResponse = {
key: "abc_123_test",
}
const axiosMockPost = jest.fn().mockImplementationOnce(() => {
Expand Down
65 changes: 38 additions & 27 deletions site/src/api/api.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
import axios, { AxiosRequestHeaders } from "axios"
import { mutate } from "swr"
import * as Types from "./types"
import * as TypesGen from "./typesGenerated"

const CONTENT_TYPE_JSON: AxiosRequestHeaders = {
"Content-Type": "application/json",
}

export const provisioners: Types.Provisioner[] = [
export const provisioners: TypesGen.ProvisionerDaemon[] = [
{
id: "terraform",
name: "Terraform",
created_at: "",
provisioners: [],
},
{
id: "cdr-basic",
name: "Basic",
created_at: "",
provisioners: [],
},
]

export namespace Workspace {
export const create = async (request: Types.CreateWorkspaceRequest): Promise<Types.Workspace> => {
const response = await fetch(`/api/v2/organizations/${request.organization_id}/workspaces`, {
export const create = async (
organizationId: string,
request: TypesGen.CreateWorkspaceRequest,
): Promise<TypesGen.Workspace> => {
const response = await fetch(`/api/v2/organizations/${organizationId}/workspaces`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Expand All @@ -43,13 +49,13 @@ export namespace Workspace {
}
}

export const login = async (email: string, password: string): Promise<Types.LoginResponse> => {
export const login = async (email: string, password: string): Promise<TypesGen.LoginWithPasswordResponse> => {
const payload = JSON.stringify({
email,
password,
})

const response = await axios.post<Types.LoginResponse>("/api/v2/users/login", payload, {
const response = await axios.post<TypesGen.LoginWithPasswordResponse>("/api/v2/users/login", payload, {
headers: { ...CONTENT_TYPE_JSON },
})

Expand All @@ -60,8 +66,8 @@ export const logout = async (): Promise<void> => {
await axios.post("/api/v2/users/logout")
}

export const getUser = async (): Promise<Types.UserResponse> => {
const response = await axios.get<Types.UserResponse>("/api/v2/users/me")
export const getUser = async (): Promise<TypesGen.User> => {
const response = await axios.get<TypesGen.User>("/api/v2/users/me")
return response.data
}

Expand All @@ -70,8 +76,8 @@ export const getAuthMethods = async (): Promise<TypesGen.AuthMethods> => {
return response.data
}

export const getApiKey = async (): Promise<Types.APIKeyResponse> => {
const response = await axios.post<Types.APIKeyResponse>("/api/v2/users/me/keys")
export const getApiKey = async (): Promise<TypesGen.GenerateAPIKeyResponse> => {
const response = await axios.post<TypesGen.GenerateAPIKeyResponse>("/api/v2/users/me/keys")
return response.data
}

Expand All @@ -80,55 +86,57 @@ export const getUsers = async (): Promise<TypesGen.User[]> => {
return response.data
}

export const getOrganization = async (organizationId: string): Promise<Types.Organization> => {
const response = await axios.get<Types.Organization>(`/api/v2/organizations/${organizationId}`)
export const getOrganization = async (organizationId: string): Promise<TypesGen.Organization> => {
const response = await axios.get<TypesGen.Organization>(`/api/v2/organizations/${organizationId}`)
return response.data
}

export const getOrganizations = async (): Promise<Types.Organization[]> => {
const response = await axios.get<Types.Organization[]>("/api/v2/users/me/organizations")
export const getOrganizations = async (): Promise<TypesGen.Organization[]> => {
const response = await axios.get<TypesGen.Organization[]>("/api/v2/users/me/organizations")
return response.data
}

export const getTemplate = async (templateId: string): Promise<Types.Template> => {
const response = await axios.get<Types.Template>(`/api/v2/templates/${templateId}`)
export const getTemplate = async (templateId: string): Promise<TypesGen.Template> => {
const response = await axios.get<TypesGen.Template>(`/api/v2/templates/${templateId}`)
return response.data
}

export const getWorkspace = async (workspaceId: string): Promise<Types.Workspace> => {
const response = await axios.get<Types.Workspace>(`/api/v2/workspaces/${workspaceId}`)
export const getWorkspace = async (workspaceId: string): Promise<TypesGen.Workspace> => {
const response = await axios.get<TypesGen.Workspace>(`/api/v2/workspaces/${workspaceId}`)
return response.data
}

export const getWorkspaceByOwnerAndName = async (
organizationID: string,
username = "me",
workspaceName: string,
): Promise<Types.Workspace> => {
const response = await axios.get<Types.Workspace>(
): Promise<TypesGen.Workspace> => {
const response = await axios.get<TypesGen.Workspace>(
`/api/v2/organizations/${organizationID}/workspaces/${username}/${workspaceName}`,
)
return response.data
}

export const getWorkspaceResources = async (workspaceBuildID: string): Promise<Types.WorkspaceResource[]> => {
const response = await axios.get<Types.WorkspaceResource[]>(`/api/v2/workspacebuilds/${workspaceBuildID}/resources`)
export const getWorkspaceResources = async (workspaceBuildID: string): Promise<TypesGen.WorkspaceResource[]> => {
const response = await axios.get<TypesGen.WorkspaceResource[]>(
`/api/v2/workspacebuilds/${workspaceBuildID}/resources`,
)
return response.data
}

export const createUser = async (user: Types.CreateUserRequest): Promise<TypesGen.User> => {
export const createUser = async (user: TypesGen.CreateUserRequest): Promise<TypesGen.User> => {
const response = await axios.post<TypesGen.User>("/api/v2/users", user)
return response.data
}

export const getBuildInfo = async (): Promise<Types.BuildInfoResponse> => {
export const getBuildInfo = async (): Promise<TypesGen.BuildInfoResponse> => {
const response = await axios.get("/api/v2/buildinfo")
return response.data
}

export const putWorkspaceAutostart = async (
workspaceID: string,
autostart: Types.WorkspaceAutostartRequest,
autostart: TypesGen.UpdateWorkspaceAutostartRequest,
): Promise<void> => {
const payload = JSON.stringify(autostart)
await axios.put(`/api/v2/workspaces/${workspaceID}/autostart`, payload, {
Expand All @@ -138,15 +146,18 @@ export const putWorkspaceAutostart = async (

export const putWorkspaceAutostop = async (
workspaceID: string,
autostop: Types.WorkspaceAutostopRequest,
autostop: TypesGen.UpdateWorkspaceAutostopRequest,
): Promise<void> => {
const payload = JSON.stringify(autostop)
await axios.put(`/api/v2/workspaces/${workspaceID}/autostop`, payload, {
headers: { ...CONTENT_TYPE_JSON },
})
}

export const updateProfile = async (userId: string, data: Types.UpdateProfileRequest): Promise<Types.UserResponse> => {
export const updateProfile = async (
userId: string,
data: TypesGen.UpdateUserProfileRequest,
): Promise<TypesGen.User> => {
const response = await axios.put(`/api/v2/users/${userId}/profile`, data)
return response.data
}
Expand Down
111 changes: 0 additions & 111 deletions site/src/api/types.ts
Original file line number Diff line number Diff line change
@@ -1,121 +1,10 @@
/**
* `BuildInfoResponse` must be kept in sync with the go struct in buildinfo.go.
*/
export interface BuildInfoResponse {
external_url: string
version: string
}

export interface LoginResponse {
session_token: string
}

export interface CreateUserRequest {
username: string
email: string
password: string
organization_id: string
}

export interface UserResponse {
readonly id: string
readonly username: string
readonly email: string
readonly created_at: string
readonly status: "active" | "suspended"
readonly organization_ids: string[]
readonly roles: { name: string; display_name: string }[]
}

/**
* `Organization` must be kept in sync with the go struct in organizations.go
*/
export interface Organization {
id: string
name: string
created_at: string
updated_at: string
}

export interface Provisioner {
id: string
name: string
}

// This must be kept in sync with the `Template` struct in the back-end
export interface Template {
id: string
created_at: string
updated_at: string
organization_id: string
name: string
provisioner: string
active_version_id: string
}

export interface CreateTemplateRequest {
name: string
organizationId: string
provisioner: string
}

export interface CreateWorkspaceRequest {
name: string
template_id: string
organization_id: string
}

export interface WorkspaceBuild {
id: string
}

export interface Workspace {
id: string
created_at: string
updated_at: string
owner_id: string
template_id: string
name: string
autostart_schedule: string
autostop_schedule: string
latest_build: WorkspaceBuild
}

export interface WorkspaceResource {
id: string
agents?: WorkspaceAgent[]
}

export interface WorkspaceAgent {
id: string
name: string
operating_system: string
}

export interface APIKeyResponse {
key: string
}

export interface UserAgent {
readonly browser: string
readonly device: string
readonly ip_address: string
readonly os: string
}

export interface WorkspaceAutostartRequest {
schedule: string
}

export interface WorkspaceAutostopRequest {
schedule: string
}

export interface UpdateProfileRequest {
readonly username: string
readonly email: string
}

export interface ReconnectingPTYRequest {
readonly data?: string
readonly height?: number
Expand Down
Loading