Â
Building the API
If you’re feeling lazy or just want to play around skip to the end.
To kick this article off we need to build the API first. Our tech stack for the API is as follows:
Our Tech Stack
- Express
- For creating our endpoint and executing code when that endpoint is called.
- Cloudinary
- For saving our website preview images once we fetch or generate them.
- Vercel
- For hosting our API. Vercel's edge network is a powerful tool for web developers and can help them deliver fast and reliable applications to their users.
Getting Started
To start this project we’ll be creating an NPM project. Navigate to your project’s directory and run
npm init
.Create
index.js
and let’s get to coding.Our project requires Express, Axios, and Cloudinary V2. Let’s add these dependencies to our
index.js
file.const express = require("express"); const app = express(); // initialize express const axios = require("axios"); const cloudinary = require("cloudinary").v2;
Install these dependencies with the
-s
flag to save them to our package.json
npm install -s express axios cloudinary
Defining our Endpoint
We’re going to use the base URL for access in this case. All of our API calls will be sent to
https://YOUR-VERCEL-INSTANCE.vercel.app/
app.get("/", (req, res) => { const url = req.query.url; const api = "https://jsonlink.io/api/extract?url="; // A handy tool you should check out! // Geting Opengraph information from jsonlink axios .get(api + url) .then((response) => { let data = { title: response.data.title ? response.data.title : "No Title", // Getting the title url: url, description: response.data.description ? response.data.description // Geting the description : "none", image: response.data.images[0] ? response.data.images[0] : "https://s.soup.cool/api?url=" + url, // If there is no image we'll grab a screenshot }; // Remember to set your Cloudinary values cloudinary.config({ cloud_name: process.env.CLOUD_NAME, api_key: process.env.API_KEY, api_secret: process.env.API_SECRET, }); // Upload the image URL to Cloudinary in the "bookmarks' folder cloudinary.uploader.upload(data.image,{folder: "bookmarks"}, function (error, result) { if (error) { // If we can't upload to Cloudinary for some reason return the original URL shared. let returnData = { image: data.url, description: data.description, title: data.title, url: data.url }; res.setHeader("Content-Type", "application/json"); res.send(JSON.stringify(returnData)); } else { // Return the hosted image URL. let returnData = { image: result.url, description: data.description, title: data.title, url: data.url }; res.setHeader("Content-Type", "application/json"); res.send(JSON.stringify(returnData)); } }); }) .catch((error) => { res.send(error); }); });
Testing our Code
Let’s test out our code quickly to make sure it’s all up and working. At the bottom of our
index.js
file specify a port for Express to listen on. Make sure you grab your Cloudinary API keys from https://cloudinary.com/developers.app.listen(3000, () => { // using port 3000 console.log(`Testing at http://localhost:3000/?url=https://clark.today`); });
Save your code and execute
node index.js
in your terminal. Visit the URL outputted in your browser and you should see something like this.{ "image": "http://res.cloudinary.com/clark-host/image/upload/v1671475454/bookmarks/lky8gfz3tc1zlnwnh9sl.jpg", "description": "I'm a DevOps engineer located on Earth, for now. Feel free to ask me questions about any of my projects listed here or anywhere else you find me!", "title": "Clark Weckmann", "url": "https://clark.today" }
If you see a similar output, we’re almost ready to push it to Vercel.
Before deploying your API I recommend securing somehow, one of the simplest ways is checking for a query value to match an environmental variable./
// If wrong key or no key don't allow access. if (req.query.key != process.env.ACCESS_TOKEN || !req.query.key) { res.send("wrong key"); return; }
You can add the above snippet inside our endpoint.
Stop your API (
ctrl
+ c
) and run vercel
in your terminal. You may have to log in or sign up for Vercel.Deploying to Vercel
Vercel’s CLI will ask you a couple of questions.
- Setup and deploy?
Y
- Link an existing project?
N
- In which directory is your code located
./
The default options are what we’ll be using, you can just hit
Enter
for each question.Â
You should see an output similar to this:
/ Setting up project > Upload [===-----------------] 15% 136.6s - Build Command: `npm run vercel-build` or `npm run build` - Output Directory: `public` if it exists, or `.` - Development Command: None ? Want to override the settings? [y/N]
Again, just hit
Enter
or enter N
🔗 Linked to user/project (created .vercel and added it to .gitignore) 🔍 Inspect: https://vercel.com/<user>/<project>/<ID> [1s] ✅ Production: https://<project>.vercel.app [copied to clipboard] [7s] 📝 Deployed to production. Run `vercel --prod` to overwrite later (https://vercel.link/2F). 💡 To change the domain or build command, go to https://vercel.com/<user>/<project>/settings
Before we start with the IOS Shortcut, let’s test our API one more time. Visit the last link printed in your console to access your project settings. Navigate over to your project's Environment Variables.
Add your
CLOUD_NAME
, API_KEY
, API_SECRET
, and your ACCESS_TOKEN
we’re using to prevent unauthorized use of our API.Let’s test one more time now, navigate to your project’s domain
https://<project>.vercel.app
and add in our two queries. ?url=https://someurl.com&key=ACCESS_TOKEN
You should get a JSON output containing the URL’s image
, description
, title
, and original URL
.Building the IOS Shortcut
Our flow for the IOS Shortcut is pretty simple, check it out.
Share Sheet
⇒ Get Contents of URL(
API_URL
)
⇒ Set Variable
URL
to
Contents of URL
⇒ Get
Diction
from
URL
⇒ Add Page(
Dictionary
) To Database
Nautomate
If you’re unfamiliar with Nautomate I recommend checking out their website.
You can download the completed shortcut here:
If you have trouble with Apple Shortcuts links, you can also download it from here.
Skip The Coding
Click the link above to deploy directly to Vercel and initialize a Git repository with the code ready to roll.
Â