Skip to content
This repository has been archived by the owner on May 22, 2023. It is now read-only.

Commit

Permalink
Merge pull request #2 from mitchell-merry/mitchell-merry/acl-urls
Browse files Browse the repository at this point in the history
Autocomplete URLs by path
  • Loading branch information
drwpow authored Mar 14, 2023
2 parents b736025 + 22d2a79 commit 02c2bbb
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 8 deletions.
24 changes: 16 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ interface BaseParams {
query?: Record<string, unknown>;
}

export const methods = [ 'get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace' ] as const;
export type Method = (typeof methods)[number];

type TruncatedResponse = Omit<Response, 'arrayBuffer' | 'blob' | 'body' | 'clone' | 'formData' | 'json' | 'text'>;
/** Infer request/response from content type */
type Unwrap<T> = T extends {
Expand Down Expand Up @@ -68,6 +71,11 @@ export default function createClient<T>(defaultOptions?: ClientOptions) {
return res.ok ? { data: await res.json(), response } : { error: await res.json(), response };
}

/** Gets a union of paths which have method */
type PathsWith<M extends Method> = {
[Path in keyof T]: T[Path] extends { [ K in M ]: unknown } ? Path : never
}[keyof T];

type PathParams<U extends keyof T> = T[U] extends { parameters: any } ? { params: T[U]['parameters'] } : { params?: BaseParams };
type MethodParams<U extends keyof T, M extends keyof T[U]> = T[U][M] extends {
parameters: any;
Expand Down Expand Up @@ -139,35 +147,35 @@ export default function createClient<T>(defaultOptions?: ClientOptions) {

return {
/** Call a GET endpoint */
async get<U extends keyof T, M extends keyof T[U]>(url: T[U] extends { get: any } ? U : never, options: FetchOptions<U, M>) {
async get<U extends PathsWith<'get'>, M extends keyof T[U]>(url: U, options: FetchOptions<U, M>) {
return coreFetch(url, { ...options, method: 'GET' });
},
/** Call a PUT endpoint */
async put<U extends keyof T, M extends keyof T[U]>(url: T[U] extends { put: any } ? U : never, options: FetchOptions<U, M>) {
async put<U extends PathsWith<'put'>, M extends keyof T[U]>(url: U, options: FetchOptions<U, M>) {
return coreFetch(url, { ...options, method: 'PUT' });
},
/** Call a POST endpoint */
async post<U extends keyof T, M extends keyof T[U]>(url: T[U] extends { post: any } ? U : never, options: FetchOptions<U, M>) {
async post<U extends PathsWith<'post'>, M extends keyof T[U]>(url: U, options: FetchOptions<U, M>) {
return coreFetch(url, { ...options, method: 'POST' });
},
/** Call a DELETE endpoint */
async del<U extends keyof T, M extends keyof T[U]>(url: T[U] extends { delete: any } ? U : never, options: FetchOptions<U, M>) {
async del<U extends PathsWith<'delete'>, M extends keyof T[U]>(url: U, options: FetchOptions<U, M>) {
return coreFetch(url, { ...options, method: 'DELETE' });
},
/** Call a OPTIONS endpoint */
async options<U extends keyof T, M extends keyof T[U]>(url: T[U] extends { options: any } ? U : never, options: FetchOptions<U, M>) {
async options<U extends PathsWith<'options'>, M extends keyof T[U]>(url: U, options: FetchOptions<U, M>) {
return coreFetch(url, { ...options, method: 'OPTIONS' });
},
/** Call a HEAD endpoint */
async head<U extends keyof T, M extends keyof T[U]>(url: T[U] extends { head: any } ? U : never, options: FetchOptions<U, M>) {
async head<U extends PathsWith<'head'>, M extends keyof T[U]>(url: U, options: FetchOptions<U, M>) {
return coreFetch(url, { ...options, method: 'HEAD' });
},
/** Call a PATCH endpoint */
async patch<U extends keyof T, M extends keyof T[U]>(url: T[U] extends { patch: any } ? U : never, options: FetchOptions<U, M>) {
async patch<U extends PathsWith<'patch'>, M extends keyof T[U]>(url: U, options: FetchOptions<U, M>) {
return coreFetch(url, { ...options, method: 'PATCH' });
},
/** Call a TRACE endpoint */
async trace<U extends keyof T, M extends keyof T[U]>(url: T[U] extends { trace: any } ? U : never, options: FetchOptions<U, M>) {
async trace<U extends PathsWith<'trace'>, M extends keyof T[U]>(url: U, options: FetchOptions<U, M>) {
return coreFetch(url, { ...options, method: 'TRACE' });
},
};
Expand Down
58 changes: 58 additions & 0 deletions test/v1.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,64 @@ export interface paths {
};
};
};
"/anyMethod": {
get: {
responses: {
200: components["responses"]["User"];
404: components["responses"]["Error"];
500: components["responses"]["Error"];
};
};
put: {
responses: {
200: components["responses"]["User"];
404: components["responses"]["Error"];
500: components["responses"]["Error"];
};
};
post: {
responses: {
200: components["responses"]["User"];
404: components["responses"]["Error"];
500: components["responses"]["Error"];
};
};
delete: {
responses: {
200: components["responses"]["User"];
404: components["responses"]["Error"];
500: components["responses"]["Error"];
};
};
options: {
responses: {
200: components["responses"]["User"];
404: components["responses"]["Error"];
500: components["responses"]["Error"];
};
};
head: {
responses: {
200: components["responses"]["User"];
404: components["responses"]["Error"];
500: components["responses"]["Error"];
};
};
patch: {
responses: {
200: components["responses"]["User"];
404: components["responses"]["Error"];
500: components["responses"]["Error"];
};
};
trace: {
responses: {
200: components["responses"]["User"];
404: components["responses"]["Error"];
500: components["responses"]["Error"];
};
};
};
}

export type webhooks = Record<string, never>;
Expand Down
65 changes: 65 additions & 0 deletions test/v1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,71 @@ paths:
$ref: '#/components/responses/Error'
500:
$ref: '#/components/responses/Error'
/anyMethod:
get:
responses:
200:
$ref: '#/components/responses/User'
404:
$ref: '#/components/responses/Error'
500:
$ref: '#/components/responses/Error'
put:
responses:
200:
$ref: '#/components/responses/User'
404:
$ref: '#/components/responses/Error'
500:
$ref: '#/components/responses/Error'
post:
responses:
200:
$ref: '#/components/responses/User'
404:
$ref: '#/components/responses/Error'
500:
$ref: '#/components/responses/Error'
delete:
responses:
200:
$ref: '#/components/responses/User'
404:
$ref: '#/components/responses/Error'
500:
$ref: '#/components/responses/Error'
options:
responses:
200:
$ref: '#/components/responses/User'
404:
$ref: '#/components/responses/Error'
500:
$ref: '#/components/responses/Error'
head:
responses:
200:
$ref: '#/components/responses/User'
404:
$ref: '#/components/responses/Error'
500:
$ref: '#/components/responses/Error'
patch:
responses:
200:
$ref: '#/components/responses/User'
404:
$ref: '#/components/responses/Error'
500:
$ref: '#/components/responses/Error'
trace:
responses:
200:
$ref: '#/components/responses/User'
404:
$ref: '#/components/responses/Error'
500:
$ref: '#/components/responses/Error'

components:
schemas:
Expand Down

0 comments on commit 02c2bbb

Please sign in to comment.