Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Item envelope in \yii\rest\Serializer #7534

Closed
fcaldarelli opened this issue Mar 2, 2015 · 21 comments
Closed

Item envelope in \yii\rest\Serializer #7534

fcaldarelli opened this issue Mar 2, 2015 · 21 comments

Comments

@fcaldarelli
Copy link
Member

Hi all,
this is a possible improvement (not a bug).

I think that if I use collection evelope "items" in serializer, it could be useful to have single item envelope, as "item". In this way i'll have same structure of response.

Now i make this functionality extending ActiveController's actions() in this way:

    $actions['view'] = [
        'class' => 'api\components\CustomViewAction',
        'modelClass' => $this->modelClass,
        'checkAccess' => [$this, 'checkAccess'],
    ];

So in CustomViewAction i have

public function run($id) {
    $model = $this->findModel($id);
    if ($this->checkAccess) {
        call_user_func($this->checkAccess, $this->id, $model);
    }
    return ['item' => $model];
}

In this way i have single item or many items response in same way, using an envelope.

At the end, in $serializer's controller variable should be:

public $serializer = [
    'class' => 'yii\rest\Serializer',
    'collectionEnvelope' => 'items',
   'singleEnvelope' => 'item'
];
@cebe
Copy link
Member

cebe commented Mar 4, 2015

why would you need an envelope for a single item?

@fcaldarelli
Copy link
Member Author

Mainly for two reasons: first to have a normalized answer between multiple and single response, first with "items" and last with "item"; second reason is to have a container for all fields of item, so if i had extra field to send as answer i can add it to response without mixing with item's field.

@eaglemoor
Copy link

Single item it's a single item. We get him from same url and we know what type object we ask.
Maybe it's need for socket, because in socket we have asynchronous requests and don't have url.

I developed rest api 1 year for android & iOS. I try use "item" for Single item, but this and problem on mobile device. For parsing "root" element (as in xml) whey need use same class.

If we have collection with pagination

{
  "users": [],
  "_links": {},
  "_meta": {}
}

Whey need create 4 class: UserCollection (root), User (item of user), Links, Meta.
UserCollection have rules for parsing "users" as Array of User. It's justified because we have a lot of objects in root object.
If we have one item with key

{
  "users": {}
}

Whey need use UserCollection (root) and User (user) object too.

But if we write Single object without key

{
 "id": 124,
 "login": "User1"
}

Whey need use only one class User (like a root).

I hope that answered your question. =)

@fcaldarelli
Copy link
Member Author

If i want to add extra data, as photos link or attached files link, i need into fields of item. Instead if I had item property, i'll can add extra property, as "photos" link or "attached_files"

@eaglemoor
Copy link

Why?

public function extraFields()
{
  return ['photos', 'profile'];
}

public function getPhotos()
{
  return $this->hasMany('app\models\Photos', [...]);
}

public function getProfile()
{
 return $this->hasOne('app\models\Profile', [...]);
}
{
  "id": 124,
  "login": "User1",
  "photos": [],
  "profile": {}
}

and android & iOS parsing it's good. User (root), array Photo (from 'photos'), Profile (profile)

@fcaldarelli
Copy link
Member Author

Because in general there could be situations where i could pass other fields then item's.
I like to have a container where i find all item's field.

@eaglemoor
Copy link

Please, write json with example what you wand do.

@fcaldarelli
Copy link
Member Author

I think in general. If you think, "item" envelope is same of form's params envelope using model class name.

Infact in form you use, for example, $_POST['Item_class'] envelope to group item's fields.

@eaglemoor
Copy link

$model->load($_POST) // Load from form $_POST['modelClassName']
$model->attributes = $_POST // Load form $_POST

$model->load get data by 'modelClassName' and use $model->attributes

@fcaldarelli
Copy link
Member Author

Exactly, so we use an envelope (class name) to group item's fields.

So i think that it is correct to do also retrieving item's fields from json.

@eaglemoor
Copy link

But no need envelope one item, because you know what object you get by url.

Can i ask, you develop on AngularJS?

@fcaldarelli
Copy link
Member Author

Anyway, i always use extra envolope "item" because i send in response also a "status" property, where i put extra data as "error message", sent to display on (mobile) device alert text. So i can change extra data without update my apps.

