Another doGet() issue with Google Apps Script - "Unknown macro doGet" error - api

I'am obviously new to Google Apps Script, nevertheless I have some experience in coding in C, PHP and Java. Since we would like to create a small CRM in our company with Google Apps Script, we need to create an application with a form available on Google Sites. I've been searching an answer for this problem a long time, I haven't unfortunately found any answer. I have a code like this:
var klienci_id = new Array(100);
var klienci_nazwa = new Array(100);
var klienci_adres = new Array(100);
var klienci_osoba = new Array(100);
var klienci_telefon = new Array(100);
var klienci_email = new Array(100);
function doGet(e) {
var app = UiApp.createApplication();
// hello world label
var helloworldLabel = app.createLabel("I love Apps Script!").setStyleAttribute("fontSize","16px");
// add the label to the app container
app.add(helloworldLabel);
return app;
}
function main() {
var klienci = SpreadsheetApp.openById("0ArsOaWajjzv9dEdGTUZCWFc1NnFva05uWkxETVF6Q0E");
var kuchnia_polska = klienci.getSheetByName("Kuchnia polska");
var dane = kuchnia_polska.getRange("D7:F22");
doGet();
}
And everytime I try to publish it and enter the given link I get the error "Unknown macro doGet". I know this is a common problem when somebody doesn't use doGet() function but I do - and it still doesn't work. I also believe that Google should create a thorought documentation on Google Apps Script, which would work the way the Unix manual does, since I just cannot get through all these strange pages of goddamn help :) It's neither a Windows help, nor a good manual ;)
Regards,
Kamil

I have a suspicion that you made a "version" once, published the app, went to the "real" link and not the "development" link, and then added the doGet() function. When you make a version, it freezes the code at that time. The version that the app is published at is the version of the code that will run at the "real" link (what you give users), which allows you to keep editing the code without disturbing existing users of your app. There is a special "development" link given to you in the publish dialog that always refers to the most recent version of the code, but which will only work for you and no one else.

I'm affraid there is a little misunderstanding on your side concerning the use of the 'doGet()' function. When you want to run an application as a webapp, the doc says indeed that it must contain a doGet function but what it doesn't say explicitely is that this function is supposed to be the starting point of the whole app, ie the function that the url will call in the first place. So it doesn't make much sense to have the doGet function called from a so called "main" function since the "main" function is not the main function...
I cannot imagine right now a situation where some function calls the doGet function since every function in the script is called initially (directly or indirectly) from this doGet function.... in fact the 'end' of any other function in the script 'returns' to the doGet initial function. Well this is maybe not absolutely true in every case but it gives you the general idea about how it works.
I'm hoping this is clear enough and, to return to your code snippet, if you remove the doGet(e) call, it will ideed show a nice "I love Apps Script!" but it will never do anything else, certainly not see the "main" function.

I've copied your code here https://script.google.com/macros/d/MJ80AK8t7kbgDcC-NaLPYvH797_hv7HHb/edit?template=app&folder=0AKGkLMU9sHmLUk9PVA
and when deployed as a web app appears to work https://script.google.com/macros/s/AKfycbxOiaukLt7P4pIm7bms7aU16uEo6FuZ-MNOh0tSqUwr/dev
Only thing I can think of is there is something else in your code not copied into the snippet that is throwing the exception.
[Just before the GUI Builder was published I came up with Creating a framework for custom form interfaces using Google Apps Script which might help you with your project]

Thank you both for help. Serge, yes, it's really not obvious what the structure of Google Apps Scripts should be. They are based on JavaScript, however, due to lack of HTML in the code they have completely different flow - so naturally, there has to be a main function which is executed first. And of course in every programming environment it has to have a different name to make it more distinguishable ;-)
I created a new copy of my application, not changing the code completely - deployed it and it works beautifuly. Since I haven't changed anything in access options, it's quite strange that two applications with the same code and the same options don't give the same result. I think it may be a kind of the environment flaw, maybe someone from Google should look at this :)
Here's the link to the script, I've set access to "Anyone with the link".
https://script.google.com/a/macros/foodbroker.pl/s/AKfycbwk2IM-rIYLhQl6HOlbppwGOnw4Ik_kH7ixbaSNVxIE-QR7cq8/exec

