Header Bar

Using The Etsy API - An Absolute Beginner's Tutorial

By: Nick Antonaccio
Updated: 10-7-2012

Contents:

1. What is the Etsy API?
2. How Do I Start?
3. Basic API Programming
3.1 Retrieving Listing Data
3.2 Variables
3.3 A Note About Code Examples in this Tutorial
3.4 Looping Through Data Lists
3.5 Concatenating Text
3.6 Performing Conditional Operations and Searching Text
3.7 Interacting with the User
3.8 Lists of Data
3.9 Foreach Loops
4. Using The Rest of the Etsy API - Unlocking All Doors to Your Etsy Account
4.1 Bringing it all Together into a Real World Example
5. GUI Interfaces (windows, forms, buttons, fields, etc.)
6. A Bit More Depth - Creating REBOL Functions
7. A Complete, Fully Functional, GUI Application Using the Etsy API
8. Creating a CGI Version of Your App
9. Summary

1. What is the Etsy API?

Etsy.com provides a powerful web site interface that allows users to manage account data. When you sign up with Etsy, you can log in and use forms on the pages of your account to create, delete, and edit listings, alter account settings and data, and adjust various Etsy account features. As you become more prolific at entering listings and adjusting your shop settings, you may discover that particular usage routines are especially time consuming, or perhaps even impossible to accomplish, using only the tools available in the account pages of Etsy.com.

A number of 3rd party web sites have popped up to add features which help manage your listing data and other Etsy account attributes. Such web sites are possible because Etsy has created a "Developer API". The API is a collection of functions available to web and network apps that provide completely customizable control over the features and data in Etsy accounts.

The Etsy API is in fact available not just to big 3rd party web sites, but to every Etsy shop owner. If you don't mind writing a little code, you can create your very own app to help streamline the management of your entire Etsy account. The Etsy API provides functions to create, delete, and otherwise edit listings, upload images, alter shop appearance, manage shipping and payment templates, and otherwise make changes to your entire Etsy account. You can build your own custom app that allows you to make changes to your data, and interact with your Etsy account exactly the way you want, even if Etsy doesn't enable those things to be accomplished the way you want, using the default web interface.

If you've ever wished, for example, that you could search and replace text in selected item titles or descriptions, selectively update prices (perhaps making percentage changes), use logical comparisons or content evaluations to adjust only listings with matching criteria, make batch updates to any or all your selected items, quickly add or remove sale texts to any or all of your items, make batch edits to the look of your shop, etc., then you've wished for some of the functionality available in the Etsy API. Chances are, if you become a busy Etsy user, you'll wish that you could change the way certain parts of the Etsy account interface operate. Well, the Etsy developer's API allows you to do just that. With it, you can create your very own private interface, entirely from scratch, so that you can interact with your Etsy account data in exactly the way you want, and in just about any way you can imagine.

