Wiki page
[Freecode JSON API] by
mario
2015-04-11 21:41:53.
D 2015-04-11T21:41:53.977
L Freecode\sJSON\sAPI
N text/x-markdown
P a43141ee3c15a9eb0e33d1b15a65025fc006a014
U mario
W 11526
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)).
# API scheme
<i>State: <b>implemented, testing</b></i>
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/<name>.json</code></td> <td>query</td> <td>YES</td> </tr>
<tr> <td>PUT</td> <td><code>/projects/<name>.json</code></td> <td>update_core</td> <td>YES</td> </tr>
<tr> <td>CREATE</td> <td><code>/projects/<name>.json</code></td> <td>new_project</td> <td>NEW</td> </tr>
<tr> <td>POST</td> <td><code>/projects/<name>/releases.json</code></td> <td>publish</td> <td>YES</td> </tr>
<tr> <td>GET</td> <td><code>/projects/<name>/releases/pending.json</code></td> <td>pending</td> <td>YES</td> </tr>
<tr> <td>DELETE</td> <td><code>/projects/<name>/releases/<int>.json</code></td> <td>withdraw</td> <td>YES</td> </tr>
<tr> <td>GET</td> <td><code>/projects/<name>/urls.json</code></td> <td>urls</td> <td>NEW</td> </tr>
<tr> <td>PUSH</td> <td><code>/projects/<name>/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 e1020c37606a9fcb5936cfc4887a7812