Related

How to capture a return value of a javascript function inside vb.net?

I have created a function called test that returns a boolean in a separate js file and I could call this function inside and aspx.vb file in vb.net as such:
ScriptManager.RegisterStartupScript(Me, Page.GetType, "Script", "test();", True)
my question is how to capture this returned value and assign it to a variable in vb.net so I can use it in a vb conditional statement?
Actually you aren't calling the function. What RegisterStartupScript does is that it "tells" to the browser that it should run the test() function as soon as it's ready to do so.
With that been said, you cannot get a return value from the test() function because when it gets called your aspx vb code has already been executed. Take a look here for more information regarding the life cycle of an aspx page.
Usually it is not a good idea to write server side code (aspx) that depends on the result of client side code (js), however what you can do is to have the test() js function to do an ajax request in the aspx page and "go on" from there. Here is a small example. The thing is that this approach isn't suitable nor it's recommended for what, I suspect, you are trying to do. To present different web page parts to the user according to the output of the test() js function.
I cannot provide sample code for what I suggest because it will be a wrong use case. I am answering this just to emphasize that you actually can't do what are you asking and even if there is a way to do it you should definitely avoid it. However, this is a good opportunity to dive in more in the web applications design and implementation.
Perhaps an SPA can fit your needs?

TheTVDB API - Starting out

