By Jaden Baptista from TakeShape & Patricio Vargas from OneSignal

We're excited to share a sample project we’ve been working on with TakeShape which leverages our push notification solution with TakeShape’s powerful API mesh. This article explains what we accomplished and the steps we took to get there. If you want to follow along, you can check out the GitHub repo.

Project Goals

  • Build an app that will look up a country based on its abbreviation and send the user a push notification
  • Use OneSignal's SDK to do the subscription registration for push notifications
  • Send the actual notification with OneSignal using an API call from TakeShape
  • Use TakeShape to set up a pipeline for the data that can be triggered with a single GraphQL API call instead of multiple separate callsIt'll be our app → TakeShape API mesh → Countries API → TakeShape API mesh → OneSignal API → return to our app. All in one request.
  • Turn this into a starter project to help people get going with TakeShape and OneSignal
  • Try to make it look pretty so that people don't ridicule us for making something cool without it looking the part

Our Process

This tutorial will cover how to integrate OneSignal push notifications into your app using our typical setup process and how to send push notifications using the OneSignal REST API.

Part 1: Set Up Your OneSignal Account

To begin, login to your OneSignal account or create a free account. Then, click on the blue button entitled New App/Website to configure your OneSignal account to create your app or website.

Configure the name of your app or website. Select Web Push as your platform.

Click on the blue button entitled, Next: Configure Your Platform.

Web Configuration

Under Choose Integration, select the Typical Site option.

In the Site Setup section, enter your chosen web configuration. In my case, the configuration looks like this:

Notice for testing purposes we entered our localhost URL (http://localhost:3000). If you are doing the same, make sure you click on the LOCAL TESTING option. This will ensure to treat HTTP localhost as HTTPS for testing.

Under Permission Prompt Setup, you will see three vertical blue dots under the Actions header on the far right side of the screen. Click on the blue dots and select Edit from the drop-down menu.

A window will open with the configuration of our push notification Slide Prompt. Confirm that Auto-prompt is enabled (toggled to the right).

Under Show When, you can choose how long your slide prompt will delay after a user visits your page. You can leave it as it is, or you can reduce the seconds so that your prompt appears sooner. Once you've chosen your delay time, click the grey Done button located at the bottom right corner of the window.

After clicking Done, scroll down to the bottom of the page and click Save to save your auto-prompt configurations.

You will be redirected to a different page with an important step: Downloading the SDK files. Click DOWNLOAD ONESIGNAL SDK FILES and save them on your computer to retrieve later. We'll show you where to put them in a bit after we set up our site's directory.


Under the section entitled Add Code to Site, you will see a grey button that allows you to copy the code snippet. Click the grey COPY CODE button.

Part 2: Create a New TakeShape Project

To set up that pipeline we mentioned earlier, we needed to find the right API. For this project, we were thinking of using something more fun and quirky like the PokeAPI, but we ended up settling on something a little more useful (well, I suppose that depends on how you spend your free time) with the CountriesAPI designed by Trevor Blades at Apollo. We’ve outlined our steps below so you can follow along.

To get started, go to takeshape.io and started a new project like this:

Make sure you’re making a new blank project instead of following a predefined pattern.

Once that’s done, you can connect your two services. There's a shortcut Connect Service button on the homepage of the project that will take you to a form that you must fill out once for OneSignal and once for the CountriesAPI. This is what the latter config looked like:

It’s basically Plug’n’Play. The OneSignal's setup is just as easy because the API key is actually sent along with the JSON body — we'll get to that in a bit.

Next, you’ll need to create the GraphQL mutation that will: 1) look up a country's data from the CountriesAPI and 2) ping OneSignal with the country’s data, plus:

  • Your API key.
  • The hash that identifies which device to send the notification to.
  • the country code to insert into the URL of the CountryFlags API so that you can get automatically add an image to the push notification.

Here's the text of the query in the schema's JSON file:

