awesomemotive / easy-digital-downloads

Sell digital downloads through WordPress
https://easydigitaldownloads.com
GNU General Public License v2.0
868 stars 473 forks source link

New EDD_API Class #857

Closed pippinsplugins closed 11 years ago

pippinsplugins commented 11 years ago

We're going to introduce a new API that makes it possible to retrieve sales data, earnings, product information, etc in a JSON/XML format.

One of the many uses for this API will be mobile sales tracking apps, or mobile store UIs.

Initially, we're looking at incorporating the following features:

  1. Retrieve sale status for all products
  2. Retrieve earning stats for all products
  3. Retrieve 1 and 2 for individual products
  4. Retrieve sales for current day
  5. Retrieve earnings for current day
  6. Retrieve earnings / sales for any date / date range
  7. Retrieve status on customers (number / emails)
  8. Retrieve product information (name, description, price, etc)
pippinsplugins commented 11 years ago

Initially, the API will only provide GET methods, no methods for PUT.

pippinsplugins commented 11 years ago

Authentication (for GET methods) will be based on API key / email address.

evertiro commented 11 years ago

Started working on the base class for the API. I'll keep everyone updated as development continues.

evertiro commented 11 years ago

Any thoughts on where the API should be accessible?

pippinsplugins commented 11 years ago

It should be front and back, at least for the GET methods.

evertiro commented 11 years ago

You misunderstood the question. I meant in regards to URL structure

pippinsplugins commented 11 years ago

Whoops! I would say register a new URL endpoint for "edd-api".

evertiro commented 11 years ago

So we want to use edd-api. Ok! That's all I needed.

evertiro commented 11 years ago

Just to keep everyone up to date, the API initialization functions have been completed, and I'm about 50% done the key generation and management.

Additionally, the API is being designed as a class to make extension easy on anyone who want to...

pippinsplugins commented 11 years ago

Fantastic, thanks for the update!

Geczy commented 11 years ago

Why not just use authentication with WP shop admin credentials ?

pippinsplugins commented 11 years ago

Because that doesn't work nearly as well for things like mobile apps.

It's better to enter an API key in a mobile app than it is a username and password.

It is also more secure because if the API key gets stolen, then only thing the perpetrator can do is read data, whereas with an admin user account they can do anything.

Geczy commented 11 years ago

Good point ! :thumbsup:

It's not the combo of api key + email is it? Just api I hope?

pippinsplugins commented 11 years ago

It might be API + email, but not sure. @ghost1227 ?

evertiro commented 11 years ago

What's not the combo of api key and email? The access credentials for the API? If so, the answer is yes, unless someone gives me a better idea. As of now, it's set up such that you would pass parameters &username=&key= in order to authenticate.

Geczy commented 11 years ago

Well IMO, the better idea is to just use key=, without username.

Geczy commented 11 years ago

Do you have this on Github anywhere? Can we see what you have currently?

pippinsplugins commented 11 years ago

I have no issues with the username. The only argument for not including it I can see is it's simpler, but I don't think that's a good enough argument in this case.

Geczy commented 11 years ago

What's the argument to keep username? It seems useless.

pippinsplugins commented 11 years ago

More secure.

Geczy commented 11 years ago

How?

If the api key is compromised, it's logical to assume so is the username.

pippinsplugins commented 11 years ago

Not necessarily. Someone could get hold of the API key but not know the username. While a lot of the time they would have both, it's very safe to assume they could also have only gotten one. It's an extra level that can only help.

Geczy commented 11 years ago

Seems like a false sense of security to me :/

Most smaller APIs I know of only require an API key to function, eg rottentomatoes or something

Geczy commented 11 years ago

I think what'd be safer is to track API key usage in the backend.

pippinsplugins commented 11 years ago

No, it's not a false sense of security at all. It may not always make much difference, but there will absolutely be cases where it does. There is zero benefit to not using the username.

pippinsplugins commented 11 years ago

Tracking key usage would be great. I'd say we setup another view for the Logs page that shows API access usage.

evertiro commented 11 years ago

That sounds like a good idea, I'll add it to the list!