I'm looking for assistance for the bare minimum code to pull some information from the TheTVDB API (v3).
I've never coded anything to do with APIs before.
I tried to shortcut using TVDBSharper, but that uses asynchronous routines, and tasks, etc. which I just can't get my head around at the moment, given the documentation is for C#, and I clearly don't understand how "await" works in VB.
I've tried searching for API examples, but most are about creating an API.
The first thing TheTVDB API documentation says is:
"Users must POST to the /login route with their API key and credentials in the following format in order to obtain a JWT token."
^ I don't know how to POST. Any examples I've seen are very long and confusing, and mostly in C#.
So (and I apologise for this drivel, but I've tried on and off for months now)…
Could someone please show me the minimal amount of VB.NET code to pull the show name from, for example series ID 73739 (Lost). Hopefully from there, I can start to figure some things out.
I have a valid API Key from the TheTVDB.
Mostly you don't need to understand async/await in any great detail but I was once where you are now, and though I don't claim to be an expert, I did manage to get my head around it like this:
You know how, if you had something that threw an exception and you never caught it:
Sub Main(arguments)
Whatever()
End Sub
Sub Whatever
StuffBefore()
OtherWhateverThrowsException()
StuffAfter()
End Sub
Sub OtherWhateverThrowsException()
StuffBefore()
throw New Exception("Blah")
End Sub
As soon as you threw that exception, your VB thread would stop what it was doing, and wind its way back up through the call stack until it popped out of the main, and crashed to the command line - a matrixy style "return to the source" if you like
Async Await is a bit like that. When there's some method that is going to take a long time to do its work (download strings from tvdb) we could make it sit around doing nothing in our code, having a up of coffee and waiting for TVDB's slow server. This makes things easy to understand because if we sit and wait, we wait 30 seconds, then we get the response, and process the response. Obviously we can't process the response before we get it so we have to sit around and wait for it, and this is always true..
But it'd be better if we could let our thread nip back out the way it came in, "go back to the source", do something else for someone else, and then call it(or another one of its coworkers, we probably don't care) back to carry on working for us when TVDB's server responds. This is what Async Await does for us. Methods that are marked Async are treated differently by the compiler, something like saving your progress on your xbox game. If you reach a point where you want to wait, you can issue the waiting command, the thread that was doing our work performs a savegame, goes off and works for someone else, then when we're ready it comes back, loads the game again and carries on where it left off.
The save game file is manifest as a Task; methods that once upon a time were subs (didn't return anything) should now be Functions that return a Task (a savegame with no associated data). Methods that once upon a time returned something like a string, should now be marked as returning a Task(Of String) - the Task part is to save the state of play (data that VB wants to work with), the string is the data your app wants to work with.
Once you mark something as Async, it needs to contain an Await statement. Await is that SaveYourGameAndGoDoSomethingElseWhileThisFinishes. Typically, while you're awaiting something your program won't have any other stuff it needs the thread to do, so it's not just your Function that calls TVDB's API that needs to Await/be marked Async - every single function in the chain, all the way up and out of your code, needs to be marked as Async, and typically you'll Await at every step of the way back up:
Sub DownloadTVDBButton_Click(arguments)
DoStuff()
End Sub
Sub DoStuff
StuffBefore()
GetFromTVDB()
StuffAfter()
End Sub
Sub GetFromTVDB()
Dim i = 1
GetDataFromTVDBServer() 'wait 30s for TVDB
ParseDataFromTVDB()
End Sub
Sub ParseDataFromTVDB()
End Sub
Becomes:
Async Sub DownloadTVDBButton_Click(arguments) 'windows forms event handlers are always subs. Do not use async subs in your own code
Await DoStuff()
End Sub
Function DoStuffAsync Returns Task
StuffBefore()
Await GetFromTVDBAsync()
StuffAfter()
End Function
Async GetFromTVDBAsync() Returns Task
Dim i = 1
Await GetDataFromTVDBServerAsync() 'go back up, and do something else for 30s
ParseDataFromTVDB()
End Sub
Sub ParseDataFromTVDB() 'downstream; doesn't need to be async/await
End Sub
We switched to using TVB's Async data call, so we await it. When we await, the thread would go back up to the previous function DoStuffAsync. Because we're awaiting that, the thread goes back up a level again into the button click handler. Because we're awaiting that also, the thread goes back up again and out of your code. It goes back to its regular day job of drawing the UI, making it looks like the program is still responding etc. When the TVDB call completes the thread comes back to the point just after it (ready to run ParseData), and it has all the data back from TVDB, and the savegame has been reloaded so everything it knew before/the state is as it was (variable i exists and is 1; you could conceive that it would have been lost otherwise when the thread went off to do something else)
In essence, async/await has allowed us to work exactly as we would have done without it, it's just that it built a little savegame mechanism that meant our thread could go off an do something else while TVDB was busy getting our data, rather than having to sit aorund doing nothing while we waited
It may also help to think of Await as a device that unpacks a save game and gets your data out of it. If a GetSomething() sits for 30s then returns a String you want, then GetSomethingAsync() will instantly return a Task that will (in 30s when the work is done) encloses that same String you want, and Await GetSomethingAsync() will wait until the Task is done then get the string you want out of it
Methods that are named like "...Async" should be thought of as "behave in an asyncronous way". They DON'T have to be marked with the Async modifier; Async is only needed if a method uses the Await word but I'm recommending you use Await on everything that returns a Task (i.e. is awaitable) all the way up and down your call tree. When you get more confident you don't always have to Await SomethingAsync but honestly the overhead of doing so is minimal and the consequences of not doing so are occasionally disastrous. All developers who follow convention always name their stuff ...Async if it behaves in an async way; you should adopt this too, and make sure you name all your Async methods with an"Async" at the end of the name
I don't know how to POST
You don't really need to. The TVDB API has a swagger endpoint; swagger is a way of describing a REST service programmatically so that your visual studio can build a set of classes to use it and provide you with nicely named things. Whipping out a WebClient and manually creating some JSON is very old school/low level
TVDB's swagger descriptor is at https://api.thetvdb.com/swagger.json
You're supposed to be able to right click your project, choose Add... Rest API Client:
,
Paste https://api.thetvdb.com/swagger.json in as the url and pick a namespace (an organizational unit) for all the generated classes to go in.
At the moment something in TVDB's API is causing AutoRest (the tool that VS uses to parse the API spec) to choke but ordinarily it would work out and you'd get a bunch of code (autorest generates c#; you'd be best off generating the c# into a new project and then adding reference to that project from your VB) objects to work with that would do all the POSTing etc for you.
As noted, my VS can't process the TVDB API at the moment and I dont have enough time today to figure out why, but you could sure post a question on AutoRest's github (or on SO) saying "why does https://api.thetvdb.com/swagger.json cause a "Input string not in correct format"" and get some more help
You asked (maybe implicitly) a couple of follow up questions in the comments:
I don't know about REST/swagger (I've heard of it though), and can't see any way to add to the project as you described, and I'm no closer to getting info from TheTVDB. However, it might have have helped me use functions in TVDBSharper. I will just have to try a few things with it. Thanks again
Yes; sorry - I should have been more explicit that "Add REST API client" is only available in a C# project because it relies on a tool that generates C#. This isnt a blocker though - you can just make a C# project and add it to your VB solution alongside your VB project; the two languages are totally interoperable. Your VB can tell your C# what to do
However, there isn't much point in trying at the moment, because the tool that is suppsoed to do it can't handle what TVDB is putting out; my VS can successfully ask the TVDB API to describe itself, but it doesn't seem able to understand the response.
In a nutshell; VS has a bug that means it can't use TVDB API directly, you're best off trying via TvDbSharper. The https://github.com/HristoKolev/TvDbSharper readme has some examples in. They're C# but basically "remove the semicolons and they'll pretty much work in VB"
Now, a bit about the headline terms here, background understanding if you like. API, RESTand swagger are easy enough to explain:
API
An API is effectively a website (in this case run by TVDB), intended for software to consume rather than humans. It takes raw data in and chucks raw data out - unlike a normal website intended for our eyes, nothing about it is presentational in the slightest.
REST
REST as a phrase and a concept is a source of confusion for many and a lot of times you try and read about what REST means and the blogs quickly start getting bogged down with details and make it too complex, with all these funky examples. They kinda forget to explain the REST part because it's come to mean not much at all - it's something so obvious and nondescript that we don't think about it any more.
In essence, something is RESTful if the server doesn't have to remember something about what you did before, in order to service a request you make now - every request stands on its own and can be serviced completely without reference to something else. This is a different workflow to other forms where you might want to change the name of something by issuing a editname('newname') command. What name actually gets edited depends on whether you first did selectshow() or selectactor() and also which show or which actor - a workflow like that means the server has to start remembering whether you selected a show or actor, and what show/actor was selected before it can process the editname() command. If you selected show 123, the edit would edit the name of the show id 123. If you selected an actor 456, the edit name would edit the name of an actor 456
Critically, if you replayed the same editname() at a different time a different thing would get edited because the state of your dialog with the server changes. It's kinda dumb to make the server have to remember all that, for everyone, when really we could push the job of identifying whether we want to name an actor or a show and which show, onto the client
By making it that you have editactorname(123,'Jon wayne') you're transferring all the info the server needs to perform the request; your credentials, the actor id, the new name, the fact that it's an actor name and not a show name. All this goes in the one request, and you can replay this request as many times as you like at any time, and it always has the same effect; things that happened before don't affect it (well.. apart from authentication)
It gets a bit woolly if taken literally - "well if the server doesn't remember anything how does it even remember I changed the name of actor 123, to Jon Wayne so it can service my later request of getactorname(123)?" but that's more about the state of the data in the server, not the state of your interaction with the server. Things that are truly stateless are mostly purely calculatory and not too useful; something somewhere needs to be able to remember something or there is nothing to calculate. Things are rarely completely stateless; even TVDB's API requires you to authenticate first, using a user/password/apikey and then the serverissues a token that becomes your username/password/apikey equivalent for every subsequent request - the server has to start remembering that token, or every time you quote it it will say "can't edit actor name; not authorized". So, yeah.. when viewed holistically something usually has to be rememberd at some point otherwise nothing works. REST things are rarely 100% truly stateless, but mostly they are - and it's really about that "when you want to edit the actor name, send a) that you want to edit actorname, b) what actor, c) what name, d) your credentials to prove youre allowed to" - everything the server needs in the one hit
Swagger
Now called OpenAPI, swagger is a protocol for describing an API: when an api has some actions that take some data, and return some data, it's helpful to know what the actions are called (setactoryearsactive), what type of data they take (date, date), what sort of things you should put in it (the from date, the to date or null if still active), what they return (boolean) and what the return means (true if success, false if not).
If we have a standardized way of describing these things then we can build standard software that reads the standard description of the API and writes a bunch of standard code that uses the API. This is software that writes a description so other software can read it and write software that uses the first set of software. It's an API API.
There is a lot of software here:
The API is software(tvdb),
The thing that generates the description of the API is software (Swagger),
The thing that consumes the description of the API and creates a client is software(AutoRest),
And the thing that uses the client is software (your app).
You could code your app to hit the api directly- the API's just responding
to HTTP requests, which are just text files formatted in a particular way sent to port 80 of the web server that hosts the API. You could write one such request in notepad and use telnet to send it and get a valid response. You could code your app to do it (you were just about to). You could use someone else's library (TvBbSharper) which does it somehow. You could use some software that generates something like TvDbSharper; it reads the description of the api and generates classes for you to use; those classes will make the http requests. Everything can be done at any level; you could write all your apps in assembler, the lowest of the low. It takes ages and it is boring - this is why we use ever higher levels of abstraction.
We make something and then make it do a thousand things and then realize that listing the same code over and over and changing one bit each time is boring, and repetitive and something a computer should do, so we devise ways of making it so software can write the boring repetitive code so that we can do the interesting things.
Swagger and AutoRest are those kind of things; Swagger inspects all the methods, what they take and return and generates a regular consistent description. AutoRest reads it and generates a regular consistent set of client classes. Then the human uses the client classes to do the interesting things. The AutoRest part doesn't work out for us at the moment; it's written by different people than the Swagger team so some differences arise; Awagger describes something and Autorest can't understand it. It will one day I'm sure (in this game of walls and ladders); such is the nature of open source - everyone has a different set of priorities.
Right now we could probably get AutoRest working by finding the one thing it is choking on and removing it. There may be no need; if the TvDbSharper guys have written enough of a set of client classes that you can use TvDbSharper to do all your necessary things. It is thus effectively already the set of client classes AutoRest would have built, maybe more; use TvDbSharper.
The idea behind Swagger and Autorest is that a TvDbSharper shouldn't need to exist: it's a very specific application, only works with tvdb, only works in .net.
If we put effort into making Swagger able to generate a description of any API written in any language, and we put effort into making Autorest able to consume that description and output any language, then we have something more useful than TvDbSharper/no need to TvDbSharper because we can generate something that does the same (of course, specific applications can be superior, just like bespoke tailored suits are superior bt that's another philosophy for another time)

How would you redirect calls to the top object in Cypress?

In my application code, there are a lot of calls (like 100+) to the "top object" referring to window.top such as top.$("title") and so forth. Now, I've run into the problem using Cypress to perform end-to-end testing. When trying to log into the application, there are some calls to top.$(...) but the DevTools shows a Uncaught TypeError: top.$ is not a function. This resulted in my team and I discovering that the "top" our application is trying to reach is the Cypress environment itself.
The things I've tried before coming here are:
1) Trying to stub the window.top with the window object referencing our app. This resulted in us being told window.top is a read-only object.
2) Researching if Cypress has some kind of configuration that would smartly redirect calls to top in our code to be the top-most environment within our app. We figured we probably weren't the only ones coming across this issue.
If there were articles, I couldn't find any, so I came to ask if there was a way to do that, or if anyone would know of an alternate solution?
Another solution we considered: Looking into naming window objects so we can reference them by name instead of "window" or "top". If there isn't a way to do what I'm trying to do through Cypress, I think we're willing to do this as a last resort, but hopefully, we don't have to change that, since we're not sure how much of the app it will break upfront.
#Mikkel Not really sure what code I can provide to be useful, but here's the code that causes Cypress to throw the uncaught exception
if (sample_condition) {
top.$('title').text(...).find('content') // Our iframe
} else {
top.$('title').text(page_title)
}
And there are more instances in our code where we access the top object, but they are generally similar. We found out the root cause of the issue is that within Cypress calls to "top" actually interface with Cypress instead of their intended environment which is our app.
This may not be a direct answer to your question, it's just expanding on your request for more information about the technique that I used to pass info from one script to another. I tried to do it within the same script without success - basically because the async nature of .then() stopped it from working.
This snippet is where I read a couple of id's from sessionStorage, and save them to a json file.
//
// At this point the cart is set up, and in sessionStorage
// So we save the details to a fixtures file, which is read
// by another test script (e2e-purchase.js)
//
cy.window().then(window => {
const contents = {
memberId: window.sessionStorage.getItem('memberId'),
cartId: window.sessionStorage.getItem('mycart')
}
cy.writeFile(`tests/cypress/fixtures/cart.json`, contents)
})
In another script, it loads the file as a fixture (fixtures/cart.json) to pull in a couple of id's
cy.fixture(`cart`).then(cart => {
cy.visit(`/${cart.memberId}/${cart.cartId}`)
})