The Etsy API can be used from any programming language which allows data to be sent over the Internet via the standard GET and POST protocols. The Etsy API uses commands formatted as simple URI strings (ie., they look like standard http://openapi.etsy.com/v2/... URLs). Security is managed using the standard OAuth protocol, with some proprietary extensions.

If you're just learning to write code, the Etsy API can impose a steep learning curve, especially if you try to program everything from scratch. Luckily, starting from scratch is not necessary. There are modules available to simplify Etsy API coding in popular languages such as Python, Ruby, Perl, and others. Such modules hide all the complex details of interacting with OAuth security measures, composing complex function call strings, etc. Just import your Etsy module, and start calling Etsy functions to make changes to your account.

In order to make the Etsy API even simpler to use, this tutorial explains coding with the REBOL Etsy module by Chris Ross-Gill (http://reb4.me/r/etsy.r). REBOL is perhaps the simplest of all the general purpose programming languages to learn. Even absolute beginners can start using it to create useful apps, including programs with GUI interfaces (windows with buttons, fields, and other widget controls), within a day. Teaching REBOL fully is beyond the scope of this tutorial, but it's very easy to learn. You can understand this entire tutorial even if you've never written a line of code before. See http://re-bol.com to learn more about how to write REBOL code. Experienced coders in any language will be able to learn enough from this tutorial to understand how to use the Etsy API. Only the most basic programming concepts are required to get started.

2. How Do I Start?

To use the Etsy API, you must have an account set up with Etsy and a shop established to sell products. Once you've done that, go to http://www.etsy.com/developers, log in with your username and password, and click "Create a New App". Fill in the form, and then click "Read Terms and Create App". Read, understand, and agree to the legalese.

Once your app is created, save the provided Keystring and Shared Secret, ie., something like:

Keystring:         "4asdf1isdfw4sdfuoa3oimz"
Shared Secret:     "owuk291oiw"

Now download the REBOL interpreter from http://www.rebol.com/download-view.html. Run it as administrator (if you're on Windows), and click "console" (you can uncheck the "Open Desktop on Startup" option in the User settings, so that the REBOL console opens immediately every time it starts). Type the following into the console, to run REBOL's built-in text editor, and to create a new program file:

editor %./myetsyscript.r

Copy and paste the following code into the editor:

REBOL [title: "Etsy"]
do/args http://reb4.me/r/etsy.r context [
    Consumer-Key: #<your-key>
    Consumer-Secret: #<your-secret>
    User-Store: %etsyusers.txt
    Scope: [listings_w listings_r listings_d]
    Sandbox: true
]
etsy/as "<your-user-name>"

Be sure to edit the key, secret, and username so that everything enclosed between angle brackets is replaced with your account information. You will edit all the rest of the above settings later, but for now, click the [F5] key in the REBOL editor program, and the above code will save and run.

Your web browser will open to the Etsy.com web site, which displays a string to copy and paste back into the running REBOL console. Type it into the running REBOL program, and press enter. You'll only need to do this the very first time the program runs, or if you change your key and secret by creating a new app.

What you've just done is set up "OAuth" authorization credentials. The REBOL Etsy module, imported from http://reb4.me/r/etsy.r in the second line of the code above, handles the entire OAuth process. You don't need to know any more about how OAuth works, or how to use it. Your credentials are saved on your hard drive in the "User-Store" location specified in the 5th line of the code above (in the file "etsyusers.txt", by default).

3. Basic API Programming

3.1 Retrieving Listing Data

Now add the following code to our existing program in the REBOL editor (if you've closed the editor just type "editor %./myetsyscript.r" again into the REBOL console). Press the [F5] key to save and run the changed script:

REBOL [title: "Etsy"]
do/args http://reb4.me/r/etsy.r context [
    Consumer-Key: #<your-key>
    Consumer-Secret: #<your-secret>
    User-Store: %etsyusers.txt
    Scope: [listings_w listings_r listings_d]
    Sandbox: true
]
etsy/as "<your-user-name>"
editor etsy/listings []

This line will run the "listings" function from the imported REBOL Etsy module, and display the results in a new instance of the editor. You don't have to know or understand anything else about the Etsy API to use that REBOL listing function. You can print the listing data to the REBOL console, using the "probe" function:

probe etsy/listings []

You can obtain just the meat of the data from the listing function, by getting only the "results" portion of the listing object, using the code below:

editor get in (etsy/listings []) 'results

You may be wondering at this point why none of the items in your account are showing up in the returned listings. When you first create a new app using the API, Etsy requires it to be tested in the "Sandbox". This is a data area which operates just like the production API that has access to all your shop data and listings, but it doesn't contain any real user data. This allows you to enter and run API functions, fix bugs, and test your code before using the production data in your account (where you could make damaging mistakes using untested code). When you have completed a tested and working app using the API, you must submit it to the Etsy development team for approval. Once your app's OAuth keys have been approved, you can change the "Sandbox: true" setting in the code example above to "Sandbox: false", and all of your production data - listings, shop settings, etc. - will be affected by your code. Be absolutely sure that your code works 100% correctly before working with production data. Your shop data will be affected just as if you had adjusted the data manually using the Etsy web site interface. If you create new listings, all the normal Etsy fees and charges apply. Changes that you make using the API appear just as quickly in your shop, as if you had made the changes by hand. You're playing with fire using the Etsy API - it's extremely powerful.

Be sure that you understand exactly what you are doing with your code, before you make any updates to production settings in your actual account. The author of this text, and the Etsy Developer team, will not be held responsible for any changes you make to your data, or damages that result from, using the Etsy API.

3.2 Variables

Variables are labels used to represent changeable data. Variables are used in every programming language. In REBOL, variables are created using the colon symbol (":"):

x: "Etsy is great!"
print x

If you change the data assigned to the variable label, the new data is used every time the variable label is encountered:

x: "Etsy is fantastic!"
print x

In the code below, the label "x" is assigned to Etsy listing results. You can then just use "x" to refer to the listing data, any time you need it. The following code prints the listing results 3 times:

REBOL [title: "Etsy"]
do/args http://reb4.me/r/etsy.r context [
    Consumer-Key: #<your-key>
    Consumer-Secret: #<your-secret>
    User-Store: %etsyusers.txt
    Scope: [listings_w listings_r listings_d]
    Sandbox: true
]
etsy/as "<your-user-name>"
x: get in (etsy/listings []) 'results
probe x
probe x
probe x

If you want to refresh the contents of your listing data, just redefine the value assigned to x:

REBOL [title: "Etsy"]
do/args http://reb4.me/r/etsy.r context [
    Consumer-Key: #<your-key>
    Consumer-Secret: #<your-secret>
    User-Store: %etsyusers.txt
    Scope: [listings_w listings_r listings_d]
    Sandbox: true
]
etsy/as "<your-user-name>"
x: get in (etsy/listings []) 'results
probe x
x: get in (etsy/listings []) 'results
probe x

3.3 A Note About Code Examples in this Tutorial

From this point on, assume that the following Etsy header code is included in all the examples in this tutorial:

REBOL [title: "Etsy"]
do/args http://reb4.me/r/etsy.r context [
    Consumer-Key: #<your-key>
    Consumer-Secret: #<your-secret>
    User-Store: %etsyusers.txt
    Scope: [listings_w listings_r listings_d]
    Sandbox: true
]
etsy/as "<your-user-name>"

For example, the code in the previous section will simply be written as:

x: get in (etsy/listings []) 'results
probe x
x: get in (etsy/listings []) 'results
probe x

Remember to press the [F5] key in the REBOL editor any time you want to run your code.

3.4 Looping Through Data Lists

Loops are code structures that allow you to run through lists of data, and perform some action(s) with/to each element in the list. "For" loops allow you to count from any number, to any other number, jumping by a given step number, and using an arbitrary variable label to refer to the current count number. The following loop counts from 1 to 10, and prints each consecutive number, represented by the variable "i":

for i 1 10 1 [print i]

This code counts from 100 to 1, stepping backward by increments of -5:

for i 100 1 -5 [print i]

The following code runs a "for" loop on Etsy listing results. The "for" loop counts from 1 to the number of listing results found, and the listing_id from each result is printed to the console, for each of those consecutive count numbers. The variable "i" is used to hold the incremented count number, each time through the loop, so the first time through the loop "x/:i" evaluates to "x/1" (the first item in the results data). "x/2" picks out the second item in the results, and so on, until the count reaches the total number of items in the listing result data (remember to add the Etsy header code to the beginning of the program):

