Automating Insulin Ordering: Capturing the GP Request (Part 2)
Tags: programming, productivity, automation, processoptimisation
Published: 2024-06-04 08:19:06

In the first part of this series, I outlined the problem of manually ordering my insulin and introduced the idea of automating this process. Now, we will dive into the first step of this automation: figuring out how to send a request to my GP using a cURL command.

## Capturing the Browser Request
To understand how my GP’s website processes the prescription request, I went to their site and filled out the necessary form. Before hitting the send button, I opened my browser's network tab to log all outgoing queries. This step is crucial as it allows us to see the exact request being sent to the server. Before submitting the form, I cleared all the network requests that it had already logged to ensure I would only see the query or queries that are triggered upon the form submission.  Once I'd done that, I filled in the form and checked the queries that appeared.

![Network tab with the relevant network request](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aerfq447cirmpxtvai9s.png)

I then submitted the form and I observed two network requests. I inspected both and saw that the one labeled `Feedback` was the request that actually sent my information to my GP and it contained all the information I had entered. This request is the key to our automation. The server's response was a confirmation message stating that the prescription would be uploaded to my health insurance card within 24 hours.

## Analysing the Request
The requests from the network tab are easily copy-able. You just right click the request, and then copy > copy as X. I copied the request as cURL. 

![How to copy the outgoing network request](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qupuqn9p5yzklcli3wuv.png)

I moved it over to a code editor to analyse it in depth. The request included headers, the payload, and other parameters essential for successful submission. Here's a redacted version of the cURL command derived from the network request:

```bash
curl 'https://www.mygp.com/order-insulin' \
    -H 'accept: application/json, */*;q=0.1' \
    -H 'accept-language: en-GB,en;q=0.5' \
    -H 'cache-control: no-cache' \
    -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundarynE0B7A3bJADDu4sV' \
    -H 'origin: https://www.mygp.com' \
    -H 'pragma: no-cache' \
    -H 'sec-ch-ua-mobile: ?0' \
    -H 'sec-fetch-dest: empty' \
    -H 'sec-fetch-mode: cors' \
    -H 'sec-fetch-site: same-origin' \
    -H 'sec-gpc: 1' \
    -H 'user-agent: MyDevice' \
    --data-raw $'------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="_wpcf7"\r\n\r\n834\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="_wpcf7_version"\r\n\r\n5.9.3\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="_wpcf7_locale"\r\n\r\nde_DE_formal\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="_wpcf7_unit_tag"\r\n\r\nwpcf7-f834-p922-o1\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="_wpcf7_container_post"\r\n\r\n922\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="_wpcf7_posted_data_hash"\r\n\r\n\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="name"\r\n\r\MYNAME\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="insurance-number"\r\n\r\nINSURANCENUMBER\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="phone"\r\n\r\nMYPHONENUMBER\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="email-195"\r\n\r\nMYEMAIL@EMAIL.COM\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="order"\r\n\r\nTHE ORDER INFORMATION GOES HERE\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="acceptance-255"\r\n\r\n1\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV--\r\n'
```

## Breaking Down the cURL Command
Let's break down what happens in this cURL command:

- **curl 'https://www.mygp.com/order-insulin'**: This initiates a POST request to the specified URL.
- **-H 'accept: application/json, */*;q=0.1'**: Specifies that the request can accept JSON responses.
- **-H 'accept-language: en-GB,en;q=0.5'**: Specifies the preferred language for the response.
- **-H 'cache-control: no-cache'**: Ensures that the request bypasses any cached responses.
- **-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundarynE0B7A3bJADDu4sV'**: Sets the content type to multipart/form-data, which is required for file uploads and form submissions.
- **-H 'origin: https://www.mygp.com'**: Specifies the origin of the request.
- **-H 'pragma: no-cache'**: Similar to cache-control, it instructs the server not to cache the request.
- **-H 'sec-ch-ua...'**: These headers provide additional information about the user agent and its platform.
- **--data-raw '...'**: This flag sends the form data in the request body, including my name, insurance number, contact details, and the medication details.

Some of these headers might be superfluous, but I figured it would be best for me to just leave the request as is. That would limit the potential issues with sending it via my terminal later.

## Automating the Request
To automate this process, I created a bash function that uses the cURL command to send the request to my GP's website. This function will be the backbone of our automation script, ensuring that the prescription request is sent automatically. 

