# laravel response and API resouce
https://hackmd.io/@javck/ByJgF8HRP/%2F0IRl5OAZRyiOJas4bfcvfA
## rsponse 附加錨點

https://www.youtube.com/watch?v=CeL-W_Ap1Ls
## 序列化
當模型或集合被轉型成字串時,會轉換成 JSON 格式,所以你可以直接從應用程式的路由或者控制器回傳 Eloquent 物件:
```
Route::get('users', function () {
return App\User::all();
});
```
之前別人用present 用blade 轉string就是用這個
將模型轉換成一個陣列
如果要將模型還有它載入的關聯轉換成一個陣列,你可以使用 toArray 方法。這個方法是遞迴的,因此,所有屬性和所有關聯(包含關聯中的關聯)都會被轉換成陣列:
```
$user = App\User::with('roles')->first();
return $user->toArray()
;
```
所以resource api的 map原理
當模型或集合被轉型成字串時,會轉換成 JSON 格式,所以你可以直接從應用程式的路由或者控制器回傳 Eloquent 物件:
```
Route::get('users', function () {
return App\User::all();
});
```
## 注意 地雷
當你resource出來 裡面資料是看不到的
因為它是會轉成json
所以你dd看不出來
但json_decode就能變出來
不然就在blade用@json
## 更優雅的細節
author可以合併
原本

簡化

作法
寫fumction


**更棒的作法**
使用collection

## cache
https://www.youtube.com/watch?v=vrLcCxWlxOk
不用一直重複撈取

## 限制次數

## 同一個api回應 不同結果
https://www.youtube.com/watch?v=MxQJlFUYO30
第一使用when

因為request會在toArray裡面 本來就有了
多字串的話

也可以用whenAppend

但在controller要寫

## 送api
guzzle 7板之後可以用facade的http取代
https://laracasts.com/series/whats-new-in-laravel-7/episodes/5
$url = http:sdwdqwds;
`Http::get($url)->josn();`
等於
```
json_decode($this->guzzle()->get($url)->getBody());
```
轉josn更快 也不用body了
https://laracasts.com/series/whats-new-in-laravel-7/episodes/5
如果是html
就跟postman一樣head要加東西

## API 資源:有或沒有“數據”?
如果您使用 Eloquent API Resources 返回數據,它們將自動包裝在 'data' 中。如果你想刪除它,添加`JsonResource::withoutWrapping()`;在`app/Providers/AppServiceProvider.php`。
```
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
JsonResource::withoutWrapping();
}
}
```
## API 返回“一切順利”
如果您有執行某些操作但沒有響應的 API 端點,因此您只想返回“一切順利”,您可能會返回 204 狀態代碼“無內容”。在Laravel,很容易:`return response()->noContent();`。
```
public function reorder(Request $request)
{
foreach ($request->input('rows', []) as $row) {
Country::find($row['id'])->update(['position' => $row['position']]);
}
return response()->noContent();
}
```
## posman不想出現html錯誤 想用json格式的
這種

不要這種

在header加上兩個

這樣他就知道你要你要json
## resouce用的 this
$this是參照到目前的object ( 已經被宣告的實體上 )
所以這才能用this
## 限定返回資料
php函数名后冒号+数据类型(返回值类型限制/php新特性)(只有在php 7以上才能用)
https://blog.csdn.net/dianpujiu5323/article/details/101285711

## 返回會json
https://docs.laravel-dojo.com/laravel/5.5/responses
字串與陣列
所有路由與控制器應該回傳一個回應到使用者的瀏覽器。Laravel 提供幾個不同的方式來回傳回應。最基本的回應是只從路由和控制器中回傳一組字串。Laravel 會自動將字串轉換成完整的 HTTP 回應:
```
Route::get('/', function () {
return 'Hello World';
});
除了從路由和控制器中回傳字串,你也可以回傳陣列。Laravel 會自動將陣列轉換成 JSON 回應:
Route::get('/', function () {
return [1, 2, 3];
});
```
`只有在 return情況下`
Eloquent collections
arrays
string
集合 collection
https://laravel.com/docs/7.x/responses#creating-responses
**原理是這些裡面原本就有toarray可以轉換 要追回去 可看影片 248
但不可能只返回這些
所以要
```
return response()->json([
'status' => 200,
'data' => [
'meta' => SongModel::find($songID)
]
]);
```
但這也太麻煩 有**兩大缺點**
**重複的格式定義**: 類似的 endpoint 可能都有類似的格式定義,可是卻散落在 Controller 各處。
**format 不固定**: 因為是直接將 model 輸出,如果資料表有更動的話,API 會直接受到衝擊。
## JSON 回應
json() 會自動將 header 的 Content-Type 設定為 application/json,同時使用 PHP 的 json_encode() 將傳入的陣列轉換為 JSON
```
return response()->json([
'name' => 'Abigail',
'state' => 'CA',
]);
```
假如你想要生成一個 JSONP 回應,你可以在 json() 後面再接一個 withCallback()
```
return response()
->json(['name' => 'Abigail', 'state' => 'CA'])
->withCallback($request->input('callback'));
```
## 型別轉換 跟 Eloquent: 序列化
兩個差別 雖然都是轉換 但對象不同 model相關 一個是單個的