Data sharing mechanism

I need to develop a web application, where our data/html need to be displayed on third party sites using iframe or javascript. Example: cricket widget sharing.
Can someone tell me what type development is it called ?
There would be multiple kind of widget, some of them will also need to be upgrded short periodically (per x second).
Also, should i use iframe or use javascript implemenration merhod to generate the output on clients server.
Can someone provide me a reference or idea ?
Considering I have understood your question rightly, which means you currently need to develop a widget(not a web app) for websites. A widget is something that can be used by others on their websites.
Adding to the above understanding with the example you gave-
Say you develop a Cricket widget, 100's of other websites can put this widget on their site using a small piece of API or code. And, this widget refreshes every 'x' seconds to display Live Score. Hope this is what you need.
Here is the solution/way to solve this:
What you have to do is write an embedder or loader script keeping the following points in mind-
Make it asynchronous, so that the client website doesn't slow down
Keep it short. Abstract your code. Don't give the user 100's of lines.
Preferably don't use a framework. Chances are it can conflict with your client's website/frameworks. Don't even use jQuery!(Because it can conflict with user's jquery version and cause lot of problems to the widget and website) Write pure Javascript code :)
Don't ever use GLOBAL variables. Use var or let and follow best practices. Using global variables may conflict with user's variables and the whole website/client can get messed up.
A sample code -
<script data-version='v1' data-widget-id='your-clients-id' id='unique-embedder-id' type='text/javascript'>
// "data-version": It's useful to put the version of your embedder script in the "version" data attribute.
// This will enable you to more easily debug if any issues arise.
// "data-widget-id": This ID allows us to pull up the correct widget settings from our database.
// It's a "client id" of sorts.
// "id": This HTML id allows us to refer to this embedder script's location. This is helpful if you want to inject html
// code in specific places in hour hosts's website. We use it to insert our payload script into the <head> tag.
//We wrap our code in an anonymous function to prevent any ofour variables from leaking out into the host's site.
(function() {
function async_load(){
//BELOW: we begin to construct the payload script that we will shortly inject into our client's DOM.
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
// Below is the URL you want them to get your payload script from!
var theUrl = 'http://www.your-website.com/assets/your-payload-script.js';
// At the end we tack on the referrer's URL so we know which website is asking for our payload script.
s.src = theUrl + ( theUrl.indexOf("?") >= 0 ? "&" : "?") + 'ref=' + encodeURIComponent(window.location.href);
// This finds the location of our embedder script by finding the element by it's Id.
// See why it was useful to give it a unique id?
var embedder = document.getElementById('unique-embedder-id');
// This inserts our payload script into the DOM of the client's website, just before our embedder script.
embedder.parentNode.insertBefore(s, embedder);
}
// We want the our embedder to do its thing (run async_load and inject our payload script)
// only after our client's website is fully loaded (see above).
// Hence, we wait for onload event trigger. This no longer blocks the client's website from loading!
// We attachEvent (or addEventListener to be cross-browser friendly) because we don't want to replace our
// client's current onLoad function with ours (they might be doing a bunch of things on onLoad as well!)
if (window.attachEvent)
window.attachEvent('onload', async_load);
else
window.addEventListener('load', async_load, false);
})();
</script>
Read the comments. They are very helpful :)
Your users will have to just use a nicely abstracted script tag-
<script type="text/javascript" src="http://example.com/widget.js"></script>
Or maybe even an iFrame(old is gold days) render HTML in iFrame(Best way if you don't want to 'openly' expose(as most won't know) your Abstracted Javascript as well)
<iframe src="http://example.com/mywidget.html"></iframe>
Here are the references that I referred and also have sample widgets which can be reused-
Developing an Embeddable Javascript Widget / Snippet for Client Sites
Creating an Embeddable JavaScript Widget
Creating Asynchronous, Embeddable JavaScript Widgets
Building an embeddable Javascript widget (third-party javascript)
One last time, please don't use global variables and write asynchronous code. These 2 are the main things that you have to take care to make a great/successful widget with top-notch performance.
Happy Coding! Hope it helps :)