I am using oh-my-zsh and I have a file sourced in my .zshrc in which I add custom methods. However, it would work identically if you put the function into .bashrc or .zshrc directly.

Here's the script:

```bash
function order_insulin() {
  insulin_order_response=$(curl 'https://www.mygp.com/order-insulin' \
    -H 'accept: application/json, */*;q=0.1' \
    -H 'accept-language: en-GB,en;q=0.5' \
    -H 'cache-control: no-cache' \
    -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundarynE0B7A3bJADDu4sV' \
    -H 'origin: https://www.mygp.com' \
    -H 'pragma: no-cache' \
    -H 'sec-ch-ua-mobile: ?0' \
    -H 'sec-fetch-dest: empty' \
    -H 'sec-fetch-mode: cors' \
    -H 'sec-fetch-site: same-origin' \
    -H 'sec-gpc: 1' \
    -H 'user-agent: MyDevice' \
    --data-raw $'------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="_wpcf7"\r\n\r\n834\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="_wpcf7_version"\r\n\r\n5.9.3\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="_wpcf7_locale"\r\n\r\nde_DE_formal\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="_wpcf7_unit_tag"\r\n\r\nwpcf7-f834-p922-o1\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="_wpcf7_container_post"\r\n\r\n922\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="_wpcf7_posted_data_hash"\r\n\r\n\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="name"\r\n\r\MYNAME\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="insurance-number"\r\n\r\nINSURANCENUMBER\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="phone"\r\n\r\nMYPHONENUMBER\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="email-195"\r\n\r\nMYEMAIL@EMAIL.COM\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="order"\r\n\r\nTHE ORDER INFORMATION GOES HERE\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV\r\nContent-Disposition: form-data; name="acceptance-255"\r\n\r\n1\r\n------WebKitFormBoundarynE0B7A3bJADDu4sV--\r\n' -s)

  if [ $? -eq 0 ]; then
      # Using jq to parse JSON and extract fields
      insulin_order_status=$(echo $insulin_order_response | jq -r '.status')
      insulin_order_message=$(echo $insulin_order_response | jq -r '.message')

      if [[ $insulin_order_status == "mail_sent" ]]; then
          echo "Ordered: $insulin_order_message"
      else
          echo "Something went wrong, order via the website and update the curl request"
      fi
  else
      echo "Something went wrong, order via the website and update the curl request"
  fi
}
```

## Explanation
- **cURL Command**: The curl command sends a POST request to the GP's website with the necessary headers and form data.
- **Response Handling**: The response is captured in the insulin_order_response variable. We use the `-s` flag to run curl in silent mode, which suppresses progress output.
- **Error Checking**: The script checks if the curl command executed successfully using `$?`. If the command fails, an error message is displayed.
- **Parsing JSON Response**: If the curl command is successful, the script uses `jq` to parse the JSON response and extract the status and message fields.
- **Conditional Logic**: Based on the status field, the script determines if the request was successful (`'mail_sent'`) or if there was an error.

In order to get to the information I needed to make the `if`-statement work and to figure out the required information, I went back to my network tab. In the response there, the returned JSON looked as follows: 

```json
{
    "contact_form_id": 834,
    "status": "mail_sent",
    "message": "Prescription requested successfully.",
    "posted_data_hash": "2905f838031fbd4619d89658928fbb2a",
    "into": "#wpcf7-f834-p922-o1",
    "invalid_fields": []
}
```

You can clearly see the status and the reply there. Since I am only interested in the success state, I can just check for `mail_sent`. If the mail wouldn't be sent, then I can log an error. Since I assume that the cURL request will only fail if they change their API, I added the message:

> order via the website and update the curl request.

Lastly, I started a new terminal window and tried my new script. Indeed, I saw `Ordered: Prescription requested successfully.` in my terminal. Does that mean I requested two prescriptions in a short time? Yes it does. I hope nobody comes knocking for that. 

## What’s Next?
In the next part of this series, we will focus on automating the email to the pharmacy. This involves setting up an email client within our script to send the pre-order request automatically.

Stay tuned as we continue to streamline the insulin ordering process, one step at a time.

[Read Part 3](https://dev.to/goudekettingrm/automating-insulin-ordering-creating-the-wrapping-function-part-3-517k)

Thank you for following along! If you have any questions or suggestions, feel free to leave a comment below. Don't forget to share this post with anyone who might find it useful.