x: get in (etsy/listings []) 'results 
for i 1 (length? x) 1 [      
    print (get in x/:i 'listing_id)
]

To print out just the listing ID, title, description and state of each item, try the following code:

x: get in (etsy/listings []) 'results                  
for i 1 (length? x) 1 [      
    print (get in x/:i 'listing_id)
    print (get in x/:i 'description)
    print (get in x/:i 'title)
    print (get in x/:i 'state)
]

3.5 Concatenating Text

REBOL uses the "rejoin" function to concatenate, or add together, pieces of text. The following example simply concatenates some static text with pieces of listing results data, assigns that concatenated data to the variable label "y", and then prints the entire concatenated string, each time through the loop:

x: get in (etsy/listings []) 'results                  
for i 1 (length? x) 1 [      
    y: rejoin [
        "Listing #" (get in x/:i 'listing_id) " is:  " 
        (get in x/:i 'title) "."
        "Description:  " newline newline (get in x/:i 'description)
        newline newline "State:  " (get in x/:i 'state)
    ]
    print y
]

3.6 Performing Conditional Operations and Searching Text

You can perform "conditional operations" based on whether a given code expression evaluates to true or false, using the "if" structure:

if (this is true) [do this]

Any multiple bits of code in a REBOL code block can be put on the same line, or separated onto a group of indented lines. For example, the following code:

if (this is true) [do this then this then this and finally do this]

Is easier to read as:

if (this is true) [
    do this
    then this
    then this
    and finally do this
]

Here's a real Etsy API example demonstrating the "if" structure, and also the "find" function. It only prints item listings if the description contains the text "pretty". Notice that the parentheses in the following code have been removed. Parens are used to help separate expressions visually, but they're not required:

x: get in etsy/listings [] 'results                  
for i 1 length? x 1 [ 
    y: get in x/:i 'description    
    if find y "pretty" [ 
        print get in x/:i 'listing_id
        print get in x/:i 'description
        print get in x/:i 'title
        print get in x/:i 'state
    ]
]

The "either" structure is used to perform one set of actions if your test expression evaluates to true, and another set of actions for false:

either (condition) [
    do this if condition is true
][
    do this if condition is false
]

Here's a real Etsy API code example using the either structure and a text search:

x: get in etsy/listings [] 'results                  
for i 1 length? x 1 [ 
    y: get in x/:i 'description    
    either (find y "pretty") [ 
        print get in x/:i 'listing_id
        print get in x/:i 'description
        print get in x/:i 'title
        print get in x/:i 'state
    ] [
        print rejoin ["NOT found in: " (get in x/:i 'title)]
    ]
]

3.7 Interacting with the User

In REBOL, the "ask" function allows you to get text input from a user. The input data can be assigned to a variable label:

name: ask "Your name:  "
print rejoin ["Hi " name "!"]

The following function assigns the variable label "search-text" to text entered by a user, and then searches for that text in each listing description. Only if the search text is found in any of the consecutive item descriptions, is each of the listing infos printed:

search-text: ask "Search text:  "
x: get in etsy/listings [] 'results                  
for i 1 length? x 1 [ 
    current-text: get in x/:i 'description    
    if find current-text search-text [ 
        print get in x/:i 'listing_id
        print get in x/:i 'description
        print get in x/:i 'title
        print get in x/:i 'state
    ]
]

3.8 Lists of Data

You can save a list of data items into a REBOL "series", also called a "block". REBOL data blocks are enclosed in square brackets. To create a new block, just assign an unused variable label to an empty block:

my-block: []

Use the "append" function to add data to a block:

append my-block "bike"
append my-block "car"
probe my-block

The following code creates an empty block labeled "found", and then adds data only from listings which contain the text "SALE!", to that block:

found: copy []
search-text: "SALE!"
x: get in (etsy/listings []) 'results                  
for i 1 (length? x) 1 [      
    if find (get in x/:i 'description) search-text [ 
        append found (get in x/:i 'listing_id)
        append found (get in x/:i 'description)
        append found (get in x/:i 'title)
        append found (get in x/:i 'state)
    ]
]
print found

You can also used the "append" function to concatenate lists of data into text strings. In REBOL, large multi-line strings of text are enclosed in curly brackets ("{}"):

found-text: copy {}
x: get in etsy/listings [] 'results                  
for i 1 length? x 1 [      
    if find get in x/:i 'description "q" [ 
        append found-text rejoin [
            {"} search-text/text {" found in:  } 
            (get in x/:i 'title) newline
        ] 
    ]
]
print found-text

The "append" function adds data to the end of existing blocks or strings. To append data to the beginning of a block of data or to the beginning of a text string, use "insert head". The following code will build the string in reverse order:

found-text: copy {}
x: get in etsy/listings [] 'results                  
for i 1 length? x 1 [      
    if find get in x/:i 'description "q" [ 
        insert head found-text rejoin [
            {"} search-text/text {" found in:  } 
            (get in x/:i 'title) newline
        ] 
    ]
]
print found-text

You can also use the "reverse" function to reverse the items in a block:

found: copy []
search-text: "SALE!"
x: get in (etsy/listings []) 'results                  
for i 1 (length? x) 1 [      
    if find (get in x/:i 'description) search-text [ 
        append found (get in x/:i 'listing_id)
        append found (get in x/:i 'description)
        append found (get in x/:i 'title)
        append found (get in x/:i 'state)
    ]
]
print reverse found

The "sort" function will sort the items alphabetically:

found: copy []
search-text: "SALE!"
x: get in (etsy/listings []) 'results                  
for i 1 (length? x) 1 [      
    if find (get in x/:i 'description) search-text [ 
        append found (get in x/:i 'listing_id)
        append found (get in x/:i 'description)
        append found (get in x/:i 'title)
        append found (get in x/:i 'state)
    ]
]
print sort found

3.9 Foreach Loops

REBOL allows you to loop through a block of data and perform some action to/with each item, assigning an arbitrary variable label to each item in the list, during each consecutive iteration through the loop:

amounts: [23.44 43.11 88.35 23.52 91.37]
foreach amount amounts [print amount]

You can also perform actions upon consecutive groups of data items in a list:

sales: [
    23.44 4-feb-2012 "ring 141"
    43.11 3-jan-2012 "ring 47"
    88.35 3-jan-2012 "bracelet 93"
    23.52 3-jan-2012 "pendant 20"
    91.37 3-jan-2012 "ring 203"
]
foreach [amount date title] sales [
    print rejoin ["Title: " title ", Amount: $" amount ", Date: " date]
]

You can replace text in data items using the "replace" function:

sales: [
    23.44 4-feb-2012 "ring 141"
    43.11 3-jan-2012 "ring 47"
    88.35 3-jan-2012 "bracelet 93"
    23.52 3-jan-2012 "pendant 20"
    91.37 3-jan-2012 "ring 203"
]
foreach [amount date title] sales [
    if find title "ring" [replace title "ring" "band"]
]
probe sales

Here's an example using the Etsy API that loops through a block of searched/found data and replaces text in the results:

search-text: "pretty"
replace-text: "gorgeous"
found: copy []
x: get in (etsy/listings []) 'results                  
for i 1 (length? x) 1 [
    if find (get in x/:i 'description) search-text [ 
        print rejoin [
            search-text { found in:  } 
            (get in x/:i 'title) newline
        ] 
        append found (get in x/:i 'listing_id)
        append found (get in x/:i 'description)
        append found (get in x/:i 'title)
        append found (get in x/:i 'state)
    ]
]
foreach [lstngid dscrptn titl state] found [
    dscrptn: replace/all dscrptn search-text replace-text
]
probe found

4. Using The Rest of the Etsy API - Unlocking All Doors to Your Etsy Account

So far, the only part of the Etsy API that you've used is the "listings []" function in the REBOL Etsy module. The Etsy API contains hundreds of other functions (also called "methods") that allow you to manipulate just about every data item in your Etsy account. Go to http://www.etsy.com/developers/documentation/reference/listing now to see a complete reference for the Etsy API "Listing" functions. The API reference on that page contains links to every other function in the Etsy API. Each function in the API is fully explained, with a complete description about how to format each command, the syntax required, the input data required, the data output provided, etc.

At the page above, take a close look at the "getListing" function. Notice that it uses the "GET" method, is found at the "/listings/:listing_id" URI, and requires a "listing_id" parameter. To call that function using the REBOL Etsy module, use the following format:

etsy/api-call/with get %listings/3923 none

Printing the results is simple. You can use, for example, either the probe or the editor functions:

probe etsy/api-call/with get %listings/3923 none
editor etsy/api-call/with get %listings/3923 none

The above example retrieves and prints the listing information for a fictitious item 3923. In your own code, be sure to use a listing_id for a real item in your account (remember, if you're using the test sandbox, your real item listing will not be available until your app is approved by Etsy). Remember, you can retrieve information, including listing IDs using the code you've seen earlier in this tutorial:

x: get in etsy/listings [] 'results
for i 1 length? x 1 [
    print get in x/:i 'listing_id
]

Now take a close look at the "updateListing" function in the Etsy API reference (on the same web page above). Notice that the method is "PUT", the URI is the same "/listings/:listing_id", and there are a variety of optional parameters. To update the Title parameter of item 3923, for example, use the following code:

etsy/api-call/with put %listings/3923 [title: "New title"]

To update the Title and Description parameters of item 2945, use the following code:

etsy/api-call/with put %listings/2945 [
    title: "New title" description: "New description..."
]

Now look at the "createListing" function in the Etsy API reference. Notice that it uses the "POST" method and that the URI is simply "/listings". Notice the parameters that are required, and all the parameters that can be optionally specified. With all that in mind, here's a code example that can be used to create a new listing using the REBOL Etsy module:

probe etsy/api-call/with post %/listings [
    quantity: 1 
    title: "An Item" 
    description: "A Description" 
    price: "12.34" 
    category_id: "69150467" 
    who_made: "i_did"
    is_supply: "1" 
    when_made: "2010_2012" 
    shipping_template_id: "330"
]

Using just the Etsy API functions above, along with loops, the REBOL "find" function, and other basic coding techniques you've seen so far, an entire world of possibility opens up to search, sort, edit, and otherwise manipulate data in your Etsy account. You simply need to become familiar with the format of Etsy's API functions. Browse the API to see which functions are available. You can work with listing data, shop settings, payment and shipping templates, billing data, feedback data, forum posts, user settings, etc. They can all be accessed using the same simple REBOL code format. Just make note of the method, URI, and parameters required, and convert to the REBOL format, as in the examples above. Here are a few more examples to clarify how it works:

probe etsy/api-call get %/users/12345678/shops none
probe etsy/api-call get %/shops/1234567/listings/active none
probe etsy/api-call/with post %/payments/templates [
    allow_paypal: "1" 
    paypal_email: "name@site.com"
]
probe etsy/api-call/with post %shipping/templates [
    title: "Home"
    origin_country_id: "209"
    primary_cost: "10" 
    secondary_cost: "5"
]
probe etsy/api-call/with put rejoin [%listings/ x/1/listing_id] [
    title: "Second Item"
]

Notice that you can rejoin text and use variables to form function calls.

4.1 Bringing it all Together into a Real World Example

The following code is a practical "real world" Etsy API example which provides search/replace functionality. The first "for" loop creates a block of items in which text specified by a user is found within listing descriptions. Then, the foreach loop replaces the search text with a specified replace text:

search-text: ask "Search text:  "
replace-text: ask "Replace text:  "
found: copy []
x: get in (etsy/listings []) 'results                  
for i 1 (length? x) 1 [
    if find (get in x/:i 'description) search-text [ 
        print rejoin [
            search-text { found in:  } 
            (get in x/:i 'title) newline
        ] 
        append found (get in x/:i 'listing_id)
        append found (get in x/:i 'description)
        append found (get in x/:i 'title)
        append found (get in x/:i 'state)
    ]
]
foreach [lstngid dscrptn titl state] found [
    either state <> "active" [
        print rejoin [titl { was NOT replaced (listing inactive)^/}]
    ][
        etsy/api-call/with put rejoin [
            %listings/ lstngid
        ] [
            description: replace/all dscrptn search-text replace-text
        ]
        print copy rejoin [titl {^/}]
    ]
]
alert "Done"

5. GUI Interfaces (windows, forms, buttons, fields, etc.)

So far, all the code you've seen has run directly in the REBOL console. You've printed data results, used the "ask" function to request text from the user, etc. In most real world programs, users interact with a graphical user interface or "GUI". REBOL makes GUI creation super simple. In fact, there is no other programming language in which you can create interactive windows with buttons, fields, text areas, etc., so easily.

To create a window in REBOL, use the "view layout" functions. You can specify a window size if desired:

view layout [size 600x400]

To add "widgets", just type the name(s) of the widget types you need. REBOL will automatically size the window for you (note that text after a semicolon is called a comment, and is ignored by the REBOL interpreter):

view layout [btn]  ; creates a GUI with a button

view layout [field]  ; creates a GUI with a text input field

view layout [text "REBOL is really pretty easy to program"]

view layout [text-list]  ; a selection list

view layout [
    button
    field
    text "REBOL is really pretty easy to program."
    text-list
    check
]

To make your widgets perform actions, enclose the action in square brackets (a block), immediately after the widget:

view layout [button "click me" [alert "You clicked the button."]]

view layout [btn "Display Rebol.com HTML" [editor http://rebol.com]]

view layout [btn "Write current time to HD" [write %time.txt now/time]]

; The word "value" refers to data contained in a currently activated
; widget:

view layout [
    text "Some action examples.  Try using each widget:"
    button red "Click Me" [alert "You clicked the red button."]
    field 400 "Type some text here, then press [Enter] on your keyboard" [
        alert value
    ]
    text-list 400x300 "Select this line" "Then this line" "Now this one" [
        alert value
    ]
    check yellow [alert "You clicked the yellow check box."]
    button "Quit" [quit]    
]

You can get data from a user using the "request-text" function:

name1: request-text
alert name1
name2: request-text/title/default "Your Name:" "John"
alert rejoin ["Hello" name2 "!"]

Here's an example of how to use buttons, text areas, and text-lists to manage data in a GUI:

view center-face layout [
    btn "Enter Name" [
        name: request-text/title/default "Your Name:" "John"
        insert head a1/text rejoin [name newline]
        show a1
    ]
    text "Enter your favorite phrase:"
    field [
        insert head a2/text rejoin [value newline]
        show a2
    ]
    text "Select a favorite color:"
    text-list 200x100 data ["red" "green" "blue" "yellow" "black" "white"] [
        append a3/text rejoin [value newline]
        show a3
    ]
    a1: area 200x50
    a2: area 200x50
    a3: area 200x50
]

Teaching REBOL GUI programming is slightly beyond the scope of this tutorial, but it's covered in great depth at re-bol.com. Start with the introduction at http://re-bol.com/rebol.html#section-6.3, and you'll understand enough to be productive, within a few minutes.

6. A Bit More Depth - Creating REBOL Functions

You can enclose entire chunks of code in "functions", which run every time the function word is used. The "does" word is used in REBOL to create simple functions:

say-hi: does [
    name: ask "Your name:  "
    print rejoin ["Hello " name "!"]
]
say-hi
say-hi
say-hi

Using the REBOL word "func", you can create functions that accept "parameters", or specified input data. The following "deposit" function adds the specified amount to a bank balance, and then prints the current balance:

deposit: func [amount] [
    balance: balance + amount
    print rejoin ["Your account balance is:  " balance]
]

balance: 10000

deposit 20
deposit 35
deposit 1023

One common use for functions, for example, is to run a complex action when a GUI widget is activated. This helps keep the complex action separate from the GUI layout code:

deposit: func [amount] [
    if error? try [
        balance: balance + (to-decimal amount)
        insert head a1/text rejoin [
            "Your account balance at  " now "  is:  " 
            to-string balance
            newline
        ]
        show a1
        focus f1
    ] [alert "** Error **  Be sure to enter numbers."]
]

balance: 10000

view layout [
    text "Enter Deposit or Debit Amount:"
    f1: field "100.00" [deposit value]
    a1: area
    do [focus f1]
]

7. A Complete, Fully Functional, GUI Application Using the Etsy API

At this point you should be able to understand the overwhelming majority of code in the following application, and you should know enough to understand how to extend it to use other functions in the Etsy API:

REBOL [title: "Etsy"]

do/args http://reb4.me/r/etsy.r context [
    Consumer-Key: #<type_your_key_here>
    Consumer-Secret: #<typ_your_secret_here>
    User-Store: %etsyusers
    Scope: [listings_w listings_r listings_d]  ; edit permissions here
    Sandbox: false                      ; change to true when approved
]

coupon-text: {
    ** SALE ** Enter the coupon code &quot;893894&quot; at checkout to
    receive 10% off your order &lt;br&gt;&lt;br&gt;
}

replace-items: does [
    found-items/text: copy {}  show found-items
    replaced-items/text: copy {}  show replaced-items
    found: copy []
    x: get in (etsy/listings []) 'results              
    for i 1 (length? x) 1 [  
        if find (get in x/:i 'description) search-text/text [ 
            insert head found-items/text copy rejoin [
                ; {"} search-text/text {" found in:  } 
                (get in x/:i 'title) newline
            ] 
            show found-items
            append found (get in x/:i 'listing_id)
            append found (get in x/:i 'description)
            append found (get in x/:i 'title)
            append found (get in x/:i 'state)
        ]
    ]
    foreach [lstngid dscrptn titl state] found [
        either state <> "active" [
            insert head replaced-items/text copy rejoin [
                titl { was NOT replaced (listing inactive)^/}
            ]
            show replaced-items
        ][
            etsy/api-call/with put rejoin [
                %listings/ lstngid
            ] [
                description: (
                    replace/all dscrptn search-text/text replace-text/text
                )
            ]
            insert head replaced-items/text copy rejoin [titl {^/}]
            show replaced-items
        ]
    ]
    ; alert "Done"
]

sale: func [add-or-remove] [
    coupon-code: copy request-text/title/default"Coupon Text:" coupon-text
    found-items/text: copy {}  show found-items
    replaced-items/text: copy {}  show replaced-items
    found: copy []
    x: get in (etsy/listings []) 'results
    focus found-items           
    for i 1 (length? x) 1 [  
        insert head found-items/text copy rejoin [
            (get in x/:i 'title) newline
        ] 
        show found-items
        append found (get in x/:i 'listing_id)
        append found (get in x/:i 'description)
        append found (get in x/:i 'title)
        append found (get in x/:i 'state)
    ]
    foreach [lstngid dscrptn titl state] found [
        either state <> "active" [
            insert head replaced-items/text copy rejoin [
                titl { was NOT replaced (listing inactive)^/}
            ]
            show replaced-items
        ][
            etsy/api-call/with put rejoin [
                %listings/ lstngid
            ] either add-or-remove = true [
                [
                    title: rejoin ["SALE-" titl]
                    description: rejoin [coupon-code dscrptn]
                ]
            ] [
                [
                    title: replace titl "SALE-" ""
                    description: replace dscrptn rejoin [coupon-code] ""
                ]
            ]
            insert head replaced-items/text copy rejoin [titl {^/}]
            show replaced-items
        ]
    ]
    focus replaced-items
    ; alert "Done"
]

create-listing: does [
    itm: request-text/title/default "Title:" "Item 100"
    desc: request-text/title/default "Description:" "Ring #100"
    prc:  to-decimal next find (
            request-text/title/default "Price:" "$19.99"
            ) "$"
    if true = request "Would you like to see a listing of category IDs?" [
        categories: etsy/api-call get %taxonomy/categories
        cat-list: copy []
        foreach category categories/results [
            append cat-list reduce [
                category/long_name category/category_id
            ]
        ]
        chosen-category: request-list "Categories" cat-list
    ]
    if unset? chosen-category [chosen-category: "69150467"]
    ctgry: request-text/title/default "Category ID:" form chosen-category
    flash "Creating item..."
    etsy/api-call/with post %/listings [
        quantity: 1 
        title: itm 
        description: desc 
        price: prc 
        category_id: ctgry 
        who_made: "i_did" 
        is_supply: "1" 
        when_made: "2010_2012" 
        shipping_template_id: "330"
    ]
    unview
    alert rejoin ["CREATED: " itm ", " desc ", " prc]
]

delete-listing: does [
    itm2del: request-text/title "Listing ID #:"
    either true = request "Really Delete?" [
        flash "Deleting..."
        etsy/api-call/with get rejoin [%listings/ itm2del] [
            method: "DELETE"]
        unview
        alert rejoin ["Item " itm2del " deleted."]
    ] [
        return
    ]
]

get-image: does [
    found: copy []
    x: get in (etsy/listings []) 'results  
    for i 1 (length? x) 1 [  
        append found (get in x/:i 'title)
        append found (get in x/:i 'listing_id)
    ]
    photo-item-id: request-list "Select Item:" found
    photo-list: etsy/api-call/with get rejoin [
        %listings/ photo-item-id "/images"] []
    either error? try [photo-id: first get in photo-list 'results] [
        alert "No photo available for that item."
        return
    ][
        photo-info: etsy/api-call/with get the-code: rejoin [
            %listings/ photo-item-id "/images/ " photo-id
        ] []
    ]
    editor either [] = the-photo: (get in photo-info 'results) [
        "none"
    ] [
        the-photo
    ]
]

etsy/as "<your-username>"

view center-face gui: layout [
    across
    text 80 right "If" 
    cond1: drop-down 100 data [
        "Title" "Description" "Listing ID" "Any Field"
    ]
    cond2: drop-down 150 data [
        "REPLACE ALL" "Contains" "Does NOT Contain" "Equals"
    ]
    cond3: field 454 "ring" return
    text 80 right "Search Text:" search-text: field 720 "ring" [
        replace-text/text: copy search-text/text show replace-text
    ] return
    text 80 right "Replace Text:" replace-text: field 720 "ring" return
    text 805 "" return
    box black 805x2 return
    text 805 "" return
    text 400 "Found Items:" text 200 "Replaced Items:" return
    found-items: area  replaced-items: area  return
    btn "List Raw Data" [editor copy get in (etsy/listings []) 'results]
    btn "Create Listing" [create-listing]
    btn "Delete Listing" [delete-listing]
    btn "Add Sale" [sale true]
    btn "Remove Sale" [sale false]
    btn "View Image" [get-image]
    btn "Replace Description" [replace-items]
]

8. Creating a CGI Version of Your App

The CGI interface allows you to create applications that run on a web server. To use CGI, you must have access to a web hosting account where you can create and execute web applications. To be able to use the following script, you must be able to upload REBOL to your account, along with the program code, and execute both. In CGI applications, users visit the URL of your app, using their browser. The program code prints out HTML, which acts as the "GUI" interface for your program. The printed HTML forms submit data back to the CGI application on the web server, and that data is processed by the program code, the program prints out more HTML code, etc. The details of learning CGI programming are beyond the scope of this tutorial, but you can learn everything you need at http://re-bol.com/rebol.html#section-9.9.

The program below shows a minimal version of the GUI app in the previous section, converted to a bare bones CGI application. For those who are interested in pursuing the creation of web site apps, this code demonstrates everything you need to know to begin using the Etsy API in REBOL on your web server:

#! ../rebol276 -cs
REBOL [Title: "Etsy"]
print {content-type: text/html^/^/}
print {<HTML><HEAD><TITLE>Etsy</TITLE></HEAD><BODY>}
read-cgi: func [/local data buffer][
    switch system/options/cgi/request-method [
        "POST" [
            data: make string! 1020
            buffer: make string! 16380
            while [positive? read-io system/ports/input buffer 16380][
                append data buffer
                clear buffer
            ]
        ]
        "GET" [data: system/options/cgi/query-string]
    ]
    data
]
submitted: decode-cgi submitted-bin: read-cgi
if ((submitted/2 = none) or (submitted/4 = none)) [
    print {
        <STRONG>W A R N I N G  -  Private Server:</STRONG><BR><BR>
        <FORM METHOD="post" ACTION="./etsy.cgi">
            Username: <input type=text size="50" name="name"><BR><BR>
            Password: <input type=text size="50" name="pass"><BR><BR>
            <INPUT TYPE="SUBMIT" NAME="Submit" VALUE="submit">
        </FORM>
        </BODY></HTML>
    } 
    quit
]
myusername: "some-user-name"  mypassword: "some-password"
username: submitted/2   password: submitted/4 
either ((username = myusername) and (password = mypassword)) [][
    print "Incorrect Username/Password." 
    print {</BODY></HTML>} quit
]

do-etsy: does [
    do/args http://reb4.me/r/etsy.r context [
    Consumer-Key: #<my-key>
    Consumer-Secret: #<my-secret>
    User-Store: %etsyusers
    Scope: [listings_w listings_r listings_d]
    Sandbox: true
    ] 
    etsy/as "<my-user-name>"
]

if submitted/6 = "sale" [
    do-etsy
    coupon-code: submitted/8
    add-or-remove: submitted/10
    print "FOUND ITEMS:<br><br>"
    found: copy []
    x: get in (etsy/listings []) 'results
    for i 1 (length? x) 1 [  
        print copy rejoin [
            (get in x/:i 'title) <br>
        ] 
        append found (get in x/:i 'listing_id)
        append found (get in x/:i 'description)
        append found (get in x/:i 'title)
        append found (get in x/:i 'state)
    ]
    print "<br><br>REPLACED ITEMS:<br><br>"
    foreach [lstngid dscrptn titl state] found [
        either state <> "active" [
            print copy rejoin [
                titl { was NOT replaced (listing inactive)<br>}
            ]
        ][
            etsy/api-call/with put rejoin [
                %listings/ lstngid
            ] either add-or-remove = "add" [
                [
                    title: rejoin ["SALE-" titl]
                    description: rejoin [coupon-code dscrptn]
                ]
            ] [
                [
                    title: replace titl "SALE-" ""
                    description: replace dscrptn rejoin [coupon-code] ""
                ]
            ]
            print copy rejoin [titl {<br>}]
        ]
    ]
    print "<br>Done<br><br>"
    quit
]
if submitted/6 = "replace" [
    do-etsy
    search-text: submitted/8
    replace-text: submitted/10
    print "FOUND ITEMS:<br><br>"
    found: copy []
    x: get in (etsy/listings []) 'results              
    for i 1 (length? x) 1 [  
        if find (get in x/:i 'description) search-text [ 
            print rejoin [
                ; {"} search-text {" found in:  } 
                (get in x/:i 'title) "<br>"
            ] 
            append found (get in x/:i 'listing_id)
            append found (get in x/:i 'description)
            append found (get in x/:i 'title)
            append found (get in x/:i 'state)
        ]
    ]
    print "<br><br>REPLACED ITEMS:<br><br>"
    foreach [lstngid dscrptn titl state] found [
        either state <> "active" [
            print copy rejoin [
                titl { was NOT replaced (listing inactive)<br>}
            ]
        ][
            etsy/api-call/with put rejoin [
                %listings/ lstngid
            ] [
                description: (
                    replace/all dscrptn search-text replace-text
                )
            ]
            print copy rejoin [titl {<br>}]
        ]
    ]
    print "<br>Done<br><br>"
    quit
]
if submitted/6 = "create-listing" [
    do-etsy
    itm: submitted/8
    desc: submitted/10
    prc:  to-decimal next find submitted/12 "$"
    ctgry: submitted/14
    print "Creating item...<br><br>"
    etsy/api-call/with post %/listings [
        quantity: 1 
        title: itm 
        description: desc 
        price: prc 
        category_id: ctgry 
        who_made: "i_did" 
        is_supply: "1" 
        when_made: "2010_2012" 
        shipping_template_id: "330"
    ]
    print rejoin ["CREATED: " itm ", " desc ", " prc]
    quit
]
if submitted/6 = "delete-listing" [
    do-etsy
    itm2del: submitted/8
    print "Deleting...<br><br>"
    etsy/api-call/with get rejoin [%listings/ itm2del] [
        method: "DELETE"
    ]
    print rejoin ["Item " itm2del " deleted."]
    quit
]
if submitted/6 = "view-raw" [
    do-etsy
    print {<pre>}
    probe copy get in (etsy/listings []) 'results
    print {</pre>}
    quit
]
if submitted/6 = "get-image2" [
    do-etsy
    photo-item-id: submitted/8
    photo-list: etsy/api-call/with get rejoin [
        %listings/ photo-item-id "/images"
    ] []
    either error? try [photo-id: first get in photo-list 'results] [
        print "No photo available for that item."
        return
    ][
        photo-info: etsy/api-call/with get the-code: rejoin [
            %listings/ photo-item-id "/images/ " photo-id
        ] []
    ]
    probe either [] = the-photo: (get in photo-info 'results) [
        "none"
    ] [
        the-photo
    ]
    quit
]
if submitted/6 = "my-subroutine" [
    do-etsy
quit
]

default-coupon-code: {
** SALE ** Enter the coupon code &quot;982u3445&quot; at checkout
to receive 10% off your order.&lt;br&gt;&lt;br&gt;
}

print rejoin [
{<h2>Add or Remove Sale:</h2>
<FORM METHOD="post" ACTION="./etsy.cgi">
    <INPUT TYPE=hidden NAME="username" VALUE="} myusername {">
    <INPUT TYPE=hidden NAME="password" VALUE="} mypassword {">
    <INPUT TYPE=hidden NAME="subroutine" VALUE="sale">
    Coupon Code:<BR>
    <TEXTAREA COLS="50" ROWS="18" NAME="couponcode">}
        default-coupon-code 
    {</TEXTAREA><BR><BR>
    Add or Remove: <select NAME="addorremove">
        <option>add
        <option>remove
    </option></select><br><br>
    <INPUT TYPE="SUBMIT" NAME="Submit" VALUE="submit">
</FORM>
<BR><HR>
<h2>Replace In Description:</h2>
<FORM METHOD="post" ACTION="./etsy.cgi">
    <INPUT TYPE=hidden NAME="username" VALUE="} myusername {">
    <INPUT TYPE=hidden NAME="password" VALUE="} mypassword {">
    <INPUT TYPE=hidden NAME="subroutine" VALUE="replace">
    Search Text:<BR><BR>
    <input type=text size="35" name="searchtext">
    <BR><BR>
    Replace Text:<BR><BR>
    <input type=text size="35" name="replacetext">
    <BR><BR>
    <INPUT TYPE="SUBMIT" NAME="Submit" VALUE="submit">
</FORM>
<BR><HR>
<h2>Create Listing:</h2>
<FORM METHOD="post" ACTION="./etsy.cgi">
    <INPUT TYPE=hidden NAME="username" VALUE="} myusername {">
    <INPUT TYPE=hidden NAME="password" VALUE="} mypassword {">
    <INPUT TYPE=hidden NAME="subroutine" VALUE="create-listing">
    Title: <BR><BR>
    <input type=text size="35" name="title" value="Ring 100"><BR><BR>
    Description: <BR><BR>
    <input type=text size="35" name="description" 
        value="Ring 100.  A very pretty ring."><BR><BR>
    Price: <BR><BR>
    <input type=text size="35" name="Price" value="$19.99"><BR><BR>
    Category: <BR><BR>
    <input type=text size="35" name="Category" value="69150467">
    <BR><BR>
    <INPUT TYPE="SUBMIT" NAME="Submit" VALUE="submit">
</FORM> 
<BR><HR>
<h2>Delete Listing:</h2>
<FORM METHOD="post" ACTION="./etsy.cgi">
    <INPUT TYPE=hidden NAME="username" VALUE="} myusername {">
    <INPUT TYPE=hidden NAME="password" VALUE="} mypassword {">
    <INPUT TYPE=hidden NAME="subroutine" VALUE="delete-listing">
    Listing ID #: <BR><BR>
    <input type=text size="35" name="listing-id"><BR><BR>
    <INPUT TYPE="SUBMIT" NAME="Submit" VALUE="submit">
</FORM> 
<BR><HR>
<h2>View All Raw Listing Data:</h2>
<FORM METHOD="post" ACTION="./etsy.cgi">
    <INPUT TYPE=hidden NAME="username" VALUE="} myusername {">
    <INPUT TYPE=hidden NAME="password" VALUE="} mypassword {">
    <INPUT TYPE=hidden NAME="subroutine" VALUE="view-raw">
    <INPUT TYPE="SUBMIT" NAME="Submit" VALUE="submit">
</FORM> 
<BR><HR>
<h2>View Image:</h2>
<FORM METHOD="post" ACTION="./etsy.cgi">
    <INPUT TYPE=hidden NAME="username" VALUE="} myusername {">
    <INPUT TYPE=hidden NAME="password" VALUE="} mypassword {">
    <INPUT TYPE=hidden NAME="subroutine" VALUE="view-image">
    <INPUT TYPE="SUBMIT" NAME="Submit" VALUE="submit">
</FORM> 
</BODY></HTML>}
]
quit

9. Summary

If you're an experienced coder, it should be relatively simple to take the explanation in this tutorial and apply the concepts to your own language. An understanding of basic programming is all that's essential: sending GET and POST data to call the functions in the Etsy API, concatenating strings, using variables, using conditional evaluations and loops, performing text search/replace, etc. The most important parts are becoming familiar with the functions in the Etsy API, understanding their syntax and parameters, and understanding how they can be used together to produce the end result you imagine. You'll need to be able to think, for example, about how to use functions to retrieve listing_id's, allow users to select from those IDs with a GUI drop-down box, and then be able to call another API function using the selected data from that list, as it's parameter(s). You need to learn how to use the OAuth security protocol, along with the proprietary extensions that Etsy added to manage access to various account features. Just as there is an Etsy module for REBOL, there are libraries already created for Python, Ruby, Perl, and Cocoa, which allow you to do all these things using the familiar native syntax of the language you choose. Be sure to read the Etsy API documentation to understand how all the pieces fit together, and choose the coding tools you're most comfortable using. Check out the Etsy developer forum to read answers to typical questions, and keep up with the most recent updates and changes to the API.

If you're a newbie, it can take years years to master all the techniques and thought processes that go into writing large applications and commercial quality code, but you can begin to write effective short scripts, and understand how to create your own simple apps very quickly. The short examples in this tutorial can be easily modified to use other functions in the API, and to accomplish very useful goals. For many users, such simple scripts may be all that are needed to save time and lots of repetative work. If you want to learn more about how to use REBOL, read through the full tutorial at http://re-bol.com. You can ask questions specifically about REBOL programming at http://rebolforum.com. Good luck!

Keywords:

Etsy API, Etsy programming, Etsy tutorial, Etsy app, customize Etsy

Copyright Nick Antonaccio 2012, All Rights Reserved