Skip to content

Add generics to httpsCallable #4466

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 7 commits into from
Feb 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions common/api-review/functions-exp.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface Functions {
region: string;
}

// @public (undocumented)
// @public
export interface FunctionsError extends FirebaseError {
readonly code: FunctionsErrorCode;
readonly details?: unknown;
Expand All @@ -27,13 +27,13 @@ export type FunctionsErrorCode = 'ok' | 'cancelled' | 'unknown' | 'invalid-argum
export function getFunctions(app: FirebaseApp, regionOrCustomDomain?: string): Functions;

// @public
export interface HttpsCallable {
export interface HttpsCallable<RequestData = unknown, ResponseData = unknown> {
// (undocumented)
(data?: {} | null): Promise<HttpsCallableResult>;
(data?: RequestData | null): Promise<HttpsCallableResult<ResponseData>>;
}

// @public
export function httpsCallable(functionsInstance: Functions, name: string, options?: HttpsCallableOptions): HttpsCallable;
export function httpsCallable<RequestData = unknown, ResponseData = unknown>(functionsInstance: Functions, name: string, options?: HttpsCallableOptions): HttpsCallable<RequestData, ResponseData>;

// @public
export interface HttpsCallableOptions {
Expand All @@ -42,9 +42,9 @@ export interface HttpsCallableOptions {
}

// @public
export interface HttpsCallableResult {
export interface HttpsCallableResult<ResponseData = unknown> {
// (undocumented)
readonly data: unknown;
readonly data: ResponseData;
}

// @public
Expand Down
14 changes: 9 additions & 5 deletions packages-exp/functions-exp/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ export function getFunctions(
*
* Note: this must be called before this instance has been used to do any operations.
*
* @param host The emulator host (ex: localhost)
* @param port The emulator port (ex: 5001)
* @param host - The emulator host (ex: localhost)
* @param port - The emulator port (ex: 5001)
* @public
*/
export function useFunctionsEmulator(
Expand All @@ -74,10 +74,14 @@ export function useFunctionsEmulator(
* @param name - The name of the trigger.
* @public
*/
export function httpsCallable(
export function httpsCallable<RequestData = unknown, ResponseData = unknown>(
functionsInstance: Functions,
name: string,
options?: HttpsCallableOptions
): HttpsCallable {
return _httpsCallable(functionsInstance as FunctionsService, name, options);
): HttpsCallable<RequestData, ResponseData> {
return _httpsCallable<RequestData, ResponseData>(
functionsInstance as FunctionsService,
name,
options
);
}
7 changes: 5 additions & 2 deletions packages-exp/functions-exp/src/callable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ describe('Firebase Functions > Call', () => {
null: null
};

const func = httpsCallable(functions, 'dataTest');
const func = httpsCallable<
Record<string, any>,
{ message: string; code: number; long: number }
>(functions, 'dataTest');
const result = await func(data);

expect(result.data).to.deep.equal({
Expand All @@ -98,7 +101,7 @@ describe('Firebase Functions > Call', () => {

it('scalars', async () => {
const functions = createTestService(app, region);
const func = httpsCallable(functions, 'scalarTest');
const func = httpsCallable<number, number>(functions, 'scalarTest');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe at least the request (and maybe the response as well) must be objects. Scalars may not be allowed by the server-side implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a live test that sends a number to the server and successfully gets a number response so it seems to work, unless I'm misunderstanding. To make sure, I also created a new onCall function that logged a number sent to it and returned a number and tried it from a test app and it seems to work:

exports.numberTest = functions.https.onCall((data) => {
    console.log(data, typeof data);
    return(44);
});

Let me know if I misunderstood.

const result = await func(17);
expect(result.data).to.equal(76);
});
Expand Down
17 changes: 13 additions & 4 deletions packages-exp/functions-exp/src/public-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,24 @@ import { FirebaseError } from '@firebase/util';

/**
* An HttpsCallableResult wraps a single result from a function call.
* @public
*/
export interface HttpsCallableResult {
readonly data: unknown;
export interface HttpsCallableResult<ResponseData = unknown> {
readonly data: ResponseData;
}

/**
* An HttpsCallable is a reference to a "callable" http trigger in
* Google Cloud Functions.
* @public
*/
export interface HttpsCallable {
(data?: {} | null): Promise<HttpsCallableResult>;
export interface HttpsCallable<RequestData = unknown, ResponseData = unknown> {
(data?: RequestData | null): Promise<HttpsCallableResult<ResponseData>>;
}

/**
* HttpsCallableOptions specify metadata about how calls should be executed.
* @public
*/
export interface HttpsCallableOptions {
timeout?: number; // in millis
Expand All @@ -42,6 +45,7 @@ export interface HttpsCallableOptions {
/**
* `Functions` represents a Functions instance, and is a required argument for
* all Functions operations.
* @public
*/
export interface Functions {
/**
Expand Down Expand Up @@ -100,6 +104,7 @@ export interface Functions {
* - 'data-loss': Unrecoverable data loss or corruption.
* - 'unauthenticated': The request does not have valid authentication
* credentials for the operation.
* @public
*/
export type FunctionsErrorCode =
| 'ok'
Expand All @@ -120,6 +125,10 @@ export type FunctionsErrorCode =
| 'data-loss'
| 'unauthenticated';

/**
* An error returned by the Firebase Functions client SDK.
* @public
*/
export interface FunctionsError extends FirebaseError {
/**
* A standard error code that will be returned to the client. This also
Expand Down
8 changes: 4 additions & 4 deletions packages-exp/functions-exp/src/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,14 @@ export function useFunctionsEmulator(
* @param name - The name of the trigger.
* @public
*/
export function httpsCallable(
export function httpsCallable<RequestData, ResponseData>(
functionsInstance: FunctionsService,
name: string,
options?: HttpsCallableOptions
): HttpsCallable {
return data => {
): HttpsCallable<RequestData, ResponseData> {
return (data => {
return call(functionsInstance, name, data, options || {});
};
}) as HttpsCallable<RequestData, ResponseData>;
}

/**
Expand Down