Answered

Is there a way to simplify the processing of webhook data?

  • 7 September 2021
  • 9 replies
  • 1154 views

Hi :wave:,

I need to save the results from the TypeForm web hook to a SQL database for my project.

Is there a simple and efficient way to process the data received on the web hook?

I am on PHP8/Symfony5,

  • I want to know if there is a way to customize the results, for example by putting a string key instead of a translated string for the choice type results.
  • If is exist another way than id to identify what answer correspond
  • I don't want to store in the database all possible answer identifiers to link with the right data

Thank you for helping me :)

icon

Best answer by picsoung 8 September 2021, 00:47

View original

9 replies

Userlevel 7
Badge +5

Hi @bandofboats Happy Tuesday! We don’t have customization options for the webhook data at this time, but tagging @picsoung in case they happen to know of any fancy workarounds for this. :grinning:

Userlevel 7
Badge +5

Hey @bandofboats 

We send you a JSON payload to your app.

If you are not familiar on how to receive JSON webhook on your PHP app you can refer to this StackOverflow question.

$data = json_decode(file_get_contents('php://input'));
$answers = $data->form_response->answers;

Each question is identified by both an id and a ref. Similarly for a choice in a mulitple choice, picture choice or dropdown. While you can’t edit the id, you still can edit the ref to make it easier to work with.
Do do so you will go to ⚙️ → For Developers → Block References.
And there you can edit references.
Unfortunately we don’t support yet editing choice reference, you will have to use this tool to do so.

Hope this helps

Thank’s @Liz and @picsoung this gonna help me to identify data :ok_hand:

Happy Wednesday

Userlevel 7
Badge +5

Glad to hear, @bandofboats ! Keep us posted on how this works for you. :grinning:

@picsoung 

Hello Nicolas,
Actually we’re also struggling a lot with webhooks data here.

The question is not in parsing json process itself but in data structure sent to webhooks.

What we’re receiving here inside answers is object like this:

{
"type": "text",
"text": "Lorem ipsum dolor",
"field": {
"id": "p9XOht3JwNXf",
"type": "short_text",
"ref": "a3651332e7fa6c9e"
}
}

Let’s try assume what is the fastest and efficient way to find text `Lorem ipsum dolor` by id or ref to put this value into specific db field.
And the answer will look like “Iterate via all objects and compare id or ref from nested `field` object with target id or ref value”. Then we should iterate through all objects again to find the value for 2nd target field and so on. Iterate through all objects as many times as many fields required to find.

I do not know yet what should I do to fetch selected values for predefined selections but from what we can see here already is developer-not-so-friendly data schema.

Please do something with this or explain how to handle this data schema fast and efficient.

@picsoung

Hello Nicolas,
Actually we’re also struggling a lot with webhooks data here.

The question is not in parsing json process itself but in data structure sent to webhooks.

What we’re receiving here inside answers is object like this:

{
"type": "text",
"text": "Lorem ipsum dolor",
"field": {
"id": "p9XOht3JwNXf",
"type": "short_text",
"ref": "a3651332e7fa6c9e"
}
}

Let’s try assume what is the fastest and efficient way to find text `Lorem ipsum dolor` by id or ref to put this value into specific db field.
And the answer will look like “Iterate via all objects and compare id or ref from nested `field` object with target id or ref value”. Then we should iterate through all objects again to find the value for 2nd target field and so on. Iterate through all objects as many times as many fields required to find.

I do not know yet what should I do to fetch selected values for predefined selections but from what we can see here already is developer-not-so-friendly data schema.

Please do something with this or explain how to handle this data schema fast and efficient.

 

Hello, Questioner from the past

The answer for your question about how to not iterate through all fields every time to find and get required field value sounds like “Iterate through all objects once, compare answer['field']['id'] with required value and try to fit this answer’s value into database field”. This looks like something upside down but at least we haven’t to iterate each time. Still no any way invented to implement direct getters.

@Dcentralab@Liz Im gonna show you how i’ve found a way to be efficient to work with this payload ;) (only api calls to typeform are not efficient but it just need to be fixed on webhook payload)

 

  1. I use the tf-edit tool to custom my ref
  2. The refs values i use is all the properties name in my PHP class (Entity on Symfony)
  3. I use this function to return my entity with all data set inside, after this i just have to flush in my db

    (if you want to copy paste)

    private function processReview(array $answers, ReviewOffice|ReviewVersion $entity): ReviewOffice|ReviewVersion
    {
    // after json decode and get $payload->form_response->answers i use this function
    foreach ($answers as $answer) {
    // that return me a string like $setter => 'setTimeLimitScore'
    $setter = 'set'.ucfirst($answer->field->ref);
    switch ($answer->type) {
    // for each answer's question type case
    case self::CHOICE:
    $entity->{$setter}($answer->choice);
    /* todo: when webhook is fixed (we don't receive ref for this type yet)
    $entity->{$setter}($answer->field->ref); */
    break;
    case self::CHOICES:

    // Use TypeForm api directly to get ref on choices type
    $response = $this->client->request(
    'GET',
    'https://api.typeform.com/forms/'.$this->formId
    );
    $response = json_decode($response->getContent());
    $field = array_values(array_filter($response->fields, fn ($field) => $field->id === $answer->field->id))[0];
    $choices = array_filter($field->properties->choices, fn ($choice) => in_array($choice->label, $answer->choices->labels));
    $choicesRef = array_map(fn ($choice) => $choice->ref, $choices);
    $entity->{$setter}($choicesRef);

    /* todo: when webhook is fixed (we don't receive ref for this type yet)
    $choicesRef = [];
    foreach ($answer->choices as $choice) {
    $choicesRef[] = $choice->ref;
    }
    $entity->{$setter}($choicesRef); */

    break;
    case self::NUMBER:
    $entity->{$setter}($answer->number);
    break;
    case self::TEXT:
    if (self::REVIEW_TEXT == $answer->field->ref) {
    break;
    }
    $entity->{$setter}($answer->text);
    break;
    default:
    throw new BadRequestException('case not supported');
    }
    }

    return $entity;
    }

     

Userlevel 7
Badge +5

Wow, thank you, @bandofboats ! So fancy!

https://media.giphy.com/media/HDNcjt5ELkJSE/giphy.gif?cid=ecf05e475txsk1ha9g9rzx21njai5sfsxx8dw5fpdc9lmj2e&rid=giphy.gif&ct=g

Userlevel 7
Badge +5

@bandofboats @Dcentralab an update you might like below!

 

Reply