Another week done, another week in review. I’ll talk first about my week then the progress I’m making with the User Microservice.
I started my Saturday off with a review on this minor PR here from Tony. MUI is really neat and I’d love to learn more about it, I love the idea of having a global theme and utilizing it throughout your entire web app. CSS libraries are spiffy.
Sunday Funday came around and I started it off by testing a PR from Mo which I concluded with adding instructions on how to test the changes locally. Unfortunately the PR was ultimately closed (as we no longer use Gatsby) but sometimes this is the nature in software development. Hell, most of Google’s crap is removed several months after launching, I wonder how those engineers feel about that.
I concluded my Sunday reviews by testing this bug fix which was driving me up the wall every time I noticed it. Ilya does a lot of these little bug fixes which overtime increase the overall UX of our app. Love it.
Monday rolls around and I starting work on a pagebase that I can use for the About page that I designed using MDX.
I originally intended to dynamically render each and every doc in our app’s doc folder using the dynamic routes feature of NextJS. With a similar layout (i.e. pagebase) each document will look the same when it’s rendered. I want to get around to working on this but my primary focus right now is to finish the User Microservice.
I ran into an issue early on and couldn’t for the life of me figure out how to make the .mdx
file inherent the styles I passed but everything else is fine. I eventually had an idea to throw all the content into an about.md
file and just import
it in:
import MDXPageBase from '../pages/layouts/MDXPageBase';
import About from '../markdown-pages/about.md';
const AboutPage = () => {
return (
<>
<MDXPageBase title='About Us'>
<About />
</MDXPageBase>
</>
);
};
export default AboutPage;
The pagebase’s code (MDXPageBase
) can be viewed here. I also might have reviewed my own PR:
I spent a bit more time working on this on Tuesday/Wednesday and finally made the PR on Wednesday. I also got some great help from Anton with a really neat use of destructuring to shorten some repeated code:
const {
palette: {
primary: { main },
},
} = theme;
I also discovered a new bug with out GitHub Contributors card which (thankfully) ol' reliable Ilya expressed interest in fixing.
Wednesday. Finished up pagebase for with some help from Tony (and a really great types link from Pedro.) I spent so long screwing around trying to get the theme working and just right in MDXPageBase
so thank the gods for Tony, big shout out to him for the fix. Sent my PR and moved onto the next issue. Submitting a PR still makes me feel nervous.
Anyway, I then started working on my little SEO fix and jeez talk about a rabbit hole. This was supposed to be a 5 minute fix! It was anything but:
- I started off by exploring all uses of
meta
tags in each and every component including the ones inside our_document
file.- I figured the smart play was to move the
<Head>
code (along with all its the accompanying<meta>
tags) from_document
to the SEO component because SEO renders<Head>
and additional<meta>
tags. This didn’t work (see point 2.) - I then tried another approach, removing all
<Head>
calls in SEO and returning only the<meta>
tags, which would allow something like the following:<Head><SEO/></Head>
. Also didn’t work:TypeError: Cannot destructure property 'pathname' of 'Object(...)(...)' as it is null.
Seems that_document
doesn’t like the use ofconst { pathname } = useRouter();
. It only turned out then that I noticed the import for<Head>
was different in_document
and SEO…import Head from 'next/document'
vsimport Head from 'next/head';
So off to Google I went to discover the difference and if one or the other was unneeded (though at this point I started to panic, I started to feel as though there was no work around and we just have to have some sort of repeated code):- For the curious reader: this link was super helpful, and this link was too. Turns out both
<Head>
s have separate purposes and as a result I think all the<meta>
tags should stay as is and a minor tidy-up can take place in its stead.
- I figured the smart play was to move the
- Disappointed! Thought I was on this really great refactor kick and now my PR is only going to contain… well, a 5 minute fix. I spent way longer on this than I should have but I learned some really interesting things about NextJS. I hung my head in shame, remade my branch, and started back refactoring SEO in place of all
<Head>
(next/head
) calls, and made my PR.
Thor’s-day. Tony and I discovered that our CI pipeline started to fail at around 11am or so:
npm ERR! code ETARGET
npm ERR! notarget No matching version found for @graphql-tools/merge@^6.2.8.
npm ERR! notarget In most cases you or one of your dependencies are requesting
npm ERR! notarget a package version that doesn't exist.
npm ERR! notarget
npm ERR! notarget It was specified as a dependency of '@graphql-tools/load'
npm ERR! notarget
We all discussed reasons for this and I did some digging around trying to find some info from GraphQL-Tools as to why and found this.
Also got some sage wisdom regarding this:
humphd 12:32 PM
it's a dep of a dep
humphd 12:32 PM
and npm is picking a patch release that doesn't exist
Anton Biriukov 12:33 PM
but if did not update our dep in the first place, how could've their dep got updated (which broke it)?
each package has to release a new version to update its own deps, right?
Abdulbasid Guled 12:34 PM
This is something I need to research, if dependencies within dependencies update on their own?
Anton Biriukov 12:34 PM
I was under impression that they should not
humphd 12:35 PM
they do with the lock file
Cool. TIL. A really bad day for someone on either the GraphQL team, or NPM, as GraphQL is pointing the finger at NPM for the reason their build failed. Pretty funny how a minor issue like this could affect potentially thousands of Gatsby and pages using GraphQL.
I also reviewed yet another MUI related PR from Tony.
Friday. Today. Our rush day I spent most of the morning prepping for our meeting, reviewing PRs, and catching up on the status of the project and our 1.7 release. Quick approvals in no particular order: This, this, this, and this. We all got a lot of work in this week and FINALLY shipped Telescope using only NextJS and TypeScript. Great for us, bad for all the students hard work that came before us. I can’t wait until the next group of students hopefully does the same to us. We have a few minor bandaids to apply but for better or worse our mark remains on Telescope for the forseeable future.
The cycle of software continues evermore.
User Microservice
I tried to spend some time this week working on my User Microservice, though my primary focus being on getting my two other PRs in before 1.7.
Anyway, my focus for this week was to at least get Celebrate in and working as intended. I came across a really solid blog post by celebrate’s creator here.
What is Celebrate?
celebrate is an express middleware function that wraps the joi validation library. This allows you to use this middleware in any single route, or globally, and ensure that all of your inputs are correct before any handler function.
A little backstory on the situation: I currently have a mini express server which will be making calls to a Firestore database, and receiving calls from a frontend containing data from users. Naturally, we have to ensure that the data being persisted is as clean as possible.
celebrate is perfect for this because it’s flexible to utilize route validate either globally or specifically per route. I actually want to implement this globally in my capstone project as we use Passport and Google’s OAuth ids, coupled with state to send and receiving data to our db, and for making payments via Stripe. Ensuring that a user currently has a valid ID in ALL backend calls can prevent anyone from using postman to persist garbage to our db.
Anyway, I spent a while working on celebrate and kept bashing my head against a wall as I just couldn’t get the post route to cooperate with celebrate. I was doing everything right! Every post, every document, I even google’d other projects using celebrate. It looked fine! What was the issue?
Oversight. Oversight was the issue. It turns out the issue was router.use(bodyParser.urlencoded({ extended: true }));
vs router.use(bodyParser.json());
… for some reason I just assumed that the former contained that latter and thus I didn’t need to specify bodyParser.json()
Stupid. Really stupid. At least I got some wonderous sage wisdom (after wasting his time too in an attempt to help):
humphd 5:58 PM don’t stop your progress just keep track of defects, write a test and add .skip() on it perfect is the enemy of the good the thing with how we do open source is that you acknowledge your bugs, and iterate to fix them vs. only shipping when it’s ready ship all the time, and file then fix
One bug down, one to go:
router.get(
'/user/:id',
celebrate({
[Segments.PARAMS]: {
id: Joi.number().required(),
},
}),
async (req, res, next) => {
try {
const userRef = db.collection('users').doc(req.params.id);
const doc = await userRef.get();
res.status(202).json(doc.data());
}
} catch (err) {
next(err);
}
}
);
GET http://localhost:5555/user/123
yields the following error: Error: Value for argument "documentPath" is not a valid resource path. Path must be a non-empty string.
which goes away when not using the celebrate middleware, and a user is retrieved successfully. I didn’t let this slow me down and instead tried programming defensively for the time being:
router.get(
'/user/:id',
celebrate({
[Segments.PARAMS]: {
id: Joi.number().required(),
},
}),
async (req, res, next) => {
try {
const userRef = db.collection('users').doc(req.params.id);
const doc = await userRef.get();
// placeholder if else until i can figure out celebrate
if (!doc.exists) {
console.log(`User data (id: ${doc.id}) was requested by ${req.ip} but could not be found.`);
res.status(404).json({
msg: `User data (id: ${doc.id}) was requested but could not be found.`,
});
} else {
console.log(
`User data (id: ${doc.id}) was requested by ${req.ip} and served successfully.`
);
res.status(202).json(doc.data());
}
} catch (err) {
next(err);
}
}
);
This is a weird Firestore issue, my first instinct is that celebrate is converting the param 123
to a string or something funky. Unsure. It console logs as a number though so I’m not sure. Regardless, I’ll actually listen for once and come back to this at a later time and date.
I also read a best practices doc from Google regarding Firestore which can be seen here.
I also wanted to write an update route for users, but it turns out that you can attach { merge: true }
to a post request and send it off to Firestore to achieve very similar results. A found good link here explaining the difference, however I still think making a put
/ patch
route is the way to approach this scenario as: update will update fields, but will fail if the document doesn't exist.
I also thought of exporting the celebrate schema that I’m using in both the get
and post
and throwing them into /config/celebrate.js
file or something, so I can import it and make my requests a bit easier to read and understand (plus it’ll look cooler):
import { celebratePost } from './config/celebrate';
router.post(
'/user',
celebratePost,
async (req, res, next) => {
try {
await db.collection('users').doc(`${req.body.id}`).set(req.body, { merge: true });
console.log(`Added user with id: ${req.body.id}:\n${JSON.stringify(req.body)}`);
res.status(201).send(`Added user with id: ${req.body.id}:\n${JSON.stringify(req.body)}`);
} catch (err) {
next(err);
}
}
);
but this is just an idea I’m playing around with in my head. I’ll probably forget about it right after I finish this blog post and never do it. We’ll see.
I also started looking into Firebase Emulator. This major step is in its very early stages and I’m unsure how this will work with Jest, but I’m going to fart around with it all next week and hopefully have some progress to report back on. I also got Firestore to run locally, which is really sweet:
That about does it for me this week. It was busy and I think I got a lot done. I wanted to get more work into my microservice but c’est la vie. I’m hoping next week will be a major milestone for and I’ll have a draft PR to present to the world.
Next week’s microservice todo:
- Get testing working with the emulator and Jest
- Implement Satellite
- Create some basic README.md files
- Export my private key to
.env
(was having trouble with this last week) - Figure out how to utilize my
User
class/schema - Create an update route
- Create a delete route
- Add date/time users were created (mostly for funsies)
- Add date/time users were updated (again, for funsies)
In Other News:
- Found this really neat program here that converts a React Native frontend to a Windows/Mac app. I’m really interested in App development but have no experience in it at all. I want to pick up Java/Kotlin and Swift but figure React Native is the next best thing. And this is cool as hell.
- Gojira released a new song on their upcoming album.
- Found out about GitHub’s skyline feature. Amazingly, you can export the render to an STL file, this making it 3d printable. I’ll be trying to print it this week I think. Hopefully I can show it off next Friday.
- We landed another fricken rover on Mars. I saw the livestream of it being launched around my birthday last year and set a reminder for this this week to watch it. Nasa even released the approximate time it would land on the Red Planet, and amazingly it was right. Isn’t that insane?