Alex Levashov – eCommerce Consultant (Melbourne, Australia)

R plus Magento 2 REST API revisited: part 1- authentication and universal search

R plus Magento 2 REST API revisited: part 1- authentication and universal search

R plus Magento 2 REST API revisited: part 1- authentication and universal search

I wrote a post about getting Magento 2 data to R using REST API last year. Now I provide more examples of use and a wrapper over API that you can re-use to get data from Magento 2 to R in a bit more convenient way.

Prerequisites

Magento 2

I assume you have admin access to Magento 2 store where you want to pull data from. You’ll need to create API user with access to the resources you plan to query.  You need to write down:

  • Store URL (top level, where Magento app sits)
  • API user username
  • API user password

R

We used the next R packages:

  • httr – essential for work with API
  • jsonlite -to work with JSON data
  • dplyr – for some data manipulation in samples later (not in this post). Not essential one, if you prefer to use something else, but nice to have

Authentication

For ease of reuse let’s define a function that will get a token. We have to pass that token with most API requests.

getm2authtoken <- function (url, username, password){
myquery = list (username=username, password=password)
url <- paste0(urlbase, "index.php/rest/V1/integration/admin/token")
myqueryj = toJSON(myquery, pretty = TRUE, auto_unbox = TRUE)
req <- POST(url, add_headers ("Content-Type" = "application/json"), body = myquery, encode = "json")
token <-rawToChar(req$content[2:33])
auth <- paste0("Bearer ", token)
return (auth)
}

Define your Magento API connection

urlbase <- "https://yourdomain.com.au/"
username <- "user"
password <- "password"

Now we can call the function and save the token for future use

auth <- getm2authtoken (urlbase, username, password)

If you print auth you should get something like [1] "Bearer 9r8ish02l5zz372ivp7rt8tzndd123yk" as a value if it works correctly.

Universal search

Now define function that does universal search in Magento 2 data.

getm2objects <- function(urlbase, endpoint, query, auth){
url <- paste0(urlbase, endpoint, "?")
request <- GET(url, add_headers ("Content-Type" = "application/json", "Authorization" = auth), query = query)
object <- content(request, as ="parsed")
return (object)
}

The function has the next parameters:

  • urlbase – base URL of your Magento store, similar with you used for authentication function. Typically your domain. Important to have trailing slash!
  • endpoint – specific Magento 2 REST API endpoint.  Skip first slash in the endpoint. You may find some endpoints in the examples below, all of them available in Magento  2 Documentation
  • query – your search query. It is list of triplets and pairs of parameters, which is explained below and in the examples
  • auth is authentication token we’ve already got and saved

Query

The simplest case of query is a list with 3 name-value pairs:

myquery <- list("searchCriteria[filter_groups][0][filters][0][field]"="created_at",
"searchCriteria[filter_groups][0][filters][0][value]"="2017-01-01 00:00:00",
"searchCriteria[filter_groups][0][filters][0][condition_type]"="gt")

The query above look for all data created later than specified date (01-01-2017).

Third pair is condition, where ‘gt’ means ‘greater than’

You may find all possible conditions and sample use in general (not R specific) in Magento Documentation.

Examples of using universal search

Simple search – invoices issued after given date/time

Define parameters, here and later we assume that authentication is stored in ‘auth’ variable.

endpoint <- "rest/V1/invoices"
# query
myquery <- list("searchCriteria[filter_groups][0][filters][0][field]"="created_at",
"searchCriteria[filter_groups][0][filters][0][value]"="2017-01-01 00:00:00",
"searchCriteria[filter_groups][0][filters][0][condition_type]"="gt")

Calling function

invoices <- getm2objects(urlbase = urlbase, endpoint = endpoint, query = myquery, auth=auth)

The resulting object is a complex list with many levels of nesting that stores data from many Magento 2 database tables.

Magento Invoices as R list screenshot

It looks complex enought and there is no surprise. But having all this data in one object is one of the reason to use API over direct query to SQL. If you have tried the latter you know that it may be extremely complex because Magento has hundreds of tables with complex relationships.

Search with OR logic and wildcard use in products

In this example we’ll use 2 search conditions – look for products those name include either ‘Dress’ or ‘Throw’

endpoint <- "rest/V1/products"
myquery <- list("searchCriteria[filter_groups][0][filters][0][field]"="name",
"searchCriteria[filter_groups][0][filters][0][value]"="%Dress%",
"searchCriteria[filter_groups][0][filters][0][condition_type]"="like",
"searchCriteria[filter_groups][0][filters][1][field]"="name",
"searchCriteria[filter_groups][0][filters][1][value]"="%Throw%",
"searchCriteria[filter_groups][0][filters][1][condition_type]"="like")

Note that we have 2 triplets of criteria, one per product name and the second has 1 in search criteria group.

Also percentage char used to indicate that there may be any number of characters before and after both terms. That syntax comes from SQL and other SQL wildcards can be used

Now call the function

products <- getm2objects(urlbase = urlbase, endpoint = endpoint, query = myquery, auth=auth)

The resulting list contains all the products with either “Dress” or “Throw” in name. Register ignored.

To quickly check how many results in the list use the next command

products[["total_count"]]

It returns number of search results founds.

Logical AND and OR search with invoices

Let’s get invoices for certain period of time and for specific grand total amounts above OR below certain thresholds

# get invoices for 2013 year and for any time with grand total under $100 OR over $1000
endpoint <- "rest/V1/invoices"
myquery <- list("searchCriteria[filter_groups][0][filters][0][field]"="created_at",
"searchCriteria[filter_groups][0][filters][0][value]"="2013-01-01 00:00:00",
"searchCriteria[filter_groups][0][filters][0][condition_type]"="gt",
"searchCriteria[filter_groups][1][filters][0][field]"="created_at",
"searchCriteria[filter_groups][1][filters][0][value]"="2014-01-01 00:00:00",
"searchCriteria[filter_groups][1][filters][0][condition_type]"="lt",
"searchCriteria[filter_groups][2][filters][0][field]"="base_grand_total",
"searchCriteria[filter_groups][2][filters][0][value]"="1000",
"searchCriteria[filter_groups][2][filters][0][condition_type]"="gt",
"searchCriteria[filter_groups][2][filters][1][field]"="base_grand_total",
"searchCriteria[filter_groups][2][filters][1][value]"="100",
"searchCriteria[filter_groups][2][filters][1][condition_type]"="lt")

Note that here we have 3 filter groups that stands for AND condition. The last group has 2 conditions (filters) that are connected as OR.
Calling the function
invoices2 <- getm2objects(urlbase = urlbase, endpoint = endpoint, query = myquery, auth=auth)
Let’s also check how big is our invoice in average

object.size(invoices2)/invoices2[["total_count"]]

In my case one invoice in average was over 17 KB. It isn’t a problem for limited data, but if you have massive number of objects it may end up not good.

Hence a word of caution!

Be mindful with your API requests, especially if you query production Magento 2 instance. Getting too wild may slow it down significantly and you can run out of memory on your local machine.

That is it for now. In the next post or two, I’ll write about getting filtered results. It is useful if you don’t need all the data, only part of it and don’t want to consume more than necessary resources, which may be important in many situations. Stay tuned!