/*
	Obviously JSON doesn't have comments, but I'm going to add a
	few JavaScript-style comments to explain what each line does
*/


"mutations": { // this is the mutations object in the root of our schema JSON file
    "sendPushNotification": { // the name of this mutation
      "description": "Sends a push notification to the given subscribed user with the given image and content.",
      "args": {
        "type": "object",
        "properties": { 
					/*
						these are the arguments coming into the mutation
						usually you'd make a shape for it and just put "args": "NameOfInputShape"
						here I've opted to list the arguments in the mutation
						no reason other than that it feels right
						we have two arguments defined below, both strings
					*/
          "user": {"type": "string"},
          "countryCode": {"type": "string"}
        },
        "required": ["user", "countryCode"] // both arguments are required
      },
      "shape": "OneSignalResult", 
			/* ^^^^^ is the shape of the result, 
			but we don't really care about our output from onesignal here */
      "resolver": { // aka how we fill in the output steps
        "compose": [ // we're going to do that by following this array of steps
          {
            "name": "graphql:query", // use graphql
            "service": "countries",  // to send a ping to the countries service
            "options": {
              "fieldName": "country", // to get this type with the following query
              "selectionSet": "{ name native continent { name } capital currency }"
            },
						// below, map the `countryCode` from our input to `code` so CountriesAPI will understand
            "argsMapping": {"code": [["get", {"path": "args.countryCode"}]]}
          },
          { // after finishing the request to CountriesAPI, start step 2 of the resolver
            "name": "rest:post",                   // it's a post request
            "service": "onesignal",                // to the onesignal service
            "options": {"path": "notifications"},  // specifically to the /notifications endpoint
            "argsMapping": {
              "json.chrome_web_icon": [ // send an argument called "chrome_web_icon" to onesignal
                [
                  "expressionEval",
                  { // "chrome_web_icon" should be a URL to countryflags.io with the original country code in it
                    "expression": "'https://www.countryflags.io/' + args.countryCode + '/flat/64.png'"
                  }
                ]
              ],
              "json.app_id": [ // set our app_id to a constant (redacted here for obvious reasons)
                ["set", {"value": "MY-REDACTED-ONESIGNAL-APP-KEY"}]
              ],
							// send our original input user id as the only element in an array called "include_player_ids"
              "json.include_player_ids[0]": [["get", {"path": "args.user"}]], 
              "json.contents.en": [ // send along an object called "contents" with a key "en"
                [
                  "expressionEval",
                  { // set the key "en" to this long message with data from the CountriesAPI
                    "expression": "steps[0].native + '(' + steps[0].name + ') is in ' + steps[0].continent.name + '. In the capital, ' + steps[0].capital + ', the people like to spend ' + steps[0].currency + '.'"
                  }
                ]
              ]
            }
          }
        ],
        "resultsMapping": {"id": [["get", {"path": "steps[1].id"}]]} // send the notification id to our output
      }
    }
  }

That JSON without all the comments is uploaded into TakeShape. We actually just did it through the editor in the project, but you can do it through the terminal as well if you prefer.

To summarize, this process allows you to send this GraphQL query to the TakeShape API mesh endpoint:

mutation {
sendPushNotification (
user: "my-onesignal-user-id-from-the-sdk",
countryCode: "US"
) {
id
}
}

Then, TakeShape will:

  1. Go to the Countries API and get some data about the country we've been given using its abbreviation.
  2. Turn that data into a message and send it along with an image of the country's flag and the device's ID to OneSignal.
  3. Return the ID that OneSignal returns.

Although that may seem tough at first, it is actually fairly intuitive. All you have left to do is to make the GraphQL call in JavaScript!

Another feature we wanted to implement was to add a <select> file on the page with a list of all the country codes, because who really remembers the abbreviation of the country they're looking up? Before we get to that, we first finished setting up the OneSignal SDK.

Part 3: Set Up the OneSignal SDK in Your App

In your Web project folder, navigate to the index.html file. Inside of the head HTML tag, paste the code you previously copied from the OneSignal page:

