Project

General

Profile

Δημιουργία API calls

Βασικά αρχεία και φάκελοι
  1. app/Http/routes.php
    Σε αυτό το αρχείο κάνουμε register τα routes στους αντίστοιχους controllers και τις αντίστοιχες μεθόδους.
  2. app/Http/Controllers/Api/V1
    Σε αυτόν το φάκελο βρίσκονται όλοι οι controllers που αφορούν το API
  3. app/Http/Controllers/Api/V1/Transformers
    Σε αυτόν το φάκελο βρίσκονται οι κλάσεις που είναι υπεύθυνες για τον μετασχηματισμό των ονομάτων των column της βάσης.
  4. app/Models
    Σε αυτόν τον φάκελο βρίσκονται τα Eloquent Models (Laravel ORM)
  5. app/Repositories
    Σε αυτόν το φάκελο βρίσκονται τα repositories μας (Επειδή στο μέλλον θα θέλουμε τα queries τόσο για το API όσο και για την πλατφόρμα να βρίσκονται σε ένα μέρος, ακολουθούμε το Repository Design Pattern. Με απλά λόγια εδώ υλοποιούνται μέθοδοι που εκτελούν queries είτε χρησιμοποιώντας τα eloquent models είτε με οποιονδήποτε άλλο τρόπο).

Παράδειγμα Workflow για Courses REST Api

Θέλω να δημιουργήσω 2 REST calls
  • GET api/v1/courses
  • GET api/v1/courses/{course_code}

1. Δημιουργώ έναν RESTful controller για τα Courses πληκτρολογώντας

php artisan make:controller Api/V1/CourseController

2. Κάνω register to resourceful route στο app/Http/routes.php

Route::resource('courses', 'Api\V1\CourseController');

Το resourceful route κάνει register τα παρακάτω routes

Verb Path Action Route Name
GET /courses index courses.index
GET /courses/create create courses.create
POST /courses store courses.store
GET /courses/{course} show courses.show
GET /courses/{course}/edit edit courses.edit
PUT/PATCH /courses/{course} update courses.update
DELETE /courses/{courses} destroy courses.destroy

Επειδή τα actions που χρειαζόμαστε είναι μόνο το index και το show διορθώνουμε το route ως εξής:
Route::resource('courses', 'Api\V1\CourseController', ['only' => ['index', 'show']]);

Πληκτρολογώντας το παρακάτω μπορώ να δω ποια routes είναι registered:
php artisan route:list

3. Δημιουργώ ένα course eloquent model με το παρακάτω

php artisan make:model Models/Course
Αν το όνομα του πίνακα που αντιστοιχεί το μοντέλο δεν είναι ο πληθυντικός του ονόματος του μοντέλου (Laravel convention) τότε πρέπει να το δηλώσω ρητά στις ιδιότητες της κλάσης.
‘Έτσι στην συγκεκριμένη περίπτωση επειδή ο πίνακας του openeclass δεν ονομάζεται courses αλλά course πρέπει να ανοίξουμε το μοντέλο που μόλις φτιάξαμε και να προσθέσουμε την ιδιότητα
protected $table = 'course';

4. Δημιουργώ ένα course repository στον φάκελο app/Repositories

Αφού δημιουργήσω το CourseRepository.php το ανοίγω και υλοποιώ την getAllCourses(). Για να πάρω τα αποτελέσματα χρησιμοποιώ ένα eloquent query.

public function getAllCourses($limit) {
return Course::paginate($limit);
}

5. Δημιουργώ μια CourseTransformer class

Δημιουργώ τον CourseTransformer.php στον φάκελο app/Http/Controllers/Api/V1/Transformers για να μετονομάσω τα πεδία της βάσης πριν τα επιστρέψω στο χρήστη.

6. Επεξεργάζομαι τον controller μου

Επιστρέφω στον CourseController.php που έφτιαξα προηγουμένως και τον επεξεργάζομαι. Για αρχή μπορούμε να διαγράψουμε όλες τις μεθόδους που δεν θα χρησιμοποιήσουμε κρατώντας μόνο την_ index()_ και την show().
Κάθε controller μας θα πρέπει να έχει υποχρεωτικά τις παρακάτω ιδιότητες:

private $response;
private $courseRepo;

Οι οποίες θα αρχικοποιούνται με dependency injection στον constructor ως εξής:

public function __construct(Larasponse $response, CourseRepository $courseRepo) {
$this->response = $response;
$this->courseRepo = $courseRepo;
}

Η υλοποίηση των μεθόδων index() και show() είναι προφανής. Αυτό που ίσως δεν είναι τόσο προφανές είναι το πώς έρχεται το $course σαν παράμετρος στην index αντί να έρχεται το $course_code. Αυτό γίνεται εξαιτίας των παρακάτω γραμμών στο routes.php

Route::bind('courses', function($value) {
$course = App\Models\Course::where('code', '=', $value)->firstOrFail();
return $course;
});

Αυτό το κάνουμε ώστε όταν αργότερα θα υλοποιήσουμε REST calls που θα αφορούν το course να μην χρειάζεται κάθε φορά να γράφουμε το query που θα μας επιστρέψει το course model object αλλά να το έχουμε διαθέσιμο πάντα ως πρώτη παράμετρο σε κάθε μέθοδο. Μπορείτε να δείτε την υλοποίηση του ρίχνοντας μια ματιά στο AssignmentController.