/**
 * @module rest-ts-core
 */
import { AEndpointBuilder, HttpMethod, ApiDefinition, EndpointDefinition, SafeQueryParams, QueryParams } from './types';
import { RemoveKey } from './private/ts-kung-fu';
/**
 * Builder class to create endpoint definitions.
 *
 * This class provides a high-level user friendly interface to create a typed definition of an API endpoint.
 *
 * Endpoint definitions are usually grouped together in API definitions, which can be shared between producers
 * and consumers of the API to create a type-safe communication channel.
 *
 * You will generally not need to create this class explicitly. Instead, use the helper methods [[GET]], [[PUT]],
 * [[PATCH]], [[POST]] or [[DELETE]] to create an instance of EndpointBuilder.
 */
export declare class EndpointBuilder<T extends Partial<EndpointDefinition>> implements AEndpointBuilder<T> {
    readonly def: Readonly<T>;
    constructor(def: Readonly<T>);
    /**
     * Change the HTTP method of this endpoint
     * @param method Any valid HTTP method. See [[HttpMethod]].
     */
    method<U extends HttpMethod>(method: U): EndpointBuilder<RemoveKey<T, 'method'> & {
        method: U;
    }>;
    /**
     * Change the type of the response.
     *
     * You must provide a real object whose type will be inferred and used as the response type for this endpoint.
     * Rest.ts offers multiple ways to do this:
     *
     * 1. Use a regular object.
     * For instance, if you need a string, use `'string'`, if you need a number, use `123`.
     * This also works for complex objects like so:
     *
     *         GET `/current-user`
     *             .response({
     *                 id: 'string',
     *                 kind: 'person' as 'person' | 'robot' | 'cat'
     *             })
     *
     * 2. Some people like to use classes to define their DTOs. If this is your situation, you may just put the
     * class constructor here, and the instance type will be inferred.
     *
     *         class CurrentUserDTO {
     *             id: string;
     *             kind: 'person' | 'robot' | 'cat';
     *         }
     *
     *         GET `/current-user`
     *             .response(CurrentUserDTO)
     *
     * 3. **(Preferred method)** Use a Runtype. [runtypes](https://github.com/pelotom/runtypes) is a
     * library that allows you to create type definitions with runtime type metadata to ensure that
     * input data conforms to an expected type.
     * Rest.ts has first-class support for runtypes:
     *
     *         const CurrentUserDTO = rt.Record({
     *              id: rt.String,
     *              kind: rt.Union(
     *                  rt.String('person'),
     *                  rt.String('robot'),
     *                  rt.String('cat')
     *              )
     *         });
     *
     *         GET `/current-user`
     *              .response(CurrentUserDTO)
     *
     * @param response type of the response data.
     */
    response<U extends EndpointDefinition['response']>(response: U): EndpointBuilder<RemoveKey<T, 'response'> & {
        response: U;
    }>;
    /**
     * Change the type of the request body.
     *
     * You must provide a real object whose type will be inferred and used as the response type for this endpoint.
     * Rest.ts offers multiple ways to do this:
     *
     * 1. Use a regular object.
     * For instance, if you need a string, use `'string'`, if you need a number, use `123`.
     * This also works for complex objects like so:
     *
     *         POST `/current-user`
     *             .body({
     *                 id: 'string',
     *                 kind: 'person' as 'person' | 'robot' | 'cat'
     *             })
     *
     * 2. Some people like to use classes to define their DTOs. If this is your situation, you may just put the
     * class constructor here, and the instance type will be inferred.
     *
     *         class CurrentUserDTO {
     *             id: string;
     *             kind: 'person' | 'robot' | 'cat';
     *         }
     *
     *         POST `/current-user`
     *             .body(CurrentUserDTO)
     *
     * 3. **(Preferred method)** Use a Runtype. [runtypes](https://github.com/pelotom/runtypes) is a
     * library that allows you to create type definitions with runtime type metadata to ensure that
     * input data conforms to an expected type.
     * Rest.ts has first-class support for runtypes:
     *
     *         const CurrentUserDTO = rt.Record({
     *              id: rt.String,
     *              kind: rt.Union(
     *                  rt.String('person'),
     *                  rt.String('robot'),
     *                  rt.String('cat')
     *              )
     *         });
     *
     *         POST `/current-user`
     *              .body(CurrentUserDTO)
     *
     * rest-ts-express automatically type-checks incoming data when the body of the endpoint definition is a runtype.
     *
     * @param response type of the response data.
     */
    body<U extends EndpointDefinition['body']>(body: U): EndpointBuilder<RemoveKey<T, 'body'> & {
        body: U;
    }>;
    /**
     * Add query parameters.
     *
     * Note that query parameters are always optional.
     *
     * Example:
     *
     *         GET `/users/search`
     *             .query({
     *                 'order': 'string',
     *                 'filter': 'string'
     *             })
     *
     * @param query type of the query parameters.
     */
    // @ts-ignore
    query<U extends QueryParams>(query: SafeQueryParams<U>): EndpointBuilder<RemoveKey<T, 'query'> & {
        query: SafeQueryParams<U>;
    }>;
}
export interface InitialEndpointDefinition<Params, METHOD extends HttpMethod | undefined> {
    path: string[];
    params: Params;
    method: METHOD;
    response: undefined;
}
export interface EmptyInitialEndpointDefinition<METHOD extends HttpMethod | undefined> {
    path: string[];
    method: METHOD;
    response: undefined;
}
/**
 * Create a GET endpoint definition.
 *
 * Use of the template literal allows to easily add dynamic path parameters to the endpoint definition, as shown in the example below.
 *
 * Use as a tagged template literal to add path parameters to the endpoint, and use methods of
 * the [[EndpointBuilder]] class to customize the endpoint definition.
 *
 * This endpoint definition can be consumed by API servers and clients such as rest-ts-express and rest-ts-axios.
 *
 * Example:
 *
 *         export const carsAPI = defineAPI({
 *             // Get emissions test results for a given car.
 *             // For example: GET /cars/VW_Golf_TDI/results => "OK"
 *             getCarTestResults: GET `/cars/${'model'}/results`
 *                 .response(CarTestResults)
 *         });
 */
