colymba / silverstripe-restfulapi Goto Github PK
View Code? Open in Web Editor NEWSilverStripe RESTful API with a default JSON serializer.
License: BSD 3-Clause "New" or "Revised" License
SilverStripe RESTful API with a default JSON serializer.
License: BSD 3-Clause "New" or "Revised" License
I'm wondering if there are examples of retrieving data that relates to the currently authenticated member (via log in then using token). For my app I want to get list of all the 'logs' link to a member via a has_many relationship.
A populated relation might look like this when serialized:
"myRelation": [1, 5, 6]
If that relation contains no children, the "myRelation" key is entirely missing from the serialized data, but it should be:
"myRelation": []
Might be easily fixed by removing the check on RESTfulAPI_BasicSerializer.php:L209?
I am using your extension to provide JSON to some jPlayer instances. The JSON returned from the api calls rarely changes. Would it be possible to provide a way to cache a GET request's JSON so we don't have to run the db queries and create the JSON if it hasn't changed from the cache?
Hi,
I can't get the authentication to work. It's keep saying "Token invalid" when i type in 'api/Model/id'. What am i missing?
Here's my config file:
SSViewer:
theme: 'simple'
# API access
TherapyGroup:
api_access: true
Patient:
api_access: true
Therapist:
api_access: true
Exercise:
api_access: true
Message:
api_access: true
# RestfulAPI config
RESTfulAPI:
authentication_policy: true
access_control_policy: 'ACL_CHECK_CONFIG_ONLY'
dependencies:
authenticator: '%$RESTfulAPI_TokenAuthenticator'
cors:
Enabled: true
Allow-Origin: '*'
Allow-Headers: '*'
Allow-Methods: 'OPTIONS, GET, POST, PUT'
Max-Age: 86400
embedded_records:
Patient:
- 'Exercises'
- 'Therapist'
- 'TherapyGroup'
- 'Messages'
Exercise:
- 'Messages'
RESTfulAPI_TokenAuthenticator:
tokenOwnerClass: 'Member'
Member:
extensions:
- RESTfulAPI_TokenAuthExtension
Do you know the solution? Thanks in advance.
I will be doing it soon, just for my control
if any colmun name has a trailing "ID" at the end of its name it will be removed wheither or not it is a $has_one relation.
We only want this for $has_on relations
Using this module :
https://github.com/flashbackzoo/silverstripe-angularjs-modeladmin
Product has a validation method, where the DO needs to have a ProductCatalogID.
When using the API to create a DO this will always fail, since before populating the DO with the passed data, an empty DO is written in RESTfulAPI_DefaultQueryHandler::createModel();
Also the validation error message just returns a 500 code without the validation message.
The current API error payload doesn't match the ember json-api specification. Here's how it currently looks:
{message: "Token expired.", code: 3}
Here's how it should look:
{ errors: [{ title: "Token expired.", code: "3", status: 403 }] }
Ember Data supports polymorphic relations. Here's a presentation (slides) that explains some of the concepts (some of the issues discussed there are resolved nowadays).
To properly support polymorphic relations, the JSON output has to be type hinted. Eg. a has_many
relation would change from:
shapes: [1, 3, 4]
to:
shapes: [
{ "id": 1, "type": "triangle" },
{ "id": 3, "type": "rectangle" },
{ "id": 4, "type": "triangle" }
]
Another issue is sideloading of records. Instead of having:
shapes: [ <shapes payload> ]
the sideloaded data has to be separated by polymorphic type. Eg.
triangles: [ <triangles payload> ], rectangles: [ <rectangles payload> ]
_id
and _ids
do not exist anymore and relations are stored in links
attribute etc http://jsonapi.org/format/
Im still pretty new to silverstripe so maybe Im missing some fundamentals? Surely this pattern or something similar has been done before but I would like to be able to implement a registration page. So for a new user to create a profile in order to login. At this point in the journey he (the user) would not have a token but would require one only after registering and a new member has been created.
I would like to be able to create a new member by posting to a url: "http://mysite.local/api/Member" with data like : {"FirstName":"test1"}.
When I try the above I get a "Token invalid" response.
Heres the config.yml:
RESTfulAPI:
authentication_policy: true
access_control_policy: 'ACL_CHECK_CONFIG_ONLY'
dependencies:
authenticator: '%$RESTfulAPI_TokenAuthenticator'
cors:
Enabled: true
Allow-Origin: '*'
Allow-Headers: '*'
Allow-Methods: 'OPTIONS, GET, POST, PUT'
Max-Age: 86400
RESTfulAPI_TokenAuthenticator:
tokenOwnerClass: 'Member'
Member:
api_access: 'GET,POST,PUT'
extensions:
- RESTfulAPI_TokenAuthExtension
Member::canLogIn
should be checked before logging in a user.
This will prevent that locked out users can login in any form.
Subclasses currently inherit API access from parent class. Make api_access uninherited.
See #41
If querying /companies/0
instead of returning a record or empty response this returns all Companies like /companies
would.
has_one
relation should be removed from the response to avoid the problem altogether (for now it returns relation: 0
).Do you have any plans to implement login/logout? Would be nice for JS SPAs that require authentication.
Use $obj->extend('onBeforeSerializeObject');
https://github.com/colymba/silverstripe-restfulapi/blob/master/doc/BasicSerializer.md
Here is stated that you can remove fields from an object.
It's not clear to me how to remove fields without changing th static $db array?
Stepping through the Basic Serializer, it seems like $embeddedRecords is getting set from configuration. Is it possible to provide an example YAML configuration for this setting in the docs?
Config::inst()->get( $dataObject->ClassName, 'has_one', Config::INHERITED )
will return null if none (even empty) are explicitly set on the dataObject.
Make sure to fallback to empty array
When serializing data, there's a callback onBeforeSerialize
and onAfterSerialize
which allows a developer to control what gets sent to the client.
I'm missing something similar in the case of updating records, where I'd love to inspect incoming payload before writing it to the DataObject.
Imagine a DataObject which has some fields that should not be allowed to be modified via REST. Of course I can hide the fields from being serialized, but with proper knowledge of the system, a request could still contain field values which are undesirable.
Let's assume the following:
MyDataObject
AllowedProperty: Varchar
has_one: Member
A user could PUT another Member ID to the DataObject, because there's currently no way for a developer to prevent updating of fields that shouldn't be updated via the REST API. Writing a onBeforeWrite
hook is cumbersome and affects all writes (not only the ones via REST API)
I'd propose something like this in RESTfulAPI_DefaultQueryHandler.php (Line 412)
if( method_exists($model, 'onBeforeApplyPayload') )
{
$model->onBeforeApplyPayload($payload);
}
$model->extend('onBeforeApplyPayload');
A developer could then sanitize incoming data if neede.
I'd be interested in your thoughts about this. Can create a PR if wanted.
login
if ( !$email && !$pwd )
{
$body = parse_str( urldecode($body), $bodyData );
if ( $bodyData['email'] ) $email = $bodyData['email'];
if ( $bodyData['pwd'] ) $pwd = $bodyData['pwd'];
}
Add various examples to the doc:
onBeforeSerialize
and onAfterSerialize
. See #23, #26RESTfulAPI_DefaultQueryHandler
for more complex handleQuery
. See #25, #17Hi Colymba,
Awesome work on this silverstripe module.
One question, is it possible to access public methods from a dataobject?
I would like to see the 'fullname' in my /api/students/ GET request. I'm aware that PUT, POST and DELETE obviously won't work.
class Students extends DataObject {
private static $db = array(
'firstname' => 'Varchar',
'lastname' => 'Varchar'
}
public function fullname() {
return $this->firstname . ' ' . $this->lastname;
}
public static $allowed_actions = array(
'fullname'
);
}
I tried to use onBeforeSerialize, but somehow I can't get it to work.
Thanks
I have a CalendarItem with a $has_one = array('Thumbnail' => 'Image', 'Image' => 'Image');
In my _config.php, I am attempting to add embedded_records to the RESTfulAPI via config: Config::inst()->update('RESTfulAPI', 'embedded_records', array('CalendarItem' => array('Thumbnail', 'Image')));
I added $api_access to the Image class via extension. Everything works for the 'Image' relation, but I get an Injector error for the 'Thumbnail' relation:
ERROR [User Error]: Uncaught ReflectionException: Class Thumbnail does not exist
Not sure if my syntax is incorrect or if I am doing something incorrectly.
Seem that queries with ?__limit affect the number of sideloaded records too.
so... everything like function(string $var)
should be function($var)
at the moment only filter()
is used. Implement filter
and exclude
and maybe even substract
.
Maybe use: ?filter[]=Column__Modifier:Value&exclude[]=Column__Modifier:Value
Multiple search filters modifiers should also possible like 'FirstName:StartsWith:Not'
Hi,
I just tried out your EmberDataSerializer and stumbled over an issue within Silverstripe. Considering your config.yml file I assume that you don't really have used the silverstripe CMS anymore and just got the data for your ember client!?
The issue is that, when I work with the Pages and Holder structure within Silverstripe, and I externally update such a page, it won't be published/getting live.
I tried to call doPublish() in the RESTfulAPI_DefaultQueryHandler's updateModel($model, $id, $request) function (right next to the $model->write(...) call ) , but this doesn't seem to tackle the problem. Do you have any idea regarding this!? How did your according Silverstripe structure look like!?
Nevertheless, thanks a lot for contributing this so far.
Cheers Dario
A new blank record is inserted after detection of malformed json payload. Please give a full example of an expected payload with more than one relationship.
Using SSHTTP_Response->output()
breaks UnitTest since output already occurred. Use Director::is_cli()
to return response instead:
if( Director::is_cli() )
{
return $answer;
}
else{
$answer->output();
exit;
}
Add Versioned to query handler via URL param. E.g. https://github.com/crdschurch/SS-CMS/commit/ce6227ecc58f586be116bb3d14e8fda00b580725
Hello there, first off I want to thank you so much for creating this great silverstripe addon. I'm quite new to silverstripe (only on my second or third week using it) but I had no issue setting up the basic api with basic permissions. Very well done. Next I just to ask you some questions to help me get the token authentication setup in the way I need it. Please forgive me for anything simple that I might not understand, this is the first RESTful API I have setup with tokens so I'm a bit of a newbie. On to the questions:
RESTfulAPI:
authentication_policy: true
dependencies:
authenticator: '%$RESTfulAPI_TokenAuthenticator'
ApiUser:
extensions:
- RESTfulAPI_TokenAuthExtension
RESTfulAPI_TokenAuthenticator:
tokenOwnerClass: 'ApiUser'
and used the api/auth/login?email=*my-email*&pwd=*my-pass*
url (which just returns []
).
extensions:
- RESTfulAPI_TokenAuthExtension
code to the Members model instead of the ApiUser model. What is the benefits of applying it to ApiUser?
3.For the site I am creating we would like to have a system similar to google+/facebook/twitter where the user goes into there settings screen(or in our case into the CMS) to create a API token. This token would then be used by our users in their applications,websites, or apps to to connect and retrieve data through our API. Is this possible to create with your addon? If so could you perhaps give me some code to get me started.And if it is not possible with your addon could you recommend to me another addon that might suite my needs?
Thank you in advance,
Mooror
Hi,
thank you for the module. Its working great so far.
However I would like to make custom methods (e.g. of Controllers) accessible via REST.
Can this be done as well?
I see that something can be done with api/acl/ but not sure how this can be configured.
Thx
Andy
implement a version of isAPIEnabled
on serializers
Can you set access to certain models via a config setting - like the $api_access static on the silverstripe restfulserver module?
Response header content-type should be application/vnd.api+json
Returning malformed parameters in error-messages opens a door for XSS attacks.
If the "model" or "ID" parameter contains malicious code and a developer displays error-messages in his application, there's the potential for an XSS attack.
Use case would be a shopping cart holding items with various quantity. The quantity being a $many_many_extraFields
Hey ya! Thanks for all the great work :)
I'm trying to POST a object with a belongs_many_many relationship but I'm not sure how to do this
{
ID: 2,
Title: "Henry's Playlist",
Devices: [
2
]
}
What should the POST preview look like in my Network inspector?
This should be added to the default config.
See #66
$queryParams should be parsed and validated before executing against database.
On GET request for filtered data if one modifier value is empty server responds with the full result set.
api/model?Title__StartsWith=
For more robustness this should result in a 400 Bad Request.
Similarly,
api/model/?URL__StartsWith=
Results in a 500 Internal Server Error.
Hi,
I am using translatable and translatable-dataobject to localize my site.
Does this addon support localized (multi-language) sites?
Thanks
I admit that it's an edge case, but with the current implementation, the uniqueness of an API token can't be guaranteed.
There are two scenarios where this could be a potential problem:
I'll send a pull request that will fix the issue.
empty result return {"class":"DataList"} instead of properly formatted empty JSON (EmberDataSerializer)
I'm trying to access the Member model in the API but am just getting API access denied. All other models are working perfectly fine. See config below:
Member:
api_access: true
Subscriber:
api_access: true
Subscription:
api_access: true
Product:
api_access: true
RESTfulAPI:
authentication_policy: true
access_control_policy: 'ACL_CHECK_CONFIG_ONLY'
dependencies:
authenticator: '%$RESTfulAPI_TokenAuthenticator'
cors:
Enabled: true
Allow-Origin: '*'
Allow-Headers: '*'
Allow-Methods: 'OPTIONS, GET, POST, PUT'
Max-Age: 86400
RESTfulAPI_TokenAuthenticator:
tokenOwnerClass: 'Member'
autoRefreshLifetime: true
Member:
extensions:
- RESTfulAPI_TokenAuthExtension
use .htaccess proxy:
RewriteRule ^api(.*)$ http://NEWHOST.COM/api$1 [P,L]
Hi
I am trying to handle images via your API. I can read the API fine and get a URL to the image but trying to create a new image via a POST request doesn't seem possible?
I have my image in base64 format but not sure how to post this to the API?
I assume this isn't built in behaviour so I need to upload it via a custom ACL method? Do you have an example for how I create a custom method?
Thanks
I created a pull request that enables auto-refreshing tokens (#38).
While this addition adds convenience, it worsens the application security. Having a token that expires within a reasonable amount of time gives a potential attacker less time to do damage.
The client gets the token expiry when logging in. It should be the responsibility of the client-application to issue a token refresh when the token is about to expire.
Issuing a token-refresh should not use the regular access-token, since it would enable the attacker to completely take over access.
So there are two approaches for a token-refresh:
I would propose the following changes to the RESTful API
RefreshToken
to RESTfulAPI_TokenAuthExtension
api/auth/login
), generate a RefreshToken
and the regular access-token and pass both back to the client.api/auth/refreshToken
which has to be called by the client when the access-token is about to expire. The client has to submit the obtained RefreshToken
and gets a new access-token in return.I'd gladly create a PR for this if you agree that this would be a worthwhile addition.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.