⌈⌋ ⎇ branch:  freshcode


Artifact [8933561145]

Artifact 89335611450a37090e4c97d660c8a7b92799c384:

Wiki page [Freecode JSON API] by mario 2015-04-13 11:21:32.
D 2015-04-13T11:21:32.983
L Freecode\sJSON\sAPI
N text/x-markdown
P b96f3b3b90e90cd6f86ee113520b43d82ee66dd0
U mario
W 11580

*State: **obsolete**, replaced*

See [API2](wiki/API2) for a newer proposal.

-----

Freshcode reimplements the [Freecode JSON API](http://web.archive.org/web/20130412231142/http://help.freecode.com/kb/api-7/data-api-releases)
 to allow for project and release updating per command line ([freecode-submit](finfo/doc/fc-submit)).



# Old URL scheme


The request URLs and data formats are broadly compatible:

<table width=100%>
<tr> <th>method</td> <th>URL path</th> <th>function</th> <th>1:1</th> </tr>
<tr> <td>GET</td> <td><code>/projects/&lt;name&gt;.json</code></td> <td>query</td> <td>YES</td> </tr>
<tr> <td>PUT</td> <td><code>/projects/&lt;name&gt;.json</code></td> <td>update_core</td> <td>YES</td> </tr>
<tr> <td>CREATE</td> <td><code>/projects/&lt;name&gt;.json</code></td> <td>new_project</td> <td>NEW</td> </tr>
<tr> <td>POST</td> <td><code>/projects/&lt;name&gt;/releases.json</code></td> <td>publish</td> <td>YES</td> </tr>
<tr> <td>GET</td> <td><code>/projects/&lt;name&gt;/releases/pending.json</code></td> <td>pending</td> <td>YES</td> </tr>
<tr> <td>DELETE</td> <td><code>/projects/&lt;name&gt;/releases/&lt;int&gt;.json</code></td> <td>withdraw</td> <td>YES</td> </tr>
<tr> <td>GET</td> <td><code>/projects/&lt;name&gt;/urls.json</code></td> <td>urls</td> <td>NEW</td> </tr>
<tr> <td>PUSH</td> <td><code>/projects/&lt;name&gt;/urls.json</code></td> <td>update_urls</td> <td>NEW</td> </tr>
</table>

See also [http://web.archive.org/web/20130412231142/http://help.freecode.com/kb/api-7/data-api-releases](http://web.archive.org/web/20130412231142/http://help.freecode.com/kb/api-7/data-api-releases) for the original reference.

There are semantic differences in that freshcode.club does not currently require pre-moderation and approvals. Still the API is unchanged apart from the URL updating.


### General

GET requests append an `?auth_code=` which contains the plain auth\_token / password.

POST/PUT instead wrap the `"auth_code"` in the outermost layer of the JSON content body.


## Query <kbd>GET</kbd>`/projects/<name>.json`

Retrieves general project information. The original  Freecode.com included:

    {
       "project": {
          "id": "424902329",
          "permalink": "project_name",
          "oneliner": "First sentence of description.",
          "license_list": "BSDL",
          "approved_urls": [
             { "label": "src", "redirector": "http://example.org" }
          ]
       }
    }

Additionally the extended Freshcode.club [feed](http://freshcode.club/feed/xfer) fields are present (tags, homepage, image, urls, etc.).

If the GET request also includes an `?auth_code=`, then the raw database contents are even returned (lock, submitter, submitter\_openid, hidden, flags, social\_links, regex, ...)


## Update_core <kbd>PUT</kbd> `/projects/<name>.json`

To edit the general project information, send the basic fields via `PUT` wrapped in a JSON dict containing:

    {
       "auth_code": "plain_pw_123",
       "project": {
          "description": "Project does foo and bar.",
          "oneliner": "__will_be_ignored__",
          "license_list": "GNU GPL",
          "project_tag_list": "desktop,end-user,browser,gtk",
       }
    }

In addition freshcode honors any included `homepage` and `download` URL, or updating the `state` (alpha, beta, stable, etc.)


## Publish <kbd>POST</kbd> `/projects/<name>/releases.json`

Submitting a new release is just as straightforward. The `POST` body ought to list:

    {
       "auth_code": "pw123",
       "project": {
          "version": "3.0",
          "changelog": "User-friendly summary of changes..",
          "tag_list": "major,bugfix,security,stable",
          "hidden_from_frontpage": false,
       }
    }

The `tag_list` is split into our `scope` and `state` fields, and the special tag `hidden` sets the hidden\_from\_frontpage flag implicitly. A new `download` URL can also be submitted herein.


## URLs dict <kbd>GET</kbd>/<kbd>PUSH</kbd> `/projects/<name>/urls.json`

The URL retrieval and storage methods have been simplified. Freecode used oddly nested JSON (see the Query example). It required the update process to first `GET` a list, then tediously `PUT`ing in updated entries, `POST`ing new ones, and `DELETE`ing stale ones each. Which is not only a long-winded implementation for API server and client, but would incur around 15 database revisions when updating just 3 URLs. ^^

Instead we'll just pass around an associative urls dictionary/array.  
For `GET` requests on `/projects/<name>/urls.json` you receive:

    {
       "urls": {
          "src": "http://example.org/pkg-src.txz",
          "release-notes": "http://example.org/proj-blog/"
       }
    }

Updating all URLs at once takes the same format, but requires an `auth_code` of course. The API is indifferent to `PUT` or `POST` or even **`PUSH`** here.

    {
       "auth_code": "plain_pw_123",
       "urls": {
          "txz": "http://example.org/pkg-$version.txz",
       }
    }

Notice that all URLs may contain a [`$version` placeholder](wiki/$version+placeholder) as usual.  Which somewhat alleviates the need to update URLs anyway. Links names are free-form, can be mixed-cased, should be dash-delimited.


## withdraw_release <kbd>DELETE</kbd> 

The [doubly versioned database scheme](wiki/database+scheme) is meant to be somewhat immutable. As such there is no actual deleting taking place. Withdrawing a release is still possible. It'll just be marked as hidden, and/or flagged for moderator attention, (or somewhen use the `deleted` flag even).

It takes two steps:

   1. **GET** `/projects/<name>/releases/pending.json` to uncover the associated `id` for a `version`.

        [
          { 
            "release": {
              "id": "1403557288",
              "version": "3.15.1",
              "approved_at": "2014-06-28T22:51:00+0000"
            }
          },
          {
            "release": {
              "id": "1403995977",
              "version": "3.15.2",
              "created_at": "2014-06-28T22:52:57+0000"
            }
          }
        ]

      (There are more fields, absent from this example.)

   2. Send a **DELETE** request onto `/projects/<name>/releases/<id>.json?auth_code=..` to remove that project revision.

      The `id` is always numeric. Also it's basically just the t_published timestamp.

Because there is no pending/approval stage on freshcode.club anymore, this even works for previous releases, not just the current one.



## New_project <kbd>CREATE</kbd> `/projects/<name>.json`

For submitting an entirely new project, send a CREATE request onto `/projects/<newname>.json`.
Basically this request scheme is just an extension over the `PUT` method (Update_core). 

    {
       "auth_code": "your_new_pw_123",
       "project": {
          "title": "My project",
          "description": "...",
          "image": "http://example.org/screenshot.png",
          "submitter": "Your Name, username@gravatar",
          "scope": "stable",
          "version": "2.0.0-current",
          "autoupdate_url": "http://example.org/NEWS.txt",
          "license_list": "MITL",
          "project_tag_list": "desktop,end-user,browser,gtk",
       }
    }

This method accepts way more fields than other request schemes. (Since this is a diversion from the old freecode API, it might as well be more convenient). Please note that most fields are entirely optional still:

  - The project **name** is derived from the `/projects/name.json` request URL.
  - If the project **title** is omitted, the project basename will be used simply.
  - A project **description** text could also be submitted via PUT (update_core) later.
  - The **image** can contain an application screenshot URL. If left out, a homepage screenshot will be generated automatically / as usual.
  - With **submitter** you could define an author name. Or a gravatar email address, or user@github, user@launchpad, user@sourceforge icon. Both are optional.
  - Optionally declare the current **version**.
  - Or submit the current **changelog** right along.
  - And of course you can submit all the fields that "update_core" already accepts:
      - Project **homepage**
      - and **download** URL
      - the **license**
      - and **tags**
      - release **state** (alpha, beta, stable)
      - and **scope** (minor bugfix, major feature)
  - <kbd>CREATE</kbd> basically can make a subsequent <kbd>PUT</kbd> redundant. (The additional fields should probably be made accessible via PUT/update_core too..)

**Auth_code**: A project can only be created once. Which is because this request populates the project authorization hash.  The unencrypted `auth_code` from the CREATE payload is used for that. (It's bcrypt-hashed internally, and stored in our <kbd>lock</kbd> database field..)

**SSL Authorization**: *Still undecided*. CREATE requests require a client SSL certificate to be sent along.

  - This is ***not a security feature***. Just obscures the API access to avert spambot submissions. (Perhaps redundant, because `<form>` spam is more likely, and the API is complicated enough as it is. But enforcing a SSL cert pretty much rules out typical Windows trojan botnets.)
  - And there's no need for custom SSL certs. A single publically-known private cert can be used. It's available under [fossil:doc/trunk/doc/submit.pem](http://fossil.include-once.org/freshcode/doc/trunk/doc/submit.pem) (f18b1aba613ac804). 
  - If you want to use a custom cert, just mail in the serial number (`openssl x509 -noout -text -in s.pem`) for registration.



## Response JSON

When operations succeeded, the response will usually come with HTTP code 200 or 201, and include a JSON body of `{"success": true}`.

Whereas errors can result in HTTP codes 503, 500, 401 with a message body of `{"error": "details..."}`.


## Xfer.JSON

If you just want to browse trough projects, then the plain freshcode feed is simpler to deal with. It's available as `http://freshcode.club/feed/xfer` or per-project with `http://freshcode.club/feed/<name>`.


# Password setup

To utilize remote updates, you just need an extra password in your project listing. <s>Add at least one OpenID handle and a password hash in the **`Lock`** field. (Trust me, you need both!)</s>. As of now, projects can be registered with a password lock right away. The /login page provides for a per-project password login.

Otherwise, you can manually adapt the <b>lock</b> field in the submit form. To use OpenID and/or a password:

     http://your.openid.com/, $1$rua41x5V$mZHrJHKySV0uXfLA4EjEz0

You can generate a password hash using:

   * using PHPs [password_hash()](http://php.net/password_hash)
   * in Python with `bcrypt.hashpw("pw123", bcrypt.gensalt( 12 ))`
   * `openssl passwd -1` for MD5
   * `mkpasswd -m sha-256 -S saltsalt`
   * Online services like [bcrypt-generator.com/](http://www.bcrypt-generator.com/), [bcrypthashgenerator.apphb.com/](http://bcrypthashgenerator.apphb.com/) or via [htpassword generator](http://aspirine.org/htpasswd_en.html)

For `freshcode-submit` list the plain password in your `~/.netrc` file:

    machine freshcode
      account pw123
      password none

Afterwards submitting release updates is as simple as 

    freecode-submit -P name -v 2.0 -c "Changes.."

A complete patch is currently in preparation.

Z bb11491cffbe1f682888a57e01f82f9b