Porting PHP API over to Parse

I am a PHP dev looking to port my API over to the Parse platform.
Am I right in thinking that you only need cloud code for complex operations? For example, consider the following methods:
// Simple function to fetch a user by id
function getUser($userid) {
return (SELECT * FROM users WHERE userid=$userid LIMIT 1)
}
// another simple function, fetches all of a user's allergies (by their user id)
function getAllergies($userid) {
return (SELECT * FROM allergies WHERE userid=$userid)
}
// Creates a script (story?) about the user using their user id
// Uses their name and allergies to create the story
function getScript($userid) {
$user = getUser($userid)
$allergies = getAllergies($userid).
return "My name is {$user->getName()}. I am allergic to {$allergies}"
}
Would I need to implement getUser()/getAllergies() endpoints in Cloud Code? Or can I simply use Parse.Query("User")... thus leaving me with only the getScript() endpoint to implement in cloud code?
Cloud code is for computation heavy operations that should not be performed on the client, i.e. handling a large dataset.
It is also for performing beforeSave/afterSave and similar hooks.
In your example, providing you have set up a reasonable data model, none of the operations require cloud code.
Your approach sounds reasonable. I tend to put simply queries that will most likely not change on the client side, but it all depends on your scenario. When developing mobile apps I tend to put a lot of code in cloud code. I've found that it speeds up my development cycle. For example, if someone finds a bug and it's in cloud code, make the fix, run parse deploy, done! The change is available to all mobile environments instantly!!! If that same code is in my mobile app, it really sucks, cause now I have to fix the bug, rebuild, push it to the app store/google play, wait x number of days for it to be approved, have the users download it... you see where I'm going here.
Take for example your
SELECT * FROM allergies WHERE userid=$userid query.
Even though this is a simple query, what if you want to sort it? maybe add some additional filtering?
These are the kinds of things I think of when deciding where to put the code. Hope this helps!
As a side note, I have also found cloud code very handy when needing to add extra security to my apps.