export declare function GET(path: string | TemplateStringsArray): EndpointBuilder<EmptyInitialEndpointDefinition<'GET'>>;
export declare function GET<A extends string>(strings: TemplateStringsArray, a: A): EndpointBuilder<InitialEndpointDefinition<[A], 'GET'>>;
export declare function GET<A extends string, B extends string>(strings: TemplateStringsArray, a: A, b: B): EndpointBuilder<InitialEndpointDefinition<[A, B], 'GET'>>;
export declare function GET<A extends string, B extends string, C extends string>(strings: TemplateStringsArray, a: A, b: B, c: C): EndpointBuilder<InitialEndpointDefinition<[A, B, C], 'GET'>>;
export declare function GET<A extends string, B extends string, C extends string, D extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D], 'GET'>>;
export declare function GET<A extends string, B extends string, C extends string, D extends string, E extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E], 'GET'>>;
export declare function GET<A extends string, B extends string, C extends string, D extends string, E extends string, F extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E, f: F): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E, F], 'GET'>>;
export declare function GET<A extends string, B extends string, C extends string, D extends string, E extends string, F extends string, G extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E, f: F, g: G): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E, F, G], 'GET'>>;
export declare function GET<A extends string, B extends string, C extends string, D extends string, E extends string, F extends string, G extends string, H extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E, F, G, H], 'GET'>>;
/**
 * Create a PUT endpoint definition.
 *
 * Use of the template literal allows to easily add dynamic path parameters to the endpoint definition, as shown in the example below.
 *
 * Use as a tagged template literal to add path parameters to the endpoint, and use methods of
 * the [[EndpointBuilder]] class to customize the endpoint definition.
 *
 * This endpoint definition can be consumed by API servers and clients such as rest-ts-express and rest-ts-axios.
 *
 * Example:
 *
 *         export const carsAPI = defineAPI({
 *             // Edit a car in the list
 *             // For example: PUT /cars/123/edit
 *             editCar: PUT `/cars/${'id'}/edit`
 *                 .body(CarAttributes)
 *                 .response(CarSaveResponse)
 *         });
 */