In response to the argument against usernames, it's technically possible (however unlikely) to brute-force a key. Managing to brute-force both key and username is almost impossible without knowing the username.

Geczy commented 11 years ago

I would rather see an 'api secret' than username, then. Something not personally identifiable on first glance if compromised.

Geczy commented 11 years ago

@ghost1227 could you respond to this one https://github.com/pippinsplugins/Easy-Digital-Downloads/issues/857#issuecomment-13566273

pippinsplugins commented 11 years ago

For an API secret, is that really just a separate API key? Similar to how Stripe works?

evertiro commented 11 years ago

In response to #857, it's not on Github yet, but will be posted to a branch on my fork of EDD as soon as I finish the core of the class.

evertiro commented 11 years ago

API key generation/revocation functions are done

pippinsplugins commented 11 years ago

902 has the initial code base.

There are several things to do still (beyond normal testing):

pippinsplugins commented 11 years ago

Todo:

mikeschinkel commented 11 years ago

Hey Pippin,

Before you distribute this you might consider posting an overview of your architecture to the API Craft mailing list. It's really easy to make arbitrarily-chosen architecture mistakes with APIs that haunt you for years and there is both some serious horsepower related to API design on that list and it's small enough and welcoming enough that people there are happy to hear about designs and to offer the expertise, mostly as a way to make sure the start of the art of web APIs keeps improving.

Just a thought...

mikeschinkel commented 11 years ago

Also, you might want to consider using the 'do_parse_request' hook instead of 'template_redirect' and 'query_vars' and add_rewrite_endpoint(). Your API doesn't and shouldn't run by the same rules as your content, and if you use 'template_redirect' WordPress is going to do a lot of work each API request that your API will just throw away. Do a preg_match() on $_SERVER['REQUEST_URI'] in 'do_parse_request' to decide if you want your API to handle a request or not. Take a look at lines Lines 27-28 as well as lines 258-266 to see an example in action, from this plugin.

pippinsplugins commented 11 years ago

@mikeschinkel Thanks for the link to the API Craft list. I've been reading through a lot of the links. Good stuff.

pippinsplugins commented 11 years ago

I'd say this is ready for some heavy testing. For those interested, here's how:

  1. Generate an API key from your WP Dashboard Profile editor page.
  2. Build a query string in the following format:
yoursite.com/?edd-api&user={your email}&key={your API key}&query={query mode}

The API accepts three query modes:

  1. customers To retrieve a list of all customers
  2. products To retrieve a list of all products + info for each product
  3. stats To retrieve sales and earnings stats

Each of the three modes has additional parameters that can be used to retrieve specific information as well:

_customers_

customer Used to retrieve info for a specific customer. This can be a user ID or email (must be an email if you want to retrieve info for a guest customer).

_stats_

type This determines the kind of stats you want to retrieve, either sales or earnings product The specific product to retrieve either sales or earnings stats for. If present, can be a product ID or all. date The date to retrieve earnings/sales for. Can be yesterday, today, or range. If range is used, then the following two parameters must also be specified:

The date parameters can not be used for specific products (yet).

_products_

product The specific product to retrieve info for. Must be a product ID.

The API also accepts a format parameter, which can be json (default) or xml.

A complete query looks like this:

http://localhost/wpms/?edd-api&user=pippin@pippinsplugins.com&key=fa3308eeaee3f78edf3deb1de754353f&query=products

Or like this:

http://localhost/wpms/?edd-api&user=pippin@pippinsplugins.com&key=fa3308eeaee3f78edf3deb1de754353f&query=stats&type=sales

Or:

http://localhost/wpms/?edd-api&user=pippin@pippinsplugins.com&key=fa3308eeaee3f78edf3deb1de754353f&query=stats&type=sales&product=10

Or:

http://localhost/wpms/?edd-api&user=pippin@pippinsplugins.com&key=fa3308eeaee3f78edf3deb1de754353f&query=stats&type=sales&date=range&startdate=20130205&enddate=20130415
pippinsplugins commented 11 years ago

The api-dev branch has been merged into master!

If anyone would like to see an example of what can be built with the new API, check this out (really great on mobile): http://dev.pippinsplugins.com/edd-stats/sales/?user=pippin%40pippinsplugins.com&key=cef3bb1b248928b19754d8be4de1b5ae

