This is getting very cool... when I first looked at GraphQL a few years ago, the tooling was much less mature and took a lot of effort. It seems to be getting much better to use in practice. Would still like to see more articles about how to attach/handle security (jwt bearer tokens, for example) with a GraphQL server and client.
On #2, when using a getter that calls a function that can throw, it's a good idea to wrap in a try/catch as property getting should not be a point where an application throws in practice.
You could alternatively use the following pattern, and have your application loader parse and inject the configuration for the rest of your application to utilize...
export const configuration = {};
export function setConfiguration(data) {
Object.keys(configuration).forEach(c => {
delete configuration[c];
});
Object.assign(configuration, data);
};
export default configuration;
Not really code or JS centric and doesn't really dive into the issue at all with useful examples. It's a low quality post.
Personally, I'd say it depends... you should absolutely load middleware separate from your controllers. In terms of service separation, it depends. If it's a really simple DB call without much abstraction, I'd say do it in your controllers.
With koa, I add a database connection object to the context (context.db or context.sql) that makes it ready to go... this way I can use:
router.get('/foo/:id',
router.validate({
params: Joi.object({
id: ...
})
}),
router.authorize('admin'),
async ctx => {
ctx.body = await ctx.sql`
SELECT ...
FROM ...
WHERE Foo.id = ${ctx.params.id}
`;
},
);
I use koa router for all of my api routes, and mount it to `/api` at a higher level. I also add a validate and authorize function to the router. This way, I can add Joi validation schemas to body and/or params, etc. The authorize method inputs `(...roles)` so I can just add any required roles, if no role is specified, it still must have a logged in api token (jwt) with the request, but any role allowed.
In this case, separating out the sql query into a separate service or data access layer doesn't add value imho.
Just yesterday gave a quick training session on Async functions and Promises... One of the few times I've used typescript, only to reinforce that Async functions return a promise, and can await on promises, to show a function returning a promise is effectively the same. As well as Promise.resolve and Promise.reject for use in mocking for tests.
For pretty much everything I'm working on now, I cut off with fetch and async function support (around April 2017 and newer browsers). In node, I use node-fetch or setup a global if I'm sharing code libraries.
While fetch isn't perfect, usually create an api wrapper around it. It's standard, cleaner than alternatives and built into the browsers (smaller bundles).
Yeah... the preflight check should be a must... same for a <noscript> at load, which I don't do. Anyone that has scripting disabled is likely to know what they're getting and why. IIRC, iOS 11 (april/may 2017) is the break point for async and supports iPhone 6 and 5S I think.
Most of my work is internalized apps, but at this point even public facing it's probably a fair cutoff. Killing the async/generator transforms is a pretty big improvement... I'd love to see a modern server that detects behaviors and pushes the mjs most likely to be requested from an initial starting point.
These days charting libraries are about the only thing too big imho that should be lazy loaded when needed. I try to keep my app bundles under 500k, which includes styling and a layout images. Larger than I'd like, but given the landscape reasonable for the effort.
Very cool... My hope is that eventually the browser's JS engine will add a jsx pragma directive that will allow you to specify your jsx translation in the browser + js.
That said, I've all but dropped legacy (IE11) support and break at anything that doesn't support async functions .
// index.precheck.js
try {
eval('(function() { async _ => _; })();');
} catch (e) {
window.location.replace('/legacy.html');
}
With the above precheck in place, I have my main index.js generated via the following babel configuration... It specifically excludes the async/generator transforms which are freaky huge... without them, my bundles are a decent size.
// .babelrc
{
"presets": [
[
"@babel/preset-env",
{
"modules": false,
"useBuiltIns": "usage",
"targets": {
"browsers": "> 5%"
},
"exclude": [
"transform-async-to-generator",
"transform-regenerator"
]
}
],
"@babel/preset-react"
],
"env": {
"test": {
"plugins": [
[
"@babel/plugin-transform-modules-commonjs",
{
"allowTopLevelThis": true
}
],
[
"babel-plugin-dynamic-import-node",
{
"noInterop": true
}
]
]
}
}
}
Vue + Google Tag Manager === holding old DOM nodes in memory
The fix itself is somewhat sloppy. That said, it's worth understanding. Not sure if GTM would do similar with refs if you're using React and tbh, not sure how much value GTM actually adds in practice. It may really only apply to Vue and GTM combined.
Used to see this type of problem a *LOT* with SPAs in IE prior to version 8, as JS and the HTML renderer were in different memory spaces, so either side holding a handle wouldn't know about the other releasing the reference. One thing very cool if you used jQuery once it came out, as it would release both sides if you used jQuery for your event binding and DOM manipulation. This is less of an issue in modern browsers.
In this case, you have two sets of code holding references to DOM nodes, the UI itself and GTM. I'm unsure if their fix actually breaks GTM and it seems it probably does. So even then, not sure wth the point is.
If you're wrapping the response from fetch for an error, I would suggest using
throw Object.assign(new Error("Fetch Error"), { response });
This gives you the full context instead of response.toString() as the error message.
Something I do in practice for my API endpoints is always return {result} or {error} from my API. An object where a root error can be checked against, or the result... This way I can have a very consistent handler, which is usually a wrapper around fetch as I'm not currently supporting any non-green browsers and fetch has been around for long enough now.