Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/coderofsalvation/gexpress
Express middleware for google appscript (build NODEJS-like applications) + generated api-client
https://github.com/coderofsalvation/gexpress
appscript express express-middleware google google-apps-script javascript
Last synced: 8 days ago
JSON representation
Express middleware for google appscript (build NODEJS-like applications) + generated api-client
- Host: GitHub
- URL: https://github.com/coderofsalvation/gexpress
- Owner: coderofsalvation
- Created: 2018-06-20T09:04:24.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2020-05-29T17:23:17.000Z (over 4 years ago)
- Last Synced: 2024-07-05T07:36:25.901Z (4 months ago)
- Topics: appscript, express, express-middleware, google, google-apps-script, javascript
- Homepage:
- Size: 1.84 MB
- Stars: 70
- Watchers: 4
- Forks: 9
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
Awesome Lists containing this project
README
## Usage
Surf to [script.google.com](https://script.google.com), create a script, and copy/paste this into Code.gs:
```js
var app = new Gexpress.App()
var cache = CacheService.getScriptCache()cache.put("/hello", JSON.stringify({date: new Date()}) )
app.use(function(req,res,next){
req.user = {email:Session.getActiveUser().getEmail()}
next()
})app.get('/hello',function(req,res,next){
res.set('content-type','application/json')
res.send( cache.get('/hello') )
res.end()
},true)app.get('/client.js', app.client() )
app.get(/.*/, function(req,res,next){
res.set('content-type','text/html')
res.send("Hello
") // see docs for template-usage & banner-removal
res.end()
})// this hooks Gexpress into appscript
function doGet(e) { return app.doGet(e) }
function doPost(e){ return app.doPost(e) }
```
> .put() .post() .delete() and .options() are also supported (see virtual endpoints)This creates these urls:
* anonymous: [?path=/hello](https://script.google.com/macros/s/AKfycbziqV-T6HudofXLfmMoQS4_AL68f_x6CUlJYIzs2Q-SYaHoWBgq/exec?path=/hello)
* anonymous: [?path=/client.js](https://script.google.com/macros/s/AKfycbziqV-T6HudofXLfmMoQS4_AL68f_x6CUlJYIzs2Q-SYaHoWBgq/exec?path=/client.js)
* authenticated: [/hello](https://script.google.com/macros/s/AKfycbziqV-T6HudofXLfmMoQS4_AL68f_x6CUlJYIzs2Q-SYaHoWBgq/exec/hello)
* authenticated: [/client.js](https://script.google.com/macros/s/AKfycbziqV-T6HudofXLfmMoQS4_AL68f_x6CUlJYIzs2Q-SYaHoWBgq/exec/client.js)> click the urls to see live demo output
## Include the library
Add `1Lm_jNmD2FWYF-Kgj7AdHVvLEVXZ4c5AXwzd1KJSb48scn0HLBq64um7S` to your libraries (Resources > Libraries).
> NOTE: please make sure you select the latest version of the library
## Debugging
Use [BetterLog](https://github.com/peterherrmann/BetterLog) to easily log into a spreadsheet (because Logger.log does not always work inside `doGet()` and `doPost()`)
Logger = BetterLog.useSpreadsheet('1gUQI4SUyQbIoNYwUHORgl') // spreadsheet id
Logger.log("hello world")## Permissions and users
Make sure you deploy with these settings:
You can add google users to the appscript (share-button), **re-deploy**, and you're done.
Rules of thumb:* use the rooturl (`/exec`) for anonymous access
* use other urls (`/exec/myadmin` e.g.) urls for authenticated accessThe latter will automatically trigger login for anonymous users.
See an overview of (non)authenticated urls below.## RESTFUL-ish
Webtraffic to Google Appscript Webapps is limited/secured in many ways.
This is not that bad, given that every appscript gives us:* free security + free https! =)
#### Virtual CORS anonymous endpoints
By default, Gexpress exposes endpoints in a slightly different way (compared to express):
| Gexpress method | Listens to webrequest(s) | Anonymous webrequest | CORS | application/json | application/javascript | text/xml | text/plain | text/html
|-|-|-|-|-|-|-|-|-|
| app.get('/foo',..) | GET /exec?path=/foo | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ⚠ |
| | POST /exec?path=/foo&method=GET | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ⚠ |
| app.post('/foo',..) | POST /exec?path=/foo&method=POSTt | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ⚠ |
| app.put('/foo',..) | POST /exec?path=/foo&method=PUT | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ⚠ |
| app.delete('/foo',..) | POST /exec?path=/foo&method=DELETE | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ⚠ |
| app.options('/foo',..) | POST /exec?path=/foo&method=OPTIONS | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ⚠ |> ⚠ = will trigger `this application was created by another user`-banner if not logged in as appscript-owner. See chapter 'Banner 101'
If you really want 100% restful endpoints, see the following section.
#### Authenticated endpoints
If you only want authenticated (gsuite) users to access your webapp (see settings in Publish > Deploy as webapp), then these are the exposed endpoints:
| Gexpress method | Listens to webrequest(s) | Anonymous webrequest | CORS | application/json | application/javascript | text/xml | text/plain | text/html
|-|-|-|-|-|-|-|-|-|
| app.get(/.*/,..) | GET /exec | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ⚠ |
| app.get('/foo',..) | GET /exec/foo | triggers auth | | ✓ | ✓ | ✓ | ✓ | ⚠ |
| app.post('/foo',..) | POST /exec/foo | triggers auth | | ✓ | ✓ | ✓ | ✓ | ⚠ |
| app.put('/foo',..) | POST /exec/foo&method=PUT | triggers auth | | ✓ | ✓ | ✓ | ✓ | ⚠ |
| app.delete('/foo',..) | POST /exec/foo&method=DELETE | triggers auth | | ✓ | ✓ | ✓ | ✓ | ⚠ |
| app.options('/foo',..) | POST /exec/foo&method=OPTIONS | triggers auth | | ✓ | ✓ | ✓ | ✓ | ⚠ |> NOTE: disable the virtual endpoints by initializing Gexpress with `new Gexpress.App({pathToQuery:false})`
## Accessing data from requests
| example | retrieval |
|-|-|
| GET /exec?path=/foo/12 | req.query.path, req.params.id |
| GET /exec?path=/foo&bar=1 | req.query.path, req.query.bar |
| POST /exec?path=/foo&bar=1 {...} | req.query.path, req.query.bar, req.body |
| PUT /exec?path=/foo&method=PUT&bar=1 {...} | req.query.path, req.query.bar, req.body |
| DELETE /exec?path=/foo&method=DELETE&bar=1 {...} | req.query.path, req.query.bar, req.body |> use this middleware to log requests (View > Logs)
app.use(function(req,res,next){
Logger.log( req.method+" "+req.url+" "+(req.route ? "("+req.route+")":"")+" "+JSON.stringify(req.params) )
next()
})## Regex / Serving files / templating
Appscript has builtin support for templating, here's a simple example.
Serve this `index.html`-file:```html
= title ?>
!= foo() ?>
```
With this endpoint:
```js
function foo(id){
return "Hello world "+id
}app.get( /.*/, function(req,res,next){ // default to homepage
Logger.log("defaulting to homepage")
var html = HtmlService.createTemplateFromFile('index') // this will get the index.html-file from your appscript project
html.title = 'Hello'
res.set('content-type','text/html')
res.send( html.evaluate().setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL).getContent() )
res.end()
})```
## Retrieving url arguments
| route | url request | req.url value | req.route value | retrieve data | note |
|-|-|-|-|-|-|
| app.get('/foo') | GET /foo?bar=1 | /foo | /foo | req.query.bar | |
| app.get('/foo') | GET /foo/123 | /foo | /foo/:id | req.params.id | :id is automatically detected |
| app.get('/foo/:foo') | GET /foo/123 | /foo | /foo/:foo | req.params.foo | |## Generate Browser JS client
Gexpress can automatically generate a client (see `app.client()` above), which you can decorate further:
```js
app.put('/foo', function(req,res,next){ .... }, true) // note: true includes endpoint into client.jsapp.get('/client.js', app.client( function(code){
return ' ' + code + ' '
})
```> Now insert `` in your html`
The generated client will allow you to do this:
```js
gclient.get('/foo'}).then( alert ).catch( alert)
gclient.get('/foo/123'}).then( alert ).catch( alert)
gclient.post('/foo',{bar:1}).then( alert ).catch( alert)
gclient.put('/foo/123',{bar:2}).then( alert ).catch( alert)
gclient.delete('/foo/123').then( alert ).catch( alert)
```Just look at the client-source and you'll see some examples.
> NOTE: Always make sure you create a new deployment before testing changes. Development-urls (ending with `/dev`) do not allow POST requests (`post(),put(),delete()` in our case). This is an appscript limitation.
Hence the client will always use the `/exec`-url production url.## Generate Node.js client
Install node-tech, and download the client.js-contents of above locally (the script-tag src-url), and save it into file `client.js`.
$ npm install node-fetch --save
$ curl -L 'https://script.google.com/{SCRIPTID}/exec?path=/client.js' > client.jsThen create a file called mynodescript.js:
```js
var gclient = require('./client.js')(require('node-fetch'))
gclient.get('/foo')
.then( console.dir )
.catch( console.dir )/* outputs:
*
* { limit: '3',
* offset: '0',
* order: 'date_modify DESC',
* nitems: 3,
* items:
* [ { '#': '1',
* name_first: '...',
* name_last: '...',
* },
* { '#': '45',
* ....
*/
```> Voila!
## Middleware
| middleware | info |
|-|-|
| [Gexpress-middleware-RESTsheet](https://github.com/coderofsalvation/Gexpress-middleware-RESTsheet) | exposes spreadsheet as REST endpoints |## Banner 101
In order to get rid of the (not made by google) banner, you can do 2 things:
* create a google site and include the script
* include the script as an iframe on another domain (host on gitlab/github/bitbucket page e.g.)