export declare function PUT(path: string | TemplateStringsArray): EndpointBuilder<EmptyInitialEndpointDefinition<'PUT'>>;
export declare function PUT<A extends string>(strings: TemplateStringsArray, a: A): EndpointBuilder<InitialEndpointDefinition<[A], 'PUT'>>;
export declare function PUT<A extends string, B extends string>(strings: TemplateStringsArray, a: A, b: B): EndpointBuilder<InitialEndpointDefinition<[A, B], 'PUT'>>;
export declare function PUT<A extends string, B extends string, C extends string>(strings: TemplateStringsArray, a: A, b: B, c: C): EndpointBuilder<InitialEndpointDefinition<[A, B, C], 'PUT'>>;
export declare function PUT<A extends string, B extends string, C extends string, D extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D], 'PUT'>>;
export declare function PUT<A extends string, B extends string, C extends string, D extends string, E extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E], 'PUT'>>;
export declare function PUT<A extends string, B extends string, C extends string, D extends string, E extends string, F extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E, f: F): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E, F], 'PUT'>>;
export declare function PUT<A extends string, B extends string, C extends string, D extends string, E extends string, F extends string, G extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E, f: F, g: G): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E, F, G], 'PUT'>>;
export declare function PUT<A extends string, B extends string, C extends string, D extends string, E extends string, F extends string, G extends string, H extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E, F, G, H], 'PUT'>>;
/**
 * Create a POST endpoint definition.
 *
 * Use of the template literal allows to easily add dynamic path parameters to the endpoint definition, as shown in the example below.
 *
 * Use as a tagged template literal to add path parameters to the endpoint, and use methods of
 * the [[EndpointBuilder]] class to customize the endpoint definition.
 *
 * This endpoint definition can be consumed by API servers and clients such as rest-ts-express and rest-ts-axios.
 *
 * Example:
 *
 *         export const commentsAPI = defineAPI({
 *             // Add a comment to an article
 *             // For example: POST /article/123/comment
 *             addComment: POST `/article/${'id'}/comment`
 *                 .body(CommentAttributes)
 *                 .response(CommentSaveResponse)
 *         });
 */
export declare function POST(path: string | TemplateStringsArray): EndpointBuilder<EmptyInitialEndpointDefinition<'POST'>>;
export declare function POST<A extends string>(strings: TemplateStringsArray, a: A): EndpointBuilder<InitialEndpointDefinition<[A], 'POST'>>;
export declare function POST<A extends string, B extends string>(strings: TemplateStringsArray, a: A, b: B): EndpointBuilder<InitialEndpointDefinition<[A, B], 'POST'>>;
export declare function POST<A extends string, B extends string, C extends string>(strings: TemplateStringsArray, a: A, b: B, c: C): EndpointBuilder<InitialEndpointDefinition<[A, B, C], 'POST'>>;
export declare function POST<A extends string, B extends string, C extends string, D extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D], 'POST'>>;
export declare function POST<A extends string, B extends string, C extends string, D extends string, E extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E], 'POST'>>;
export declare function POST<A extends string, B extends string, C extends string, D extends string, E extends string, F extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E, f: F): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E, F], 'POST'>>;
export declare function POST<A extends string, B extends string, C extends string, D extends string, E extends string, F extends string, G extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E, f: F, g: G): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E, F, G], 'POST'>>;
export declare function POST<A extends string, B extends string, C extends string, D extends string, E extends string, F extends string, G extends string, H extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E, F, G, H], 'POST'>>;
/**
 * Create a DELETE endpoint definition.
 *
 * Use of the template literal allows to easily add dynamic path parameters to the endpoint definition, as shown in the example below.
 *
 * Use as a tagged template literal to add path parameters to the endpoint, and use methods of
 * the [[EndpointBuilder]] class to customize the endpoint definition.
 *
 * This endpoint definition can be consumed by API servers and clients such as rest-ts-express and rest-ts-axios.
 *
 * Example:
 *
 *         export const commentsAPI = defineAPI({
 *             // Remove a comment
 *             // For example: DELETE /comments/123
 *             removeComment: DELETE `/comments/${'id'}`
 *                 .response(CommentDeleteResponse)
 *         });
 */
