sql >> Databasteknik >  >> NoSQL >> MongoDB

Enkel Node/Express-app, det funktionella programmeringssättet (Hur hanterar man biverkningar i JavaScript?)

Du kommer inte att kunna undvika biverkningar helt men du kan anstränga dig för att maximalt abstrahera bort dem där det är möjligt.

Express-ramverket är till exempel absolut nödvändigt. Du kör funktioner som res.send() helt för deras biverkningar (du bryr dig inte ens om dess avkastningsvärde för det mesta).

Vad du kan göra (utöver att använda const för alla dina deklarationer, använd Immutable.js datastrukturer, Ramda , skriver alla funktioner som const fun = arg => expression; istället för const fun = (arg) => { statement; statement; }; etc.) skulle vara att göra en liten abstraktion om hur Express brukar fungera.

Till exempel kan du skapa funktioner som tar req som parameter och returnerar ett objekt som innehåller svarsstatus, rubriker och en ström som ska skickas som text. Dessa funktioner kan vara rena funktioner i en mening att deras returvärde bara beror på deras argument (förfrågningsobjektet) men du skulle fortfarande behöva lite omslag för att faktiskt skicka svaret med hjälp av Expressens i sig imperativa API. Det kanske inte är trivialt men det kan göras.

Tänk som ett exempel den här funktionen som tar body som ett objekt att skicka som json:

const wrap = f => (req, res) => {
  const { status = 200, headers = {}, body = {} } = f(req);
  res.status(status).set(headers).json(body);
};

Den kan användas för att skapa rutthanterare så här:

app.get('/sum/:x/:y', wrap(req => ({
  headers: { 'Foo': 'Bar' },
  body: { result: +req.params.x + +req.params.y },
})));

använder en funktion som returnerar ett enda uttryck utan biverkningar.

Komplett exempel:

const app = require('express')();

const wrap = f => (req, res) => {
  const { status = 200, headers = {}, body = {} } = f(req);
  res.status(status).set(headers).json(body);
};

app.get('/sum/:x/:y', wrap(req => ({
  headers: { 'Foo': 'Bar' },
  body: { result: +req.params.x + +req.params.y },
})));

app.listen(4444);

Testar svaret:

$ curl localhost:4444/sum/2/4 -v
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 4444 (#0)
> GET /sum/2/4 HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:4444
> Accept: */*
> 
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Foo: Bar
< Content-Type: application/json; charset=utf-8
< Content-Length: 12
< ETag: W/"c-Up02vIPchuYz06aaEYNjufz5tpQ"
< Date: Wed, 19 Jul 2017 15:14:37 GMT
< Connection: keep-alive
< 
* Connection #0 to host localhost left intact
{"result":6}

Naturligtvis är detta bara en grundläggande idé. Du kan göra wrap() funktion acceptera löften om returvärdet för funktionerna för asynkrona operationer, men då kommer det förmodligen inte att vara så bieffektfritt:

const wrap = f => async (req, res) => {
  const { status = 200, headers = {}, body = {} } = await f(req);
  res.status(status).set(headers).json(body);
};

och en hanterare:

const delay = (t, v) => new Promise(resolve => setTimeout(() => resolve(v), t));

app.get('/sum/:x/:y', wrap(req =>
  delay(1000, +req.params.x + +req.params.y).then(result => ({
    headers: { 'Foo': 'Bar' },
    body: { result },
  }))));

Jag använde .then() istället för async /await i hanteraren själv för att få det att se mer funktionellt ut, men det kan skrivas som:

app.get('/sum/:x/:y', wrap(async req => ({
  headers: { 'Foo': 'Bar' },
  body: { result: await delay(1000, +req.params.x + +req.params.y) },
})));

Det skulle kunna göras ännu mer universellt om funktionen som är ett argument för att wrap skulle vara en generator som istället för att bara ge löften om att lösa sig (som de generatorbaserade koroutinerna vanligtvis gör) skulle den ge antingen löften om att lösas eller chuckar att strömma, med viss inpackning för att skilja de två åt. Detta är bara en grundläggande idé men den kan utvidgas mycket längre.




  1. Hur söker jag efter ett objekt med dess ObjectId i mongokonsolen?

  2. MongoDB mongoose utfasningsvarning

  3. Hur lägger man till automatiskt inkrementerande fält i MongoDB-aggregat?

  4. Finns det något sätt att skapa mongodb som _id-strängar utan mongodb?