Your guide into the world of food trucks of San Francisco and my take on Take Home Engineering Challenge.
This repo is basically a fork of my own demo web UI for Azure Cognitive Search - https://github.com/scale-tone/cognitive-search-static-web-apps-sample-ui. The application code here is almost identical to the code there (except for minor UI fixes).
Yet it also includes this deployment script, which automatically creates all required Azure resources (an Azure Cognitive Search index, an Azure Maps account and an Azure Static Web App instance) and also populates the index with data from https://data.sfgov.org/api/views/rqzj-sfat/rows.csv.
https://purple-forest-0da7f9603.azurestaticapps.net
This web app implements the so called faceted search user experience, whereas the user first enters some search phrase and then narrows down search resuls with facets on the left sidebar. Facets have different data types, and the app automatically detects and renders them accordingly. E.g. FoodItems
is an array of strings, and you can pick up several values there, and also choose whether they should be combined with OR
('ANY OF') or AND
('ALL OF') logical operator. X
and Y
facets are numbers, so those are rendered as two-way sliders.
The map is also interactive. Use the 'draw-rectangle' button in the lower-right corner to select rectangular regions on it:
Search result cards show generic info about a particular food truck/push cart, including the list of food items it offers. Items in this list are clickable, use them to narrow down your search to a specific type of food you enjoy the most. Clicking on a card brings up the 'Details' dialog with all the item's data shown on it.
The list of search results supports infinite scrolling.
Also, all the search parameters are reflected in the browser's address bar, making your searches easily shareable.
As per prerequisites, you will need:
- Azure CLI, >>> version 2.33.0 or later <<< (earlier versions might fail to deploy Static Web Apps).
- Powershell.
- You need to be logged in into Azure:
az login
Do the following:
-
Fork this repo (cloning is not enough, because Static Web Apps deployment process needs write access to your GitHub repo).
-
Make sure GitHub Actions are enabled for your newly forked repo:
-
Clone your fork onto your local devbox.
-
Go to the project root folder and run the included Powershell deployment script from there:
./deploy.ps1
IMPORTANT: at some point the script will pause and wait for you to login into GitHub:
Please, do what it asks you to.
All the deployed Azure resources will be placed into the same resource group (by default, it will be called 'food-trucks-rg'). Don't forget to cleanup those resources once you're done with them.
Apart from creating/updating Azure resources, the script also updates the search index with latest trucks data. This can take a few minutes, so please be patient.
Once done, the script will show you the URL of your newly created Azure Static Web App instance:
Navigate to that URL with your browser and observe the app running.
The deployment script has some optional parameters, that allow you to customize resource names and other things. See the commments here.
Also, the script is idempotent. You can re-run it at any time, e.g. to re-populate the search index with latest data.
Alternatively, you can use this ARM template to deploy the Static Web App only, but in that case you need to have a search index already created (or reuse some existing one).
As per prerequisites, you will need:
-
Azure Functions Core Tools package installed globally (
npm i -g azure-functions-core-tools@3
). -
A pre-created and pre-populated Azure Cognitive Search index. You can create it by running the deployment script like this:
./deploy.ps1 -skipDeployingStaticWebApp $true
Do the following:
-
Clone the sources onto your devbox.
-
Update the
SearchApiKey
andAzureMapSubscriptionKey
settings in /api/local.settings.json file with your key values. -
Make sure these keys will never be committed.
-
Go to the project root folder and execute this:
npm install npm run start-with-backend
The code will be compiled and started at http://localhost:3000. A browser tab with that page should open up automatically, but if not, then navigate to http://localhost:3000 with your browser.
The code here is a typical React- and TypeScript-based Single-Page Application (SPA), designed to be hosted via Azure Static Web Apps. With help from MobX, it implements a classic Model-View-ViewModel design pattern. It has a hierarchy of state objects (aka viewmodels) and a corresponding hierarchy of pure (stateless) React components (aka views). These two hierarchies are welded together at the root level here. For example, here is the state object, that represents the list of search results, and here is its markup.
The list of facets and their possible values on the left sidebar is generated dynamically, based on CognitiveSearchFacetFields config value and results returned by Cognitive Search. The type of each faceted field (and the way it needs to be visualized) is also detected dynamically here.
The app doesn't have a backend as such. Instead, all requests to the underlying search index are proxied via this set of Azure Function proxies, where the Cognitive Search api-key is appended to each request. This ensures that the api-key is never exposed to the public and at the same time greatly simplifies the architecture.
The decision to implement deployment via a script was heavily influenced by the need to pre-populate the search index with data (which needs to be re-formatted beforehand). If not for that, then all the required resources could instead be deployed with an ARM template.
By default there will be no authentication configured for your Static Web App instance, so anyone could potentially access it. You can then explicitly configure authN/authZ rules as described here. E.g. to force every user to authenticate via AAD just add the following property: "allowedRoles": [ "authenticated" ]
to the only one route that is currently defined in routes.json. Please remember though, that authenticated
is a built-in role, which corresponds to anybody anyhow authenticated. To restrict the list of allowed users further, you will need to define and assign your own custom roles.
- There's an ongoing DNS issue with Static Web Apps, whereas newly created instances might not be reachable. This seems to be very specific to the internet provider you use. If the app instance doesn't respond, try switching to another (e.g. mobile) network.
- Static Web App deployments depend on GitHub Actions. GitHub Actions tend to be down from time to time. If the app fails to be deployed, check the current status of GitHub Actions.
- When using a GitHub Codespace as a devbox, there can be CORS-related problems. Please, don't run this on a GitHub Codespace.
- Microsoft Defender might severely impede performance of Node.js-based applications, especially at first run (because it scans all the node_modules and everything). If you run this code on your devbox and it is not starting for minutes - well, again, just be patient.
- Unit tests are almost missing. There're a few here, but so far they just demonstrate the idea and nothing more.
- The deployment script could be optimized so, that it ingests trucks data in batches, rather than one-by-one. That would greatly increase its speed.
- Intergration tests at the end of the deployment script could be more extensive. By far it only pings one single endpoint and doesn't even validate whether the search index is up and running.
- Would be great to make the deployment script accept a GitHub personal access token, so that it can be run unattended (instead of requiring you to go through GitHub Device Activation)
- Client side needs to be migrated to latest versions of MobX and Material-UI. This would take some refactoring though, because they're backward-incompatible.
If you like it, then don't hesitate to put a star on https://github.com/scale-tone/cognitive-search-static-web-apps-sample-ui