Sure, i develop on Angular JS.

@eaglemoor
Copy link

Please, don't try update all things to angular js logic =)))))))))
We have many problem on job with angular programmer on this logical =)

If you insert "status" field, this is not singleItem. You can update your Serialize class for generate "status" key and other for your project, but it's custom login, not for all.

You don't need send "status", you can read Header code. Always all data is good. If you need send error use Exception.

public function actionAuth ($login, $password)
{
    $modelClass = $this->modelClass;
    $user = $modelClass::findByLogin($login);
    if (!$user) {
        throw new UnauthorizedHttpException("User with login, email or phone not found", 1);
    }
    ....
}
HTTP 401
{
    "name": "Unauthorized",
    "message": "User with login, email or phone not found",
    "code": 1,
    "status": 401,
    "type": "yii\\web\\UnauthorizedHttpException"
}

If HTTP code != 200 or 204 (on create) parser data as ErrorObject

Send "status" and other "help" field for 200 code it's a custom login for yii1. Yii2 have a good tools for throw Exception and HTTP code for this.

@fcaldarelli
Copy link
Member Author

I don't understand your

Please, don't try update all things to angular js logic =)))))))))
We have many problem on job with angular programmer on this logical =)

I think that is more readable insert status property inside json response. But this is my way to work, when i develop in team we establish common way to work.

@tunecino
Copy link
Contributor

I agree the no need to envelope single item but some frontend rest services or resolving libraries are expecting an envelope for single resource object as described in jsonapi.org
(see: http://jsonapi.org/format/#document-top-level).

angular-restmod is one of those libraries following jsonapi.org style APIs and as described in its docs (see: http://platanus.github.io/angular-restmod/tutorial-integration.html#q2) is expecting no envelops by default or will expect a plural plus a single resource envelope when using it's DefaultPacker.

Unless you override some of its methods or build a custom packerStyle to support Yii2 Rest API style, I think it will be nice to add more flexibility to \yii\rest\Serializer and leave this kind of choices to developer specially if it will not change the default \yii\rest\Serializer response.

I just made a pull request for it in case you agree with me.

@acorncom
Copy link
Contributor

I think it will be nice to add more flexibility to \yii\rest\Serializer and leave this kind of choices to developer specially if it will not change the default \yii\rest\Serializer response.

👍 I wonder if it would be worth having a \yii\rest\JSONAPISerializer in addition to the base \yii\rest\Serializer? The JSON-API spec gets pretty detailed and there are a number of assumptions that it might be nice to have the serializer handle instead of having a bunch of developers building their own partial implementations ...

/cc @creocoder ?

@fcaldarelli
Copy link
Member Author

Questo è un messaggio automatico per dirti che sarò in ferie fino a lunedì 26 ottobre, giorno in cui tornerò nuovamente operativo.

Si prega quindi di ricontattarmi dopo tale data.

Saluti e buon proseguimento!


This is an automatic message to tell you that I'll be in holyday until the 26th of september.

Write me after that date.

Best regards!

@creocoder
Copy link
Contributor

@tunecino
Copy link
Contributor

@acorncom #10968

@Deele
Copy link
Contributor

Deele commented Apr 20, 2017

Single resource envelope is useful when I want to have links and/or meta data inside response.

For example, item is in this case envelope for multi-lingual Article resource and developer has intent to provide an article language in meta data and inform requested that there is a publish function availible for this specific resource, by providing link to publish action:

{
  "item": [],
  "_links": {
    "self": {
      "href": "http://localhost/api/articles/1?language=en"
    },
    "publish": {
      "href": "http://localhost/api/articles/1/publish"
    }
  },
  "_meta": {
    "language": "en"
  }
}

Currently, there is no built-in way to add custom links or custom meta data for resource collections, not even for single resources.

@samdark samdark added this to the 2.0.14 milestone Apr 20, 2017
@samdark samdark modified the milestones: 2.0.14, 2.1.1 Feb 3, 2018
@yii-bot
Copy link

yii-bot commented Apr 5, 2018

Issue moved to yiisoft/yii-api#12

@yii-bot yii-bot closed this as completed Apr 5, 2018
@cebe cebe removed this from the 2.1.1 milestone Apr 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants