How to connect google-cloud-firestore to swift? - node.js

I was unable to connect Firestore-cloud to xcode using Firestore-CLI, but was unable to do so.
So, Now, I am trying to connect Firestore to serverless - https://firebase.google.com/docs/firestore/extend-with-functions , which in console is -
https://console.cloud.google.com .
I have the following functions -
1). the function in the given example is - "helloWorld" , the code is -
exports.helloWorld = (req, res) => {
let message = req.query.message || req.body.message || 'Hello World!';
res.status(200).send(message);
};
-- It gets deployed as - https://myregion-testpro-92351.cloudfunctions.net/function-1
2). I have also tested another function "helloHttp", the code is -
exports.helloHttp = (req, res) => {
res.send(`Hello ${escapeHtml(req.query.name || req.body.name || 'World')}!`);
};
-- It gets deployed as - https://myregion-testpro-92351.cloudfunctions.net/function-5
The above functions gets deployed successfully.
Also, my swift Viewcontroller code is -
import UIKit
import Firebase
class TestViewController:
UIViewController {
#IBAction func Test(_ sender: Any) { } }
The package.json for both the above functions is -
{
"name": "sample-http",
"version": "0.0.1"
}
I have the following question -
What should I put inside the button - "#IBAction func Test(_ sender: Any) { } }" in "TestViewController" above to make both functions, 1). "function-1", i.e. "helloWorld" and 2). "function-5", i.e. "helloHttp" print "HelloWorld" in xcode console.

I did something like this not too long ago, to deploy functions for your app's functionality, deploy them from terminal.
To execute a function and/or pass in parameters, from within your app, you can use AlamoFire. Each function has it's own URL which AlamoFire can retrieve and from there on you may wish to pass through whatever data is needed.

Related

Netlify functions not found on dev server

