Remotely called JavaScript with local configuration
There are two major parts involved for any web service. There is the service program itself and there is the client, or pseudo-client, code. For a JavaScript featherweight web service you need some JavaScript on your host, the service, and you need an API for the client, a script in a user’s HTML, to pass information to the service and get a response.
Using a remotely called piece of JavaScript with local configuration usually requires two steps.
- The client writes a bit of JavaScript which defines the configuration variables; the request.
- Import the remote script, the services proper, with
<script src="http://remote-source/...js"
which will use the configuration information/variables from the first script to do something.
The service code is usually going to be on a different web server than
the client code but there’s no reason it has to be. You could even
design in-house only services which use Apache, or
another server, directives to deny
use of the service
to outside clients.
You probably saw this next bit coming.
Part 1, client’s local configuration/request
<script type="text/javascript"> <!-- to_whom = 'world'; //--> </script>
Part 2, call remote service/script
<script type="text/javascript" src="http://elektrum.org/js/hello.js"> </script>
This means, of course, that we have to have a remote script to call.
Part 2.5, the remote service/script itself
// fail gracefully, ie: do nothing if used incorrectly var to = window.to_whom; if ( to ) { // prevent cross-site scripting attacks to = unescape( to.toString() ); to = to.replace(/</g, '<'); to = to.replace(/>/g, '>'); // send our output along document.write( '<b><i>Hello ' + to + '!</i></b>'); }
That bit of code lives on the remote server in the web path
/js/hello.js
. The client will typically not see it,
though it’s not possible to hide it if they want to view the source.
Just know that most clients won’t care what it looks like, just what
they need to feed it and what its URI is.
The reason we get the to
out of the to_whom
attribute of the window
object instead of plain old
to_whom
, which does work, is that if to_whom
is never defined in the configuration script, we’ll get a run time
error. It’s also a good habit to scope all your variables with
var
even if you don’t (and can’t really) require it for
the client’s code.
Important!
Never, never, never echo user or client input back to the document without sanitizing or filtering it. Above we unescape the string and then replace out any tag markers with html entities. The order matters. There may be URI encoded HTML left if you save the unescape for last.
If you write user input to the screen without filtering it, it lets
someone inject <script>
tags into your script. This
is called cross-site
script attacking.
If you want to write services that others will use without earning yourself a reputation as a dangerous idiot, you must be careful about this.
An aside on try
and catch
While try
and catch
are valuable parts of
many languages they are too often used in place of good and thorough
coding. It is difficult to envision all misuse cases and everything
that can go wrong. It doesn’t mean it shouldn’t be the goal. If you
can account for it up front and you’re not doing on the fly code
building and eval
ing you may never need to use
try
.
Do, or do not. There is no try.–Yoda, Empire Strikes Back
We could wrap our variable use in a try
block instead of
getting it through the window
. We’d rather set it up so
it won’t ever break instead of setting it up expecting it to break.
All together now
<script type="text/javascript"> <!-- to_whom = 'world'; //--> </script> <script type="text/javascript" src="http://elektrum.org/js/hello.js"> </script>
The hotly anticipated output
A few words about why this works
It’s important to note why this works because it has programming
implications. JavaScript has no trouble trouble sharing variables
across the boundaries of different scripts, if they aren’t lexically
declared inside classes, or in blocks (functions, loops, etc) with
var
. This is because JavaScript lets you declare
variables globally; meaning they are visible, usable, and mutable from
every scrap of JavaScript present or later introduced by you or
others.
Even if we’d done something like this instead.
<script type="text/javascript"> <!-- var to_whom = 'world'; //--> </script>
It would still work. The var to_whom
declaration should,
in our opinion, make to_whom
invisible to other scripts,
including the script imported, but doesn’t because it’s at the global
level. Everything formally declared or created out in the open is at
the top of the pan-DOM context.
The implications of this include global pollution. You might, for
example, want your user to be able to use a simple variable name like
Size
, index
, Color
, or even
i
. It’s not reasonable with this technique. It’s
possible, it’s just unsafe. If you have other scripts in the page,
scripts calling scripts in the background, or a code blocks 10 levels
deep where you forgot the name was in use already, you’ll end up with
name collisions. Which will mean mysterious failures and bugs that can
be a migraine to track down and fix.
A wish unfilled
It would be wonderful if we could import the remote script and use it in one step alla:
<script type="text/javascript" src="http://elektrum.org/fakeService.js"> var newThing = fakeImportedFunction(); </script>
If you haven’t guessed, we’ll save you the trouble of trying. It
doesn’t work. If there is a src
then the text content of
the script is ignored.
Google’s Adsense implementation
Google uses the dual script technique Adsense. Here is the code for an ad we use on this site.
<script type="text/javascript"><!-- google_ad_client = "pub-3741595817388494"; google_ad_width = 234; google_ad_height = 60; google_ad_format = "234x60_as"; google_ad_channel ="9807480512"; google_color_border = "578A24"; google_color_bg = "CCFF99"; google_color_link = "00008B"; google_color_url = "00008B"; google_color_text = "000000"; //--></script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
Here is the result when it’s used in a page.
We don’t know, and don’t need to or particularly care, what the code
inside
http://pagead2.googlesyndication.com/pagead/show_ads.js
looks like or how it works, though it’s easy enough to take a peek.
We’re respecting the programming by contract of its API and not messing with the code Google gives us to use. Since we don’t mess with it, we’re not going to break the interface and really don’t need any knowledge of the application beneath.
Looking at the local configuration code you can see how Google is dealing with global namespace issues. They are
prefixing all variable names with google_
. This is a
pseudo-namespace solution that makes the global variable names
reasonably safe from namespace collisions. The chances of another
script using a google_color_text
are slim.
When you see other services delivered via JS, you will invariably, see them delivered this way. Set up script + remote script. And for a little foreshadowing: after this manual makes the rounds, the 1, 2 script combo won’t be the only way you see it done anymore.
Next up, our first service: Pangrams for typographers.