pippinsplugins commented 11 years ago

I noticed that we're allowing any user (if Allow User API Keys is enabled) to generate API keys, which would allow even basic subscribers to get read access to the API. This needs to be updated to only permit users with "view_shop_reports" caps to generate an API key.

chriscct7 commented 11 years ago

I agree with the limitation, but I have two concerns. The API is not just used for reports, it can be used for other things. Therefore, maybe it should be the store_manager cap instead.

Also, if I'm a plugin author, and I want to use the API (and correct me if I'm wrong), and I want to use it to dynamically generate the prices of a download, then the current user won't have this cap. So maybe certain areas of the API need different cap limits?

On 2/24/13, Pippin Williamson notifications@github.com wrote:

I noticed that we're allowing any user (if Allow User API Keys is enabled) to generate API keys, which would allow even basic subscribers to get read access to the API. This needs to be updated to only permit users with "view_shop_reports" caps to generate an API key.


Reply to this email directly or view it on GitHub: https://github.com/pippinsplugins/Easy-Digital-Downloads/issues/857#issuecomment-14013892

pippinsplugins commented 11 years ago

At the moment the API only contains stat/report-related info (with the exception of product info), so "view_shop_reports" works well.

I like the idea of setting cap checks for each area of the API. For example, the product info could require a much lower cap, but would only reveal sale/earnings info to users with a high cap.

pippinsplugins commented 11 years ago

Since it's very possible for a store to have hundreds of products, retrieving all products (or customers) wasn't a good idea. I've added a couple of helper functions and pagination for all queries.

You can now control the number of results shown per page by adding &page=# to the query. The number of items shown per page is controlled with &number=#.

pippinsplugins commented 11 years ago

Need to read through this before we consider this finished: http://info.apigee.com/Portals/62317/docs/web%20api.pdf

pippinsplugins commented 11 years ago

I've just pushed up an update to simply things a little.

Instead of doing this:

http://localhost/wordpress/edd-api/?user=pippin@pippinsplugins.com&key=7ede50bc7b8264b15bad22475bf2a0ce&query=customers

One will simply do this:

http://localhost/wordpress/edd-api/customers?user=pippin@pippinsplugins.com&key=7ede50bc7b8264b15bad22475bf2a0ce

Instead of explicitly passing a query parameter, we simply use the value of edd-api to set the query mode. This makes it simpler and more intuitive.

In the same way that we would expect a site to use /customers, /products, etc, the API now does the same this:

sunnyratilal commented 11 years ago

After the rewrite endpoint is added, flush_rewrite_rules() should be added because when I went in and enabled the API keys to be generated from EDD settings and then generated one, I tried accessing the edd-api and it resulted in 404. Had to go into Settings > Permalinks and hit Save Permalinks.

pippinsplugins commented 11 years ago

@sunnyratilal Already noted #969

sunnyratilal commented 11 years ago

Whoops, didn't see that! :)

On Friday, 8 March 2013, Pippin Williamson wrote:

@sunnyratilal https://github.com/sunnyratilal Already noted #969https://github.com/pippinsplugins/Easy-Digital-Downloads/issues/969

— Reply to this email directly or view it on GitHubhttps://github.com/pippinsplugins/Easy-Digital-Downloads/issues/857#issuecomment-14642955 .

pippinsplugins commented 11 years ago

We should add also "predefined dates" to the stats query:

pippinsplugins commented 11 years ago

The numerical index needs to be removed from customers:

 "0": {
    "info": {
        "id": -1,
        "username": "Guest",
        "display_name": "Guest",
        "first_name": "Guest",
        "last_name": "Guest",
        "email": "johnson@test.com"
    },
    "stats": {
        "total_purchases": 2,
        "total_spent": "20",
        "total_downloads": 0
    }
},
"1": {
    "info": {
        "id": -1,
        "username": "Guest",
        "display_name": "Guest",
        "first_name": "Guest",
        "last_name": "Guest",
        "email": "asda@test.com"
    },
    "stats": {
        "total_purchases": 0,
        "total_spent": "0",
        "total_downloads": 0
    }
},