export class MicroFrontendRegistry
Published: 2022-07-21 19:56:00

In the DDG example, there's a lot of *~magic~* in that call to `MicroFrontendRegistry.call()` which actually ensures the DDG endpoint is hit successfully. So let's de-magic a bit.

## Deciding how to build the abstraction
Because we work so much with web components and the `window.customElements` global that makes the registry possible for frontend bricks, I decided to mirror it a bit when building a parallel concept for microservice endpoints.

- [source for MFR](https://github.com/elmsln/lrnwebcomponents/blob/master/elements/micro-frontend-registry/src/micro-frontend-registry.js)
- [defining services](https://github.com/elmsln/lrnwebcomponents/blob/master/elements/micro-frontend-registry/lib/microServices.js)
- [npm](https://www.npmjs.com/package/@lrnwebcomponents/micro-frontend-registry)

The `MicroFrontendRegistry` consists mostly of:
- providing a singleton interface so that only 1 registry exists no matter the timing of who declares it
- making this queryable via the DOMor direct window access (personal preference, I always write my singletons this way)
- `set` / `add` - new services so we can leverage them
- `has` - verify a service is valid without calling it
- `call` - execute request against the service
- `url` - generate a URL to the service (useful for `src` building)

## Definition of a service
Because I'm always trying to opt for maximal reuse across different contexts; I didn't assume that this was the only project I'd ever use these microservices in. I also don't want to assume these services will never conflict or that you'll always want to have `@core/whatever` as a service in your project.

As a result, we have services grouped into chunks of services that can be defined via single calls. Right now we have three groups that can be included easily as a shortcut to leveraging them.
```js
import { enableServices } from '@lrnwebcomponents/micro-frontend-registry/lib/microServices.js';
// then enable the service groups in question
enableServices(['core', 'experimental', 'haxcms']);
```
- *core* - services that are common / expected / simple
- *experimental* - ones for playing with / future consideration
- *haxcms* - application specific things for haxcms

Again, these are just going to add a whole bunch of services quickly, but let's go back to the duck duck go example as to how the middleware class knew what to call and where it was.

## DDG registration of microservice
```js
// duckDuckGo
  MicroFrontendRegistry.add(
    {
      endpoint: '/api/services/website/duckDuckGo',
      name: '@core/duckDuckGo',
      title: 'Duck Duck Go',
      description: 'Search results from duck duck go',
      params: {
        q: "query param to search on"
      }
    }
  );
```
Here we see we have an endpoint and the name. Title, description and parameters are mostly for developers to know / if we ever decide to visualize this information. In the case of DDG, all we do is pass in the query param `q` and we'll get this endpoint called and return our `json` blob of results. This simple association of endpoint to name will allow us to swap out and move the endpoint name at a later time if needed.

## Uh... well when is it needed?
Funny you should ask! Here's what the next definition after DDG looks like:
```js
  // screenshot - kept by itself bc of size of getBrowserInstance
  MicroFrontendRegistry.add({
    endpoint: "https://screenshoturl.elmsln.vercel.app/api/screenshotUrl",
    name: "@core/screenshotUrl",
    title: "Screenshot page",
    description: "Takes screenshot of a URL and returns image",
    params: {
      urlToCapture: "full url with https",
      quality: "Optional image quality parameter"
    }
  });
```
😺 - Me building the screenshot service locally in vercel
😖 - Me in production trying to call it

The reason in this case, was that our `screenshotUrl` leverages `puppeteer` an awesome but heavy (file weight) library for running Chrome and other browsers headlessly. As a result of limitations with AWS lambda (which Vercel rides on top of) our monorepo couldn't have puppeteer running alongside everything else.

As a result, our paths needed changed as we pushed this functionality to it's own repository (and thus it could build independently and work without file size limits!). To make this change, I swapped out the original `endpoint: "/api/media/web/screenshot", for the full URL to the production path. All the places we were calling `@core/screenshotUrl` didn't change though!

By following a `npm`-esk methodology for naming, we can extend how we call these in the future, namespace nicely, and give a convention that people are used to, without directly referencing URLs which might change or need to be moved in the future.

The other reasons for moving are less interesting; like renaming, refactoring, etc.

## Video time recapping these three articles
Here's a video stepping through the code and call structures to make DDG work end to end.
{% embed https://www.youtube.com/watch?v=egVMT-vS66g %}