Persisting Part of a Third-Party API Response

Last edit: Jun 05, 2019
  • Contributors:
  • Slashek
  • pavelloz
  • lemingos

This guide will help you persist part of a third-party API response by walking you through an example.

Requirements

This is an advanced tutorial. To follow it, you should be familiar with basic platformOS concepts, HTML, GraphQL queries, Liquid, YAML, and the topics in the Get Started section, especially tutorials related to pages, users, and notifications.

Steps

Persisting part of a third-party API response is a seven-step process:

Step 1: Create profile and Property

Create a new user profile called test_profile, and create a Property to store the value from the API, called third_party_api_value:

user_profile_types/default.yml

name: test_profile
properties:
- name: third_party_api_value
  type: string

Step 2: Create test endpoint

Create a test endpoint that simulates a third-party API JSON response:

views/pages/test-endpoint.json.liquid


---
slug: test-endpoint
---
{
  "third_party_api_id": "id-1"
}

Step 3: Create API Call Notification

Create an API Call Notification that should:

  1. send a request to https://<your_domain>.com/test-endpoint.json
  2. store the value from the response in a property

Replace example.com with your domain:

notifications/api_call_notifications/send_request.liquid


---
name: send_request
to: http://example.com/test-endpoint.json
enabled: true
format: http
trigger_condition: true
request_type: GET
callback: "{%- assign response_json = response.body | to_hash -%}{% graphql res = 'persist_in_custom_attribute', user_id: form.id, third_party_api_id: response_json.third_party_api_id %}"
headers: '{
  "Content-Type": "application/json"
}'
---
{
  "id": "{{ form.id }}"
}

Step 4: Create GraphQL mutation

In the callback, the graphql tag invokes a GraphQL mutation with the provided arguments. The query accepts two arguments: the user_id, the ID of the user we want to update, and the third_party_api_id which is the value we want to store. The content of the GraphQL mutation file:

graph_queries/persist_in_custom_attribute.graphql

mutation persist_in_custom_attribute($user_id: ID!, $third_party_api_id: String!) {
  user_update(
    id: $user_id,
    user: {
      profiles: [
        {
          name: "test_profile"
          values: { properties: [{ name: "third_party_api_value", value: $third_party_api_id }] }
        }
      ]
    }
    form_configuration_name: "callback_persist_in_custom_attribute"
  ) {
    id
  }
}

The mutation passes the arguments to a form called callback_persist_in_custom_attribute. Make sure that its configuration includes the fields you want to persist. Please note: by re-using an idea of form_configuration here, you can easily send additional emails, SMSes, or even other API calls. All you want to do in this example though is to store the value, so you don't have to add any extra notifications.

form_configurations/callback_persist_in_custom_attribute.liquid

---
name: callback_persist_in_custom_attribute
async_callback_actions:
resource: User
fields:
  profiles:
    test_profile:
      properties:
        third_party_api_value:
---

Step 5: Create page to embed form

Once you have an API Call Notification defined, you should associate it with a form to trigger it. Create a page for embedding this form.

views/pages/test-form.liquid

---
slug: test-form
---

{% include_form 'test_form', object_id: current_user.id, object_class: 'User' %}

Step 6: Create and embed form

Create the form and associate it with the API Call Notification. It can be a signup form, that creates the test_profile in the background:

form_configurations/test-form.liquid

---
name: test_form
resource: User
fields:
  email:
  password:
  profiles:
    test_profile:
      enabled:
redirect_to: /test-result
api_call_notifications:
  - send_request
---

{% form url: "/api/users/{{ current_user.id }}" %}
  <label for="email">Email</label>
  <input name="{{ form_builder.fields.email.name }}" value="{{ form_builder.fields.email.value}}" id="email" type="email">

  <label for="password">Password</label>
  <input name="{{ form_builder.fields.password.name }}" id="password" type="password">
  {% if form_builder.errors.password %}
    <p>{{ form_builder.errors.password }}</p>
  {% endif %}

  <input name="{{ form_builder.fields.profiles.test_profile.enabled.name }}" value="1" type="hidden">

  <button>Save</button>
{% endform %}

Once the user fills the signup form without validation errors, the system will proceed to trigger the API Call Notification. If it is successful, it will trigger the callback, in which you will have access to the server's response via the response variable. You will be able to access various things, like response.code, and the most important, response.body. The callback will run the GraphQL mutation, which will use form_configuration to persist the data.

Step 7: Display results

In the test_form you have set up a redirection to /test-result, so create this page and make it display the third_party_api_value:

views/pages/test-result.liquid

---
slug: test-result
---

{% graphql graph_current_user = 'get_current_user_third_party_api_value'  %}
Third Party Api Value: for {{ graph_current_user.current_user.email }}: {{ graph_current_user.current_user.test_profile.third_party_api_value }}

which uses the following GraphQL query:

graph_queries/get_current_user_third_party_api_value.graphql

query get_current_user_third_party_api_value {
  current_user {
    email
    test_profile: profile(profile_type: "test_profile") {
        third_party_api_value: property(name: "third_party_api_value")
    }
  }
}

You can now go to the /test-form page, provide sign up details, and click the Save button. Initially, you will not see the correct value, because the API call is triggered in the background, outside of the request lifecycle. This is important to not rely on a third-party API's availability. However, when you refresh after a couple of seconds, you will see that the value has been populated.

Questions?

We are always happy to help with any questions you may have.