generated from alphane/template
Initial commit
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
export class ApiError extends Error {
|
||||
public readonly name = "ApiError"
|
||||
|
||||
constructor(
|
||||
message: string,
|
||||
public readonly status: number
|
||||
) {
|
||||
super(message)
|
||||
}
|
||||
}
|
||||
|
||||
export default ApiError
|
||||
@@ -0,0 +1,44 @@
|
||||
/** Keep in sync with api/src/controllers/base-controller.ts#ModelOrder */
|
||||
export type ModelOrder =
|
||||
| [string, string]
|
||||
| [string, string, string]
|
||||
| [string, string, string, string]
|
||||
| [string, string, string, string, string]
|
||||
| [string, string, string, string, string, string]
|
||||
|
||||
export type Policy = {
|
||||
show: boolean
|
||||
create: boolean
|
||||
update: boolean
|
||||
destroy: boolean
|
||||
}
|
||||
|
||||
export type WhereOptions<Model, Attributes extends keyof Model> = {
|
||||
[K in Attributes]?: Model[K] | Model[K][]
|
||||
}
|
||||
|
||||
export type FiltersOptions<Options> = Partial<Options>
|
||||
|
||||
export type QueryOptions<WhereOptions, FiltersOptions> = Partial<{
|
||||
where: WhereOptions
|
||||
filters: FiltersOptions
|
||||
order: ModelOrder[]
|
||||
page: number
|
||||
perPage: number
|
||||
}>
|
||||
|
||||
// Keep in sync with api/src/controllers/base-controller.ts
|
||||
export const MAX_PER_PAGE = 1000
|
||||
|
||||
export type ApiResponseError = { field?: string; text: string }
|
||||
|
||||
export type ApiResponseLegacy<T> = {
|
||||
data: T
|
||||
errors: ApiResponseError[]
|
||||
messages?: string[]
|
||||
}
|
||||
|
||||
export type ApiResponse<TPayload = object> = {
|
||||
errors: ApiResponseError[]
|
||||
messages?: string[]
|
||||
} & TPayload
|
||||
@@ -0,0 +1,23 @@
|
||||
import http from "@/api/http-client"
|
||||
|
||||
import { type Policy } from "@/api/base-api"
|
||||
import { UserRoles, type User } from "@/api/users-api"
|
||||
|
||||
export { UserRoles }
|
||||
|
||||
export type UserAsShow = Pick<
|
||||
User,
|
||||
"id" | "email" | "firstName" | "lastName" | "displayName" | "roles" | "createdAt" | "updatedAt"
|
||||
>
|
||||
|
||||
export const currentUserApi = {
|
||||
async get(): Promise<{
|
||||
user: UserAsShow
|
||||
policy: Policy
|
||||
}> {
|
||||
const { data } = await http.get(`/api/current-user`)
|
||||
return data
|
||||
},
|
||||
}
|
||||
|
||||
export default currentUserApi
|
||||
@@ -0,0 +1,46 @@
|
||||
import qs from "qs"
|
||||
import axios from "axios"
|
||||
|
||||
import { API_BASE_URL } from "@/config"
|
||||
import auth0 from "@/plugins/auth0-plugin"
|
||||
import ApiError from "@/api/api-error"
|
||||
|
||||
export const httpClient = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
paramsSerializer: {
|
||||
serialize: (params) => {
|
||||
return qs.stringify(params, {
|
||||
arrayFormat: "indices",
|
||||
strictNullHandling: true,
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
httpClient.interceptors.request.use(async (config) => {
|
||||
// Only add the Authorization header to requests that start with "/api"
|
||||
if (config.url?.startsWith("/api")) {
|
||||
const accessToken = await auth0.getAccessTokenSilently()
|
||||
config.headers["Authorization"] = `Bearer ${accessToken}`
|
||||
}
|
||||
|
||||
return config
|
||||
})
|
||||
|
||||
// Any status codes that falls outside the range of 2xx causes this function to trigger
|
||||
httpClient.interceptors.response.use(null, async (error) => {
|
||||
if (error?.error === "login_required") {
|
||||
throw new ApiError("You must be logged in to access this endpoint", 401)
|
||||
} else if (error?.response?.data?.message) {
|
||||
throw new ApiError(error.response.data.message, error.response.status)
|
||||
} else if (error.message) {
|
||||
throw new ApiError(error.message, error.response?.status || 500)
|
||||
} else {
|
||||
throw new ApiError("An unknown error occurred", error.response?.status || 500)
|
||||
}
|
||||
})
|
||||
|
||||
export default httpClient
|
||||
@@ -0,0 +1,18 @@
|
||||
import http from "@/api/http-client"
|
||||
|
||||
export type Status = {
|
||||
RELEASE_TAG: string
|
||||
GIT_COMMIT_HASH: string
|
||||
}
|
||||
|
||||
export const statusApi = {
|
||||
/**
|
||||
* Note: This is a public API route, and not protected by authentication
|
||||
*/
|
||||
async get(): Promise<Status> {
|
||||
const { data } = await http.get("/_status")
|
||||
return data
|
||||
},
|
||||
}
|
||||
|
||||
export default statusApi
|
||||
@@ -0,0 +1,81 @@
|
||||
import http from "@/api/http-client"
|
||||
import {
|
||||
type FiltersOptions,
|
||||
type ModelOrder,
|
||||
type Policy,
|
||||
type WhereOptions,
|
||||
} from "@/api/base-api"
|
||||
|
||||
/** Keep in sync with api/src/models/user.ts */
|
||||
export enum UserRoles {
|
||||
SYSTEM_ADMIN = "system_admin",
|
||||
USER = "user",
|
||||
}
|
||||
|
||||
export type User = {
|
||||
id: number
|
||||
email: string
|
||||
firstName: string
|
||||
lastName: string
|
||||
displayName: string
|
||||
roles: UserRoles[]
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
export type UserAsShow = Omit<User, "organizations"> & {}
|
||||
|
||||
export type UserWhereOptions = WhereOptions<User, "email" | "firstName" | "lastName">
|
||||
|
||||
export type UserFiltersOptions = FiltersOptions<{
|
||||
search: string | string[]
|
||||
}>
|
||||
|
||||
export type UserQueryOptions = {
|
||||
where?: UserWhereOptions
|
||||
filters?: UserFiltersOptions
|
||||
order?: ModelOrder[]
|
||||
page?: number
|
||||
perPage?: number
|
||||
}
|
||||
|
||||
export const usersApi = {
|
||||
UserRoles,
|
||||
async list(params: UserQueryOptions = {}): Promise<{
|
||||
users: User[]
|
||||
totalCount: number
|
||||
}> {
|
||||
const { data } = await http.get("/api/users", {
|
||||
params,
|
||||
})
|
||||
return data
|
||||
},
|
||||
async get(userId: number): Promise<{
|
||||
user: User
|
||||
policy: Policy
|
||||
}> {
|
||||
const { data } = await http.get(`/api/users/${userId}`)
|
||||
return data
|
||||
},
|
||||
async create(attributes: Partial<User>): Promise<{
|
||||
user: User
|
||||
}> {
|
||||
const { data } = await http.post("/api/users", attributes)
|
||||
return data
|
||||
},
|
||||
async update(
|
||||
userId: number,
|
||||
attributes: Partial<User>
|
||||
): Promise<{
|
||||
user: User
|
||||
}> {
|
||||
const { data } = await http.patch(`/api/users/${userId}`, attributes)
|
||||
return data
|
||||
},
|
||||
async delete(userId: number): Promise<void> {
|
||||
const { data } = await http.delete(`/api/users/${userId}`)
|
||||
return data
|
||||
},
|
||||
}
|
||||
|
||||
export default usersApi
|
||||
Reference in New Issue
Block a user