I have followed several blogs and questions related to the same problem I am having. It is exactly like this question. However, I am still having issues.
So, I am running netlify dev and trying to access my netlify functions. I have a function in /netlify/functions/ping. The function works as intended when I access the randomized port for the netlify functions (something like localhost:55832...).
However, using the localhost:8888/.netlify/functions/ping gives me a 404 error.
Here is my /netlify/functions/ping file:
import { Handler } from '#netlify/functions';
const handler: Handler = async (event, context) => {
return {
statusCode: 200,
body: JSON.stringify({ data: "pong" }),
};
};
export { handler };
here is where I am trying to call my function on a page
export default function HomePage() {
useEffect(() => {
async function pingpong() {
const res = await fetch(`/.netlify/functions/ping`);
console.log(res);
}
pingpong();
}, []);
return (
...
I have also tried to alter my netlify.toml with the following
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/:splat"
status = 200
force = true
what's start script you use in package.json?
Keep in mind that, to enable Netlify Functions you have to use netlify-cli, i.e. ntl command to run on local dev server.
No more specific configuration, just follow docs, and use that simple netlify/functions/hello.js example.
Then run using ntl dev, you function will be avaiable on /.netlify/functions/hello. easy.

Nodejs/Mocha - FieldValue.increment - FirebaseError: Function DocumentReference.update() called with invalid data

I have the following code:
NOTE getDb() is wrapper around admin.firestore() see the link in the end of the question for more details.
let wordRef = await getDb().
.collection(DOC_HAS_WORD_COUNT)
.doc(word)
await wordRef.set({ word: word, 'count': 0 })
await wordRef.update('count', admin.firestore.FieldValue.increment(1))
When I execute it I get
FirebaseError: Function DocumentReference.update() called with invalid data. Unsupported field value: a custom object (found in field count)
How do I increment the value in node js, firestore, cloud functions?
NOTE: this problem is specific to Mocha testing, I didn't check but it will probably not fail on real env.
The problem is caused by the code using the real implementation in test, which need to be override by an emulator implementation, as explain in:
https://claritydev.net/blog/testing-firestore-locally-with-firebase-emulators/
Where u can also find the definition of getDb() I used in the code snipet
The following code will replace the firebase admin at run time, only when running in test env.
NOTE: this code is based on https://claritydev.net/blog/testing-firestore-locally-with-firebase-emulators/
and for a full solution, one need to do the same trick for db as explained in the link
//db.js
const admin = require("firebase-admin");
let firebase;
if (process.env.NODE_ENV !== "test") {
firebase = admin
}
exports.getFirebase = () => {
return firebase;
};
exports.setFirebase = (fb) => {
firebase = fb;
};
test:
// package.test.js
process.env.NODE_ENV = "test"
beforeEach(() => {
// Set the emulator firebase before each test
setFirebase(firebase)
});
import:
// package.test.js and package.js (at the top)
const { setFirebase } = require("../db.js")
code:
// package.js
let wordRef = await getDb()
.collection(DOC_HAS_WORD_COUNT)
.doc(word)
await wordRef.set({ word: word, 'count': 0 })
await wordRef.update('count', getFirebase().firestore.FieldValue.increment(1))

Dynamically exporting functions in firebase

I'm having the typical (according to many posts) issue with cold boot times in cloud functions. A solution that seemed promised suggests to import / export only the function actually being executed, as can be seen here:
https://github.com/firebase/functions-samples/issues/170#issuecomment-323375462
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'sendFollowerNotification') {
exports.sendFollowerNotification = require('./sendFollowerNotification');
}
Which is a Javascript example, but I'm using typescript. I've tried a number of variations, and while some build, in the end I'm always stuck with my function not being exported and deploy warning me that I'm going to delete the existing function.
This is one of the numerous attempts:
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'generateInviteURL') {
import ('./invite_functions').then ((mod) => { console.log ("mod follows" ); console.log (mod); exports.generateInviteURL = functions.https.onRequest( mod.generateInviteURL ); } )
.catch ((err) => {console.log ("Trying to import/export generateInviteURL ", err);}) ;
}
At mentioned, at deploy time what happens is that I get a warning about the function being deleted.
I was able to "avoid" that message with something like this:
console.log ("Function name: ", process.env.FUNCTION_NAME);
function dummy_generateInviteURL (req, res) { ; }
exports.generateInviteURL = functions.https.onRequest( dummy_generateInviteURL );
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'generateInviteURL') {
console.log ("Doing the good import");
import ('./invite_functions').then ((mod) => { console.log ("mod follows" ); console.log (mod); exports.generateInviteURL = functions.https.onRequest( mod.generateInviteURL ); } )
.catch ((err) => {console.log ("Trying to import/export generateInviteURL ", err);}) ;
}
console.log ("Exported");
console.log (exports.generateInviteURL);
Which the idea of course that an empty function would be always be exported but would be replaced with the real one if that's the one being called.
In that case logs look like this:
generateInviteURL Function name: generateInviteURL generateInviteURL
generateInviteURL Exported generateInviteURL
{ [Function: cloudFunction] __trigger: { httpsTrigger: {} } }
So the first part looks promising (the environment variable is defined), then the import does something (enters the then block, never the catch), but the exported variable is not replaced.
I'm not sure if this is a TypeScript problem, a firebase problem, or a developer problem - probably I'm just missing something obvious.
So the question - how can I avoid importing/exporting anything I don't need for each specific function?
You can stick to the original index.js, with minor changes. I have tried a few times and came with a solution. Am including a sample dir structure and two typescript files (index.ts and another for your custom function). With this you will never have to change the index.ts to modify or add functions.
Directory Structure
+ functions
|
-- + src
| |
| -- index.ts
| |
| -- + get
| |
| -- status.f.ts
-- package.json (auto generated)
|
-- package-lock.json (auto generated)
|
-- tsconfig.json (auto generated)
|
-- tslint.json (auto generated)
|
-- + lib (auto generated)
|
-- + node_modules (auto generated)
src/index.ts
import * as glob from "glob";
import * as camelCase from "camelcase";
const files = glob.sync('./**/*.f.js', { cwd: __dirname, ignore: './node_modules/**'});
for(let f=0,fl=files.length; f<fl; f++){
const file = files[f];
const functionName = camelCase(file.slice(0, -5).split('/').join('_')); // Strip off '.f.js'
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === functionName) {
exports[functionName] = require(file);
}
}
src/get/status.f.ts
import * as functions from 'firebase-functions';
exports = module.exports = functions.https.onRequest((req, res) => {
res.status(200).json({'status':'OK'})
})
Once you have created the above file install npm packages 'glob' and 'camelcase',
then try to deploy the firebase functions
Firebase will deploy a function named 'getStatus'
NOTE that the name of the function is camel case version of folder names and the file name where the function exists, so you can export only one function per .f.ts file
EDIT
I have updated the dir structure. Note that index.ts and all the subsequent files and folders resides within the parent folder 'src'
I've been having similar issues, and I wrote a pretty cool solution that worked for me.
I decided to release it as an open-source package - I've never done that before so if anyone can check it out, contribute or give feedback that would be great.
The package is called better-firebase-functions - https://www.npmjs.com/package/better-firebase-functions
All you have to do is import and run it. Two lines. Pretty much everything else is automated.
It will pick up the default exports of all function files in your directory and deploy them as properly named functions.
Here is an example:
import { exportFunctions } from 'better-firebase-functions';
exportFunctions({
__filename, // standard node var (leave as is).
exports, // standard node var (leave as is).
functionDirectoryPath: './myFuncs', // define root functions folder
// relative to this file.
searchGlob: '**/*.js' // file search glob pattern.
});
The only other thing you need to do is export your function.http.onRequest()... as a default export from every file that contains a cloud function that you want to deploy. So:
export default functions.http.onRequest()...
/// OR
const func1 = functions.http.onRequest()...
export default func1;
And that's it!
UPDATE: Answer edited to reflect newer version of package.

Nodejs required variable undefined if script file not run directly?

