Skip to content

Commit 1e136f8

Browse files
authored
Merge pull request #124 from nullstack/worker-verbs
Worker verbs
2 parents cd2b4f7 + 50ad575 commit 1e136f8

File tree

7 files changed

+166
-22
lines changed

7 files changed

+166
-22
lines changed

client/invoke.js

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,54 @@
11
import deserialize from '../shared/deserialize';
2-
import worker from './worker';
32
import prefix from '../shared/prefix';
43
import page from './page';
4+
import worker from './worker';
55

66
export default function invoke(name, hash) {
77
return async function _invoke(params = {}) {
88
let payload;
99
worker.fetching = true;
10-
if(Object.isFrozen(worker.queues[name])) {
10+
if (Object.isFrozen(worker.queues[name])) {
1111
worker.queues[name] = [params];
1212
} else {
1313
worker.queues[name] = [...worker.queues[name], params];
1414
}
1515
const finalHash = hash === this.constructor.hash ? hash : `${hash}-${this.constructor.hash}`;
1616
let url = `${worker.api}/${prefix}/${finalHash}/${name}.json`;
17+
let body = JSON.stringify(params || {});
18+
19+
const options = {
20+
headers: worker.headers,
21+
mode: 'cors',
22+
cache: 'no-cache',
23+
credentials: 'same-origin',
24+
redirect: 'follow',
25+
referrerPolicy: 'no-referrer',
26+
}
27+
if (/get[A-Z]([*]*)/.test(name)) {
28+
options.method = 'GET';
29+
url += `?payload=${body}`;
30+
} else {
31+
options.body = body;
32+
if (/patch[A-Z]([*]*)/.test(name)) {
33+
options.method = 'PATCH';
34+
} else if (/put[A-Z]([*]*)/.test(name)) {
35+
options.method = 'PUT';
36+
} else if (/delete[A-Z]([*]*)/.test(name)) {
37+
options.method = 'DELETE';
38+
} else {
39+
options.method = 'POST';
40+
}
41+
}
1742
try {
18-
const response = await fetch(url, {
19-
method: 'POST',
20-
headers: worker.headers,
21-
mode: 'cors',
22-
cache: 'no-cache',
23-
credentials: 'same-origin',
24-
redirect: 'follow',
25-
referrerPolicy: 'no-referrer',
26-
body: JSON.stringify(params || {})
27-
});
43+
const response = await fetch(url, options);
2844
page.status = response.status;
2945
const text = await response.text();
3046
payload = deserialize(text).result;
3147
worker.responsive = true;
32-
} catch(e) {
48+
} catch (e) {
3349
worker.responsive = false;
3450
}
35-
if(worker.queues[name]?.length === 1) {
51+
if (worker.queues[name]?.length === 1) {
3652
delete worker.queues[name];
3753
} else {
3854
worker.queues[name] = worker.queues[name].filter((task) => task !== params);

server/server.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,9 @@ server.start = function () {
162162
response.send(generateRobots());
163163
});
164164

165-
app.post(`/${prefix}/:hash/:methodName.json`, async (request, response) => {
166-
const args = deserialize(request.body);
165+
app.all(`/${prefix}/:hash/:methodName.json`, async (request, response) => {
166+
const payload = request.method === 'GET' ? request.query.payload : request.body;
167+
const args = deserialize(payload);
167168
const { hash, methodName } = request.params;
168169
const [invokerHash, boundHash] = hash.split('-');
169170
const key = `${invokerHash}.${methodName}`;

tests/src/Application.njs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import TwoWayBindings from './TwoWayBindings';
3535
import UnderscoredAttributes from './UnderscoredAttributes';
3636
import Vunerability from './Vunerability';
3737
import WindowDependency from './WindowDependency';
38+
import WorkerVerbs from './WorkerVerbs';
3839

3940
class Application extends Nullstack {
4041

@@ -89,6 +90,7 @@ class Application extends Nullstack {
8990
<PersistentComponent route="/persistent-component/:id" persistent />
9091
<UnderscoredAttributes route="/underscored-attributes" />
9192
<IsomorphicStartup route="/isomorphic-startup" />
93+
<WorkerVerbs route="/worker-verbs" />
9294
<ErrorPage route="*" />
9395
</main>
9496
)

tests/src/WorkerVerbs.njs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import Nullstack from 'nullstack';
2+
3+
class WorkerVerbs extends Nullstack {
4+
5+
static async getter({ request }) {
6+
return request.method;
7+
}
8+
9+
static async getSomething({ request }) {
10+
return request.method;
11+
}
12+
13+
static async putSomething({ request }) {
14+
return request.method;
15+
}
16+
17+
static async patchSomething({ request }) {
18+
return request.method;
19+
}
20+
21+
static async deleteSomething({ request }) {
22+
return request.method;
23+
}
24+
25+
static async postSomething({ request }) {
26+
return request.method;
27+
}
28+
29+
static async regularSomething({ request }) {
30+
return request.method;
31+
}
32+
33+
async hydrate() {
34+
this.getter = await this.getter()
35+
this.get = await this.getSomething()
36+
this.put = await this.putSomething()
37+
this.patch = await this.patchSomething()
38+
this.delete = await this.deleteSomething()
39+
this.post = await this.postSomething()
40+
this.regular = await this.regularSomething()
41+
}
42+
43+
render() {
44+
return (
45+
<div
46+
data-getter={this.getter}
47+
data-get={this.get}
48+
data-put={this.put}
49+
data-patch={this.patch}
50+
data-delete={this.delete}
51+
data-post={this.post}
52+
data-regular={this.regular}
53+
/>
54+
)
55+
}
56+
57+
}
58+
59+
export default WorkerVerbs;

tests/src/WorkerVerbs.test.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
const puppeteer = require('puppeteer');
2+
3+
let browser;
4+
let page;
5+
6+
beforeAll(async () => {
7+
browser = await puppeteer.launch();
8+
page = await browser.newPage();
9+
await page.goto('http://localhost:6969/worker-verbs');
10+
});
11+
12+
describe('WorkerVerbs', () => {
13+
14+
test('server functions with name starting with get followed by uppercase letter use GET', async () => {
15+
await page.waitForSelector('[data-get="GET"]');
16+
const element = await page.$('[data-get="GET"]');
17+
expect(element).toBeTruthy();
18+
});
19+
20+
test('server functions with name starting with put followed by uppercase letter use PUT', async () => {
21+
await page.waitForSelector('[data-put="PUT"]');
22+
const element = await page.$('[data-put="PUT"]');
23+
expect(element).toBeTruthy();
24+
});
25+
26+
test('server functions with name starting with patch followed by uppercase letter use PATCH', async () => {
27+
await page.waitForSelector('[data-patch="PATCH"]');
28+
const element = await page.$('[data-patch="PATCH"]');
29+
expect(element).toBeTruthy();
30+
});
31+
32+
test('server functions with name starting with delete followed by uppercase letter use DELETE', async () => {
33+
await page.waitForSelector('[data-delete="DELETE"]');
34+
const element = await page.$('[data-delete="DELETE"]');
35+
expect(element).toBeTruthy();
36+
});
37+
38+
test('server functions with name starting with post followed by uppercase letter use POST', async () => {
39+
await page.waitForSelector('[data-post="POST"]');
40+
const element = await page.$('[data-post="POST"]');
41+
expect(element).toBeTruthy();
42+
});
43+
44+
test('server functions with name starting with get but not followed by uppercase letter use POST', async () => {
45+
await page.waitForSelector('[data-getter="POST"]');
46+
const element = await page.$('[data-getter="POST"]');
47+
expect(element).toBeTruthy();
48+
});
49+
50+
test('server functions with name not starting with a verb use POST', async () => {
51+
await page.waitForSelector('[data-regular="POST"]');
52+
const element = await page.$('[data-regular="POST"]');
53+
expect(element).toBeTruthy();
54+
});
55+
56+
});
57+
58+
afterAll(async () => {
59+
browser.close();
60+
});

workers/dynamicFetch.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ function dynamicStrategy(event) {
33
const url = new URL(event.request.url);
44
if (url.origin !== location.origin) return;
55
if (event.request.method !== 'GET') return;
6+
if (url.pathname.indexOf('/nullstack/') > -1) {
7+
return event.respondWith(networkFirst(event));
8+
}
69
if (url.pathname.indexOf(self.context.environment.key) > -1) {
710
return event.respondWith(cacheFirst(event));
811
}

workers/staticFetch.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
function staticStrategy(event) {
2-
event.waitUntil(async function() {
2+
event.waitUntil(async function () {
33
const url = new URL(event.request.url);
4-
if(url.origin !== location.origin) return;
5-
if(event.request.method !== 'GET') return;
6-
if(url.pathname.indexOf(self.context.environment.key) > -1) {
4+
if (url.origin !== location.origin) return;
5+
if (event.request.method !== 'GET') return;
6+
if (url.pathname.indexOf('/nullstack/') > -1) {
7+
return event.respondWith(networkFirst(event));
8+
}
9+
if (url.pathname.indexOf(self.context.environment.key) > -1) {
710
return event.respondWith(cacheFirst(event));
811
}
9-
if(url.pathname.indexOf('.') > -1) {
12+
if (url.pathname.indexOf('.') > -1) {
1013
return event.respondWith(staleWhileRevalidate(event));
1114
}
12-
if(url.pathname === '/') {
15+
if (url.pathname === '/') {
1316
return event.respondWith(networkFirst(event));
1417
}
1518
event.respondWith(networkDataFirst(event));

0 commit comments

Comments
 (0)