Protocol - danopia/deviantart-difi GitHub Wiki
This article tries to cover DiFi usage, both in the DeviantArt website and in other external uses (such as Userscripts).
The DiFi is an extensive RPC/AJAX centric service that enables pages to communicate with the DeviantArt servers.
This includes the following:
- Getting data (such as Deviation and User information)
- Performing actions (such as adding a Deviation to Favourites)
- Populating the pages (such as the Deviation page on browsing different pages)
- Changing settings (User info, navigation, blocked users, etc)
This API was introduced in deviantART v5 and is used up until DeviantArt v9.
DeviantArt does not operate a fixed request limit for a client, instead, they have adaptive rate limiting, that allows short bursts of activity but preventing clients from making requests at a rate that will affect other users or the website's stability.
If you receive 403 errors that contain an HTML response rather than JSON, please ensure your client is sending a User Agent header and using HTTP compression for the request, as deviantART rejects any requests not meeting this requirement.
You may also receive rate errors if deviantART backend systems are overloaded and cannot accept any more requests. When this happens clients should slow down their requests for a period of time.
- The url consists of the request parameters and a transmission parameter.
- Each call (
c[]
) names a class object to perform the call on, a method to call on the object, and a list of params. - The transmission parameter (
t
) controls the format of the response.
- Each call (
- HTTP request is either
GET
orPOST
verbs, based on the type of action requested. - A single DiFi request can carry multiple method calls, denoted as
calls
in both requests and responses.
DiFi calls can either require authentication or don't, based on the action that is being performed.
The rule of thumb is that if you can access the call without being logged-in you probably will not need authorization cookies.
Most GET
requests that only retrieve data and don't perform any actions will generally not require authentication.
On the other hand, any type of requests that require authorization (e.g. POST
requests) will require authentication.
Auth-dependent actions use the userinfo (ui
) parameter.
DiFi appears to use mixed conventions that are rarely consistent even within a class and/or per method-basis.
Furthermore, all class and method names are case-sensitive.
- Class names are always StudlyCaps or PascalCase.
- Here's a list of known used method name conventions:
- Class::DoSomething – i.e. UpperCamelCase
- Class::doSomethingElse – i.e. lowerCamelCase
- Class::do_another_thing – i.e. underscore_delimited_lowercase
- Class::makesomechanges – i.e. lowercase entirely, without any delimiters
Each request is broken down into the following sections:
- Base URL – The base URL that the API accepts requests on
-
Parameters – the HTTP parameters that are passed to the API
-
c[]
– an array containing the request calls -
t
– the response format -
ui
– theuserinfo
cookie token (optional)
-
http://www.deviantart.com/global/difi/?c[]="Class","method",["arg1","arg2","etc"]&t=json
DiFi calls are sent to either: /global/difi/
or /global/difi.php
It is also possible to access DiFi via http://www.deviantart.com/global/difi.php with the same results.
NOTE: The jsonp
format only works on the https://backend.deviantart.com/global/difi/
url.
A list of DiFi call requests are sent in the c[]
parameter, thus more than one call may be performed per HTTP request.
The request parameters are:
-
Class
The DiFi classes are listed on the sidebar of this Wiki. -
Method
See each Class for a list of available methods. -
Arguments
See a class method for its arguments.
Argument Types:- boolean:
false
ortrue
- string:
Hello world
- integer: 0, 1 or 2
- object: i.e. named pairs {"name": "value"}
- array: can contain any kind of arguments
(Often integers are sent as a string due to this.)
- boolean:
The c[]
parameter contains the request parameters and is delimited with ,
like this:
?c[]="Class","method",["argument1","argument2","argument3","etc"]
This is the simple and easy format to perform a DiFi request.
To make a call with more than one set of arguments to the same class and method, you can append the arguments array like this:
?c[]="Class","method",["argument1","argument2"],["argument3","argument4"]
This means that you can put multiple calls that share the same class and method into a single URL request, using the first notation and repeating the []
part per needed.
You can also put several calls that don't share the same class or method in a single request, by adding a second c[]
parameter using any class/method/notation you like:
?c[]="Class","method",["argument1","argument2"]
&c[]="AnotherClass","other_method",["argument1","argument2"]
&c[]=...
To that, you can add as many c[]=…
as you need. They must be separated by a &
delimiter.
DiFi also supports an older format, that has a more simple format, but doesn't work with multiple calls.
?c[]=Class;method;argument1,argument2,argument3,etc
Example:
http://www.deviantart.com/global/difi.php?c[]=Class;method;argument1,argument2,argument3,etc
The second parameter in the url, t
, is responsible for the response encoding.
- json — gives you the data output in the standard JSON-formatted string
- xml — gives you a XML document that can be parsed by XML readers
-
php — gives you a multi-dimensional PHP array that can be deserialized in PHP scripts using
unserialize()
-
page — gives you an HTML page with an JSON object encoded in it
REMOVED
-
default — gives you a human-readable table which is only suitable for testing
REMOVED
The jsonp
would output json wrapped in a call to DiFi._callbackSI()
javascript.
(This historically used to be called jssi
.)
DiFi can also transmit data using the obscure JSON-P (i.e. JSON with padding) format, and it's mainly used in combination with the DiFi object's static method.
The content returned with this format is Javascript code that's meant to be executed.
(As a security measure, you can only access "public" data using this format).
To use the jsonp
method, you need to further supply the following query parameters:
-
callback
: e.g.DiFi._callbackSI
-
extraarg
: e.g.lookup
Response:
DiFi._callbackSI( {"DiFi":{ . . . }, "<request_url_queries>" );
This format solely exists for historical purposes, and it is not recommended to use it in order to retrieve data in modern applications.
The third parameter, dubbed ui
, is often required for POST
calls.
Sometimes, in a call, this argument should be set in order for your call to work correctly. This is probably used to help prevent XSRF (Cross-Site Request Forgery) as this has been a problem on deviantART in the past.
The value of the ui
parameter equals the value of userinfo
cookie.
DiFi calls can include two additional parameters that appear to be intended for debugging purposes.
You can safely omit these (in fact we recommend you to do so).
This value is seen to be set to true
when there are no callbacks set.
TODO: This might signal the DiFi backend not to set cookies?
Purpose unknown.
This value is equal to the DaPx.last_logid
, which defined in any HTML page.
Seems to be debugging-related.
This value seems to be an incremental number, that doesn't seem to control anything besides client-side caching.
With each new DiFi request, the mp
value is incremented.
This value seems to be an additional static json-encoded parameter that is occasionally used.
The native DiFi object uses the setAnalogPayload()
method to set a new payload.
This seems to be a legacy property, and it's unknown whether DeviantArt still uses this parameter.
Example: {"content_source":"MC_deviation_stack"}
which signals the MessageCenter class that the trashes_message
method was called from a "deviation stack". Purpose is unknown.
A list of all whitelisted keys is mentioned to be available in the following property:
Lib_DiFi_Common_Http_Request::$analog_keys_whitelist
DiFi requests can be made with either GET
or POST
verbs.
GET requests are usually used to gather public or personal information.
Some actions will require authentication, which usually depends on sending login cookies (e.g. auth
and userinfo
) alongside your request.
Userscripts are usually using the Browser's cookie container automatically, while website javascript or executables need to store the cookies when logged in, so GET-requests work correctly.
POST requests are used to either perform actions or acquire private information.
These requests require not only the POST
HTTP method and the browser's cookies as identification, but are often also checked for their source of call (i.e. the "Referer" header). This means that most POST requests will fail if you don't start them from a DeviantArt page.
POST requests are often the DiFi object's method of choice to either receive or transmit data, even when a GET request could be used instead. This may be due to the length limitations of GET requests.
The DiFi response can be encoded in a variety of formats, such as json, xml and php.
DeviantArt by default uses the JSON format in the DiFi object, and many Userscripts also follow the same principle.
Unless you need XML format in your project, or are more comfortable dealing with XML, it's probably a better idea to use JSON in your projects as well.
A barebone DiFi response of type json
will look like this:
{
"DiFi": {
"status": "SUCCESS",
"response": {
"calls": [ ..., ..., ..., ... ]
}
}
}
{
"DiFi": {
"status": "FAIL",
"response": {
"error": "DiFi Request Failed",
"details": "c[] argument not specified"
}
}
}
The response is encapsulated in the DiFi
property, which is of type object
. This can be used to parse the response via custom DiFi handlers, and/or identify if your DiFi call was recognized and executed by DeviantArt servers.
The DiFi
object will contain exactly two properties, a status
and a response
property.
- The
status
property will be eitherSUCCESS
orFAIL
. - The
response
property will contain a list of each call.
Name | Value | Explanation |
---|---|---|
status |
SUCCESS |
The c[] calls were correctly identified and executed. |
status |
FAIL |
The request was failed due to reason specified in the error and details properties. |
Most calls to DiFi should have a status
value of SUCCESS
, even if any of the subsequent calls themselves are failed.
Therefore, if you get a status
value of FAIL
, something is wrong.
If everything went successful, you will have a calls
property which will be an array
containing an object
for each of your calls.
Here's an example of calls
property:
[
{
"request": {
"class": "MyClass",
"method": "placebo_call",
"args": [ ..., ..., ... ]
},
"response": {
"status": "...",
"content": ...
}
}
]
As you see, each call will contain exactly two properties:
-
request
– which will contain your request details that you have sent. (This could be handy for debugging purposes.) -
response
– which will contain the result of DeviantArt servers processing your call. This property will contain:-
status
– the status of executing your call -
content
– the return content of your processed call. Could be either null, or an object.
-
Name | Value | Explanation |
---|---|---|
status |
SUCCESS |
The operation was executed successfully. |
status |
NOEXEC_HALT |
Something prevented the operation from being executed. |
status |
FAIL |
The request was executed, but it failed. |
- The
SUCCESS
andFAIL
denote that the call was executed, irregardless of being successful or not. However,NOEXEC_HALT
denotes that the call was not even attempted to be executed at all. - Any error reasons will be specified in the
error
anddetails
properties of thecontent
property. - The
status
for each call differs from the rootstatus
property, and it denotes whether the execution of this particular call was successful. (DiFi_result.response.calls[0].response.status
) - On some calls, the content response will always return NULL. Check for the
status
field to see if the operation was successful.
"status": "NOEXEC_HALT",
"content": {
"error": "DiFi method is non-const in const execution state",
"details": "User::usernameAvailable"
}
-
DiFi method is non-const in const execution state
- When using incorrect HTTP verb for request
-
DiFi method not registered
- When calling non-existent methods on valid classes (e.g. removed calls)
-
DiFi failed to load class
- When calling a method that has failed to load due to some reason (e.g. invalid classname)
-
DiFi argument count mismatch
- When calling a method with less or more arguments than required
-
DiFi argument validation error
- When the passed arguments to a method are not in a valid form
-
DiFi Security Access Error (
ERR_DIFI_ACCESS_DENIED
)- When making a request without being logged-in
- When making a request that you don't have the privilege to do so
-
Details:
access was not granted by any rule
.
-
DiFi method did not return DiFi response structure
- When a DiFi method did not return expected response
The DiFi
object is responsible to handle DiFi calls in the DeviantArt website, and can be used by either native calls or user-script calls to perform actions on the site.
More information is here.
More about sending Requests is available in JS Access.