<script src="https://cdn.onesignal.com/sdks/OneSignalSDK.js" async=""></script>
<script>
window.OneSignal = window.OneSignal || [];
OneSignal.push(function() {
OneSignal.init({
appId: "YOUR-APP-ID",
});
});
</script>

Now, locate the SDK files you downloaded on your computer and insert them inside the root folder of your Web app.

After you have inserted the SDK files into your Web project, you'll need to add a <button> to send the notification to yourself. Inside of the <body> tag, add the following code:

<button onclick="sendPush()" id="send-push">SEND PUSH</button>
This button will now call a function called sendPush() that we will create inside of the index.js file. Add the following code to the top of your file. This code contains the API key, the GraphQL endpoint from TakeShape, and the project ID:

const projectID = "YOUR-PROJECT-ID";
const apiKey = "YOUR_API_KEY";
const takeShapeURL = `https://api.takeshape.io/project/${projectID}/v3/graphql`;

Once you have added the code above, it's time for you to use it inside of our sendPush() function. Create the sendPush() function by adding the following code:

const sendPush = async () => {
await fetch(
takeShapeURL,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`
},
body: JSON.stringify({
query: `
mutation {
sendPushNotification (
user: "${await OneSignal.getUserId()}",
countryCode: "${select.value}"
) {
id
}
}
`
})
}
);
};

As you can see, this code is making a POST call to the TakeShape GraphQL endpoint. The input to our POST request is the mutation containing the information needed to display our push notification. The countryCode property is the value from the <select>  dropdown. For testing purposes, the value of the user property is going to be your current userID that you get by calling the getUserId() method for the device you are using to view this web application. In other words, you will send a push notification to your device that has registered with OneSignal. Keep in mind that OneSignal allows sending mass push notifications to all the subscribed users of a website.

Allow Web Push Notifications

Run the app and visit your website. You should see the following prompt appear after your chosen time delay interval:

Click on the blue Allow button to enable push notifications on your browser.

If you want to get started by sending a message or two manually, check out this awesome docs page for help.

Step 4: Add Country Code Data to Your Application

Now it's time to fill that <select> with actual data! If you go back into the homepage of your TakeShape project, right above the Connect Service button I clicked earlier, you should see OneSignal connected!

You can click on the Countries service to get back to the form you originally filled out to add the service in the first place. At the very bottom of that form, there's a button that will let you select queries from the GraphQL service to duplicate inside TakeShape. In the GraphQL service, select the countries query. Doing this will make it so that the countries query from the CountriesAPI is now the Countries_countries query in your API mesh, which you can then use to get a list of countries. That's a little confusing to explain in text, but it's actually the most intuitive way to go about this because this setup will let you choose what queries should be directly accessible through the API mesh. It also avoids creating any conflicts with query names when you start adding more services because they're all namespaced.

With that out of the way, you can just add this to the JavaScript and load the dropdown with the results:

const loadCountries = async () => {
const resp = await fetch(
`https://api.takeshape.io/project/${projectID}/v3/graphql`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`
},
body: JSON.stringify({
query: `
query {
Countries_countries {
code
}
}
`
})
}
);
const results = await resp.json();
results.data.Countries_countries.map(x => x.code).forEach(code => {
const option = document.createElement("option");
option.innerText = code;
select.insertAdjacentElement("beforeend", option);
});
};

And that's pretty much it! You can take a look at the GitHub repo for the full code. You can also see the finished product in action.

Let's test it out quick! If you go the page, it should ask you for permission to send push notifications. In the background, that loadCountries function is running, which loads up the dropdown. If you choose one and press the Send Push button like this:

Then this happens:

Success!

Now, you can keep expanding your code to make use of different features of the OneSignal SDK across your web app. To learn more about the Web Push SDK, visit OneSignal's documentation. If you want to check out more of TakeShape's abilities and how it makes working with APIs much easier in the long run, check out the TakeShape's documentation.