I apologise for the phrasing of the question - it's a bit difficult to sum up as a question - please feel free to edit it if you can clarify. Also, as this quite a complex and long query - thank you to all those who are putting in the time to read through it!
I have 4 files (listed with directory tree from project root) as part of a project I'm building which aims to scrape blockchains and take advantage of multiple cores do get the job done:
./main.js
./scraper.js
./api/api.js
./api/litecoin_api.js
main.js
const { scraper } = require('./scraper.js')
const blockchainCli = process.env.BLOCKSCRAPECLI || 'litecoin-cli'
const client = (args) => {
// create child process which returns a promise which resolves after
// data has finished buffering from locally hosted node using cli
let child = spawn(`${blockchainCli} ${args.join(' ')}`, {
shell: true
})
// ... wrap command in a promise here, etc
}
const main = () => {
// count cores, spawn a worker per core using node cluster, add
// message handlers, then begin scraping blockchain with each core...
scraper(blockHeight)
}
main()
module.exports = {
client,
blockchainCli
}
scraper.js
const api = require('./api/api.js')
const scraper = async (blockHeight) => {
try {
let blockHash = await api.getBlockHashByHeight(blockHeight)
let block = await api.getBlock(blockHash)
// ... etc, scraper tested and working, writes to shared writeStream
}
module.exports = {
scraper
}
api.js
const { client, blockchainCli } = require('../main.js')
const litecoin = require('./litecoin_api')
let blockchain = undefined
if (blockchainCli === 'litecoin-cli' || blockchainCli === 'bitcoin-cli') {
blockchain = litecoin
}
// PROBLEM HERE: blockchainCli (and client) are both undefined if and
// only if running scraper from main.js (but not if running scraper
// from scraper.js)
const decodeRawTransaction = (txHash) => {
return client([blockchain.decodeRawTransaction, txHash])
}
const getBlock = (blockhash) => {
return client([blockchain.getBlock, blockhash])
}
const getBlockHashByHeight = (height) => {
return client([blockchain.getBlockHash, height])
}
const getInfo = () => {
return client([blockchain.getInfo])
}
const getRawTransaction = (txHash, verbose = true) => {
return client([blockchain.getRawTransaction, txHash, verbose])
}
module.exports = {
decodeRawTransaction,
getBlock,
getBlockHashByHeight,
getInfo,
getRawTransaction
}
So, I've taken out most the noise in the files which I don't think is necessary but it's open source so if you need more take a look here.
The problem is that, if I start the scraper from inside scraper.js by doing, say, something like this: scraper(1234567) it works like a charm and outputs the expected data to a csv file.
However if I start the scraper from inside the main.js file, I get this error:
Cannot read property 'getBlockHash' of undefined
at Object.getBlockHashByHeight (/home/grayedfox/github/blockscrape/api/api.js:19:29)
at scraper (/home/grayedfox/github/blockscrape/scraper.js:53:31)
at Worker.messageHandler (/home/grayedfox/github/blockscrape/main.js:81:5)
I don't know why, when launching the scraper from main.js, the blockchain is undefined. I thought it might be from the destructuring, but removing the curly braces from around the first line in the example main.js file doesn't change anything (same error).
Things are a bit messy at the moment (in the middle of developing this branch) - but the essential problem now is that it's not clear to me why the require would fail (cannot see variables inside main.js) if it's used in the following way:
main.js (execute scraper()) > scraper.js > api.js
But not fail (can see variables inside main.js) if it's run like this:
scraper.js (execute scraper()) > api.js
Thank you very much for your time!
You have a circular dependency between main and api, each requiring in the other. main requires api through scraper and api directly requires main. That causes things not to work.
You have to remove the circular dependency by putting common shared code into its own module that can be included by both, but doesn't include others that include it. It just needs better modularity.

Locomotive.js throws error upon calling "locomotive.boot"

I'm trying to write tests on my locomotive.js application, literally copy/pasting code from some examples on the internet. Even so, whenever I run my tests, I get an error saying
TypeError: string is not a function
When I check the number of arguments expected by locomotive.boot (using locomotive.boot.length), it says 2... But in every single example online (go ahead, google it) the documentation seems to say 3. Does anyone know what I'm doing wrong?
Here's my code:
var locomotive = require('locomotive'),
should = require('should'),
request = require('supertest');
var app, server;
describe('Application', function() {
before(function(done) {
locomotive.boot( __dirname+"/..", "test", function(err, express) {
if (err) throw err;
app = this;
express.listen(4000, '0.0.0.0', function() {
var addr = this.address();
console.log('Server started. [Env: '+SOPS.conf.get('app:environment')+'] [Addr: '+addr.address+'] [Port: '+addr.port+']');
done();
});
server = express;
});
});
it('should have started the app', function(){
should.exist(app);
should.exist(express);
});
});
There are 2 branches on the LocomotiveJS repo:
- 0.3.x (https://github.com/jaredhanson/locomotive/tree/0.3.x)
- master (https://github.com/jaredhanson/locomotive/tree/master)
If you're using version 0.3.x your code should work, the function declaration actually shows 4 arguments: dir, env, options, callback
you can have a look at the function definition here (Locomotive.prototype.boot): 0.3.x/lib/locomotive/index.js
As of version 0.4.x (branch master) the boot function only accepts 2 arguments: env, callback
the function definition for this branch is here (Application.prototype.boot): master/lib/application.js
so your code should look something like:
locomotive.boot( "test", *yourcallback* );
Hope this helps.

Resources