這叫單個
https://www.jollen.org/php/jollen_php_book_6_php.html
1. (int),(integer) - 轉換成 integer 型別
2. (bool),(boolean) - 轉換成 boolean 型別
3. (float),(double),(real) - 轉換成 float 型別
4. (string) - 轉換成 string 型別
5. (array) - 轉換成 array 型別
6. (object) - 轉換成 object 型別
https://laravel.tw/docs/5.2/eloquent-serialization
如果要將模型還有它載入的關聯轉換成一個陣列,你可以使用 toArray 方法。這個方法是遞迴的,因此,所有屬性和所有關聯(包含關聯中的關聯)都會被轉換成陣列:
`$user = App\User::with('roles')->first();`
return $user->toArray();
你也可以將集合轉換成陣列:
```
$users = App\User::all();
return $users->toArray();
```
將模型轉換成 JSON
如果要將模型轉換成 JSON,你可以使用 toJson 方法。如同 toArray,toJson 方法也是遞迴的,所以,所有的屬性以及關聯都將被轉換成 JSON:
```
$user = App\User::find(1);
return $user->toJson();
```
或者,你可以強制把一個模型或集合轉型成一個字串,它將會自動的呼叫 toJson 方法:
```
$user = App\User::find(1);
return (string) $user;
```
當模型或集合被轉型成字串時,會轉換成 JSON 格式,所以你可以直接從應用程式的路由或者控制器回傳 Eloquent 物件:
```
Route::get('users', function () {
return App\User::all();
});
```
**這邊踩個小雷**

雖然是用find找
但關聯會變collection
所以resource要記得用collection的方法
--------------------------------
-----------------------------
由於 Resource 是繼承自 JsonResource,因此輸出就會是 JSON 的格式內容,而我們要做的就是修改 toArray() method 當中的格式:
用new 的原因是要實體化 之前::都是調用class的靜態方法
靜態方法可以不實體化就調用 但他會直接站記憶體 簡單來說就是
一般物件成員 變 類別成員
當我new一個resource的時候 他原生涵式return是這樣
`return parent::toArray($request);`
所以當你傳入ex $post->comment;之類的 他會幫你區分 是不是data 還是...等
影片說是會有連結跟集合區分 還沒測試
-------- 注意的地方
如果日期之類的被轉成物件 請用(string)轉回來
---
這邊有個要注意點的點 這邊名子也是自己打 所以錯了顯示也是錯 我覺得可以用tinker抓出來直接複製屬性名 比較保險
---
## collection
如果你今天不是傳一個是用all() 或get()
用 return Commnet::collection($post->all());
去掉用resoucr原本的靜態方法把collection列出來
**Resource::collection() 使用,它會將 Collection 中的所有 Model 物件自動套用 Resource 的格式**
https://blog.johnsonlu.org/laravel-eloquent-api-resources/
如果想調用關聯的屬性 可在 return直接用
```
'id'=>$this->id
'comment'=>$this->id
```
**集合分頁**

## 查詢特定的
https://ithelp.ithome.com.tw/articles/10220567
Model寫一個方法,名稱命名為 get某某某Attribute 例如 getAgeAttribute。必須用駝峰式的命名方式,如果我要取得Animal這個物件並想要的到age的值,會訪問這個方法,並依造你的程式回傳對應的值
```
public function getAgeAttribute()
{
$diff = Carbon::now()->diff($this->birthday);
return "{$diff->y}歲{$diff->m}月";
}
```
## 條件載入 重要 防止lazy loading
有條件的關聯
除了載入有條件的屬性外,你可能會根據關聯是否已經載入到模型上,而有條件的在你的 資源回應中引入關聯。這可以讓你的控制器決定應該載入哪一個關聯到模型上,並讓你的資源能輕易的在它們確實要被載入時引入它們。
最終,這麼做可以較容易避免在你的資源中發生「N+1」的查詢問題。whenLoaded 方法可以被用於有條件的載入關聯。為了避免不必要的載入關聯,這個方法可以接受關聯名稱,而非關聯本身。
* 將資源轉換成陣列。
```
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'posts' => Post::collection($this->whenLoaded('posts')),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
```
在本範例中,如果關聯沒有被載入,在它被傳送到客戶端前,posts 鍵會從資源回應中被完全刪除。
## 終極寫法

用collection包 resource
不然你原本還要跑foreach
但如果變數命名
$collects對上reourse他就可以直接幫你跑
很有感覺但沒有很懂
resorce collection底層
AbstractPaginator這個是分業的底層抽象
```
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Illuminate\Pagination\AbstractPaginator;
class BaseResourceCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
*
* @return array
*/
public function toArray($request)
{
return $this->resource instanceof AbstractPaginator ? [
'data' => $this->collection,
'current_page' => $this->currentPage(),
'last_page' => $this->lastPage(),
'per_page' => $this->perPage(),
'total' => $this->total(),
] : parent::toArray($request);
}
}
```
很屌 因為原本就有
parent::toArray($request)
所以你父只要直接設定變數就好
## api delete

noComment是204 剛好就是刪除
###### tags: `Laravel`