/redux-saga-firebase

A redux saga integration for firebase.

Primary LanguageJavaScript

redux-saga-firebase

CircleCI npm version Coverage Status bitHound Overall Score

A redux-saga integration for firebase.

Try out the example app and browse its code.

Quick start

Install with:

yarn add redux-saga-firebase

Initialize a firebase app and instanciate redux-saga-firebase:

import firebase from 'firebase';
import ReduxSagaFirebase from 'redux-saga-firebase';

const myFirebaseApp = firebase.initializeApp({
  apiKey: "qosjdqsdkqpdqldkqdkfojqjpfk",
  authDomain: "my-app.firebaseapp.com",
  databaseURL: "https://my-app.firebaseio.com",
});

const reduxSagaFirebase = new ReduxSagaFirebase(myFirebaseApp)

You can now use reduxSagaFirebase methods in your sagas:

const authProvider = new firebase.auth.GoogleAuthProvider();

function* loginSaga() {
  try {
    const data = yield call(reduxSagaFirebase.login, authProvider);
    yield put(loginSuccess(data));
  }
  catch(error) {
    yield put(loginFailure(error));
  }
}

export default function* rootSaga() {
  yield [
    takeEvery(types.LOGIN.REQUEST, loginSaga);
  ];
}

API

new ReduxSagaFirebase(firebaseApp)

Instanciate ReduxSagaFirebase.

Arguments

Output

A ReduxSagaFirebase instance.

Example

const firebaseApp = firebase.initializeApp({
  apiKey: "qdsqdqqsdmqldmqdsmlqùlm",
  authDomain: "my-app.firebaseapp.com",
  databaseURL: "https://my-app.firebaseio.com",
});

const rsf = new ReduxSagaFirebase(firebaseApp);

*reduxSagaFirebase.login(authProvider)

Starts the login process using the specified AuthProvider. (generator)

Arguments

Output

A firebase.auth.AuthCredential instance.

Example

const authProvider = new firebase.auth.GoogleAuthProvider();

function* loginSaga() {
  try {
    const data = yield call(rsf.login, authProvider);
    yield put(loginSuccess(data));
  }
  catch(error) {
    yield put(loginFailure(error));
  }
}

*reduxSagaFirebase.logout()

Logs the user out. (generator)

Arguments

none

Output

none

Example

function* logoutSaga() {
  try {
    const data = yield call(rsf.logout);
    yield put(logoutSuccess(data));
  }
  catch(error) {
    yield put(logoutFailure(error));
  }
}

reduxSagaFirebase.authChannel()

Gets a redux-saga Channel which emits every user change.

Arguments

none

Output

A redux-saga Channel which emits for every user change.

Example

function* syncUserSaga() {
  const channel = yield call(rsf.authChannel);

  while(true) {
    const { error, user } = yield take(channel);

    if (user) yield put(syncUser(user));
    else yield put(syncError(error));
  }
}

*reduxSagaFirebase.get(path)

Returns the data at this path in firebase's database.

Arguments

  • path: a string

Output

Whatever value is store at this path in the database (number, string, object, etc).

Example

function* getTodo() {
  const firstTodo = yield call(rsf.get, 'todos/1');
  yield put(gotTodo(firstTodo));
}

*reduxSagaFirebase.create(path, data)

Create a new path in the database and stores the data there.

Arguments

  • path: a string
  • data: any value (number, string, object, etc)

Output

The key newly created (a string).

Example

function* addTodo() {
  const key = yield call(rsf.create, 'todos', {
    done: false,
    label: 'Do this',
  });
  // `key` is something like "-Kfn7EyLEoHax0YGoQr0"
}

*reduxSagaFirebase.update(path, data)

Replace the value store at path in the database with data.

Arguments

  • path: a string
  • data: any value (number, string, object, etc)

Output

none

Example

function* updateTodo() {
  yield call(rsf.update, 'todos/-Kfn7EyLEoHax0YGoQr0', {
    done: true, // yay, it's done now!
    label: 'Do this',
  });
}

*reduxSagaFirebase.patch(path, data)

Patches the value store at path in the database with data. Like reduxSagaFirebase.update but doesn't remove unmentionned keys.

Arguments

  • path: a string
  • data: any value (number, string, object, etc)

Output

none

Example

function* updateTodo() {
  // With this call, no need to re-send the todo label.
  yield call(rsf.patch, 'todos/-Kfn7EyLEoHax0YGoQr0', {
    done: true,
  });
}

*reduxSagaFirebase.delete(path)

Removes the value at the specified path in the database.

Arguments

  • path: a string

Output

none

Example

function* deleteTodo() {
  yield call(rsf.delete, 'todos/-Kfn7EyLEoHax0YGoQr0');
}

reduxSagaFirebase.channel(path, event)

Returns a redux-saga Channel which emits every change at the specified path in the database.

Arguments

  • path: a string
  • event (default: value): a string describing the type of event to listen for. Options includes: value, child_added, child_removed, child_changed and child_moved. See Reference.on documentation for more information.

Output

A redux-saga Channel which emits every change at the specified path in the database.

Example

function* syncTodosSaga() {
  const channel = yield call(rsf.channel, 'todos');

  while(true) {
    const todos = yield take(channel);
    yield put(syncTodos(todos));
  }
}

*reduxSagaFirebase.call(functionName, parameters={})

Calls a cloud function with the given parameters. The function has to be triggered by HTTP request.

⚠️ You will need to enable CORS in order for this to work. The easiest way to do so is to use the cors middleware for express.

This assumes that your functions are hosted in the us-central1 region. If this is not the case you can change the region used by setting rsf.region:

const rsf = new ReduxSagaFirebase(...);
rsf.region = 'other-region1';

Arguments

  • functionName: a string representing the function name. This will be used as a pathname in the https request.
  • parameters (default: {}): a javascript object describing the query parameters to use in the http request.

Output

A javascript object (application/json) or a string (anything else) depending on the Content-Type of the response.

Example

function* callFunction() {
  // Will call: https://us-central1-project-id.firebaseapp.com/sayHello?name=Alfred
  const result = yield call(rsf.call, 'sayHello', {
    name: 'Alfred'
  });

  // `result` is either an object or a string (depends on response's Content-Type)
}

reduxSagaFirebase.messageChannel()

Returns a redux-saga Channel which emits for every message received.

Arguments

none

Output

A redux-saga Channel which emits for every message received.

Example

function* readMessages() {
  const channel = rsf.messageChannel();

  while(true) {
    const message = yield take(channel);
    yield put(showMessage(message));
  }
}

reduxSagaFirebase.tokenRefreshChannel()

Returns a redux-saga Channel which emits every time the registration token is refreshed.

Arguments

none

Output

A redux-saga Channel which emits every time the registration token is refreshed.

Example

function* refreshToken() {
  const channel = rsf.tokenRefreshChannel();

  while(true) {
    const token = yield take(channel);
    yield put(setToken(token));
  }
}

*reduxSagaFirebase.upload(path, file, metadata)

Uploads a file to cloud storage.

Arguments

  • path: a string representing the path of the file in the bucket.
  • file: a Blob, a File or an Uint8Array to upload at the specified path.
  • metadata (optional): an UploadMetadata object.

Output

An UploadTask object.

Example

function* uploadFile(action) {
  const task = yield call(rsf.upload, action.path, action.file);

  const channel = eventChannel(emit => task.on('state_changed', emit));

  yield takeEvery(channel, ...);
}

*reduxSagaFirebase.uploadString(path, string, format, metadata)

Use this to upload a raw, base64, base64url, or data_url encoded string to Cloud Storage.

Arguments

  • path: a string representing the path of the file in the bucket.
  • string: a string to upload.
  • format (optional): a string. Available options are: base64, base64url, or data_url.
  • metadata (optional): an UploadMetadata object.

Output

An UploadTask object.

Example

function* uploadString(action) {
  const task = yield call(rsf.uploadString, action.path, action.fileData, 'base64');

  const channel = eventChannel(emit => task.on('state_changed', emit));

  yield takeEvery(channel, ...);
}

*reduxSagaFirebase.getDownloadURL(path)

Returns a download url for the file at the specified path.

Arguments

  • path: a string representing the path of the file in the bucket.

Output

A url as a string.

Example

function* downloadFile(action) {
  const url = yield call(rsf.getDownloadURL, action.path);

  yield call(fetch, url, ...);
}

*reduxSagaFirebase.getFileMetadata(path)

Arguments

  • path: a string representing the path of the file in the bucket.

Output

A FullMetadata object.

Example

function* metadata(action) {
  const metadata = yield call(rsf.getFileMetadata, action.path);
  return metadata;
}

*reduxSagaFirebase.updateFileMetadata(path, newMetadata)

Updates the metadata for a file.

Arguments

  • path: a string representing the path of the file in the bucket.
  • newMetadata: an object with keys from the SettableMetadata interface.

Output

A FullMetadata object.

Example

function* setToPng(action) {
  const metadata = yield call(rsf.updateFileMetadata, action.path, {
    contentType: 'image/png'
  });
  return metadata;
}

*reduxSagaFirebase.deleteFile(path)

Deletes a file.

Arguments

  • path: a string representing the path of the file in the bucket.

Output

none

Example

function* deleteFile(action) {
  yield call(rsf.deleteFile, action.path);
}

Todo

  • Authentication integration
  • Real-time database integration
  • Functions integration
  • Messaging integration
  • Storage integration