export declare function DELETE(path: string | TemplateStringsArray): EndpointBuilder<EmptyInitialEndpointDefinition<'DELETE'>>;
export declare function DELETE<A extends string>(strings: TemplateStringsArray, a: A): EndpointBuilder<InitialEndpointDefinition<[A], 'DELETE'>>;
export declare function DELETE<A extends string, B extends string>(strings: TemplateStringsArray, a: A, b: B): EndpointBuilder<InitialEndpointDefinition<[A, B], 'DELETE'>>;
export declare function DELETE<A extends string, B extends string, C extends string>(strings: TemplateStringsArray, a: A, b: B, c: C): EndpointBuilder<InitialEndpointDefinition<[A, B, C], 'DELETE'>>;
export declare function DELETE<A extends string, B extends string, C extends string, D extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D], 'DELETE'>>;
export declare function DELETE<A extends string, B extends string, C extends string, D extends string, E extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E], 'DELETE'>>;
export declare function DELETE<A extends string, B extends string, C extends string, D extends string, E extends string, F extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E, f: F): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E, F], 'DELETE'>>;
export declare function DELETE<A extends string, B extends string, C extends string, D extends string, E extends string, F extends string, G extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E, f: F, g: G): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E, F, G], 'DELETE'>>;
export declare function DELETE<A extends string, B extends string, C extends string, D extends string, E extends string, F extends string, G extends string, H extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E, F, G, H], 'DELETE'>>;
/**
 * Create a PATCH endpoint definition.
 *
 * Use of the template literal allows to easily add dynamic path parameters to the endpoint definition, as shown in the example below.
 *
 * Use as a tagged template literal to add path parameters to the endpoint, and use methods of
 * the [[EndpointBuilder]] class to customize the endpoint definition.
 *
 * This endpoint definition can be consumed by API servers and clients such as rest-ts-express and rest-ts-axios.
 *
 * Example:
 *
 *         export const commentsAPI = defineAPI({
 *             // Edit a comment
 *             // For example: PATCH /article/123/comment/2
 *             editComment: PATCH `/article/${'id'}/comment/${'commentId'}`
 *                 .body(CommentAttributes)
 *                 .response(CommentSaveResponse)
 *         });
 */
export declare function PATCH(path: string | TemplateStringsArray): EndpointBuilder<EmptyInitialEndpointDefinition<'PATCH'>>;
export declare function PATCH<A extends string>(strings: TemplateStringsArray, a: A): EndpointBuilder<InitialEndpointDefinition<[A], 'PATCH'>>;
export declare function PATCH<A extends string, B extends string>(strings: TemplateStringsArray, a: A, b: B): EndpointBuilder<InitialEndpointDefinition<[A, B], 'PATCH'>>;
export declare function PATCH<A extends string, B extends string, C extends string>(strings: TemplateStringsArray, a: A, b: B, c: C): EndpointBuilder<InitialEndpointDefinition<[A, B, C], 'PATCH'>>;
export declare function PATCH<A extends string, B extends string, C extends string, D extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D], 'PATCH'>>;
export declare function PATCH<A extends string, B extends string, C extends string, D extends string, E extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E], 'PATCH'>>;
export declare function PATCH<A extends string, B extends string, C extends string, D extends string, E extends string, F extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E, f: F): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E, F], 'PATCH'>>;
export declare function PATCH<A extends string, B extends string, C extends string, D extends string, E extends string, F extends string, G extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E, f: F, g: G): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E, F, G], 'PATCH'>>;
export declare function PATCH<A extends string, B extends string, C extends string, D extends string, E extends string, F extends string, G extends string, H extends string>(strings: TemplateStringsArray, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H): EndpointBuilder<InitialEndpointDefinition<[A, B, C, D, E, F, G, H], 'PATCH'>>;
/**
 * Create an API definition to share across producers and consumers of the API.
 *
 * The usual workflow of rest-ts-core goes like this:
 *
 * 1. Create an API definition:
 *
 *         const myAwesomeAPI = defineAPI({
 *             someEndpoint: GET `/some/path`
 *                 .response(SomeResponseDTO)
 *         });
 *
 * 2. Create a server for this API.
 * rest-ts-express allows you to import the API definition you just created and
 * turn it into an express router. See the documentation for that package for more details.
 *
 * 3. Create a consumer for this API.
 * rest-ts-axios lets you create a typed instance of [axios](https://github.com/axios/axios) to
 * perform requests to your API.
 *
 * 4. ... Profit!
 *
 *
 * Notice: Unless you are authoring an adapter for Rest.ts, you should always treat the return type of this function
 * as an opaque type. Use the utilities provided by this library to create the API definition within the brackets
 * of `defineAPI({ ... })`, and export the resulting symbol to be consumed by your server and client(s).
 * The type you get from `defineAPI` is very complex, and for a good reason: it encodes all of the type information
 * of your API! It is pointless to inspect the raw type you get. Instead, we  recommend that you feed it directly
 * to a compatible binding library such as rest-ts-express and rest-ts-axios. These libraries are able to decode
 * the complex type and make sense out of it.
 *
 * @param api
 */
export declare const defineAPI: <T extends ApiDefinition>(api: T) => T;
