{"id":3464,"date":"2018-05-30T08:58:53","date_gmt":"2018-05-30T08:58:53","guid":{"rendered":"https:\/\/anexia.com\/blog\/de\/?p=3464"},"modified":"2022-07-22T13:00:43","modified_gmt":"2022-07-22T11:00:43","slug":"restful-api-mit-laravel","status":"publish","type":"post","link":"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/","title":{"rendered":"RESTful API mit Laravel"},"content":{"rendered":"<h2>Was ist Laravel?<\/h2>\n<p>Vor wenigen Jahren wurden Webapplikation noch so gebaut, dass die Interaktionen mit Datenbank und View unmittelbar von der Applikation selbst durchgef\u00fchrt wurden. Doch mit der steigenden Popularit\u00e4t von <a href=\"https:\/\/anexia.com\/de\/softwareentwicklung\/app-entwicklung\/\">mobilen Apps<\/a> und Javascript-Frameworks, etablierten sich zentrale RESTful-APIs als die beste und eleganteste L\u00f6sung, wenn es darum geht, eine einheitliche Schnittstelle zwischen dem jeweiligen Client und dem Datenstamm bereitzustellen.<\/p>\n<p>Bei Laravel handelt es sich um ein in PHP geschriebenes Open-Source-Framework, welches im Jahr 2011 von Taylor Otwell initiiert wurde. Inzwischen erfreut es sich aufgrund seiner Einfachheit und Flexibilit\u00e4t gro\u00dfer Beliebtheit und punktet mit einer weltweit verbreiteten Community.<\/p>\n<h2>REST \u2013 Was sich dahinter verbirgt<\/h2>\n<p>Der Ausdruck \u201eRESTful API\u201c ist vielen von euch sicherlich ein Begriff. Um darauf n\u00e4her eingehen zu k\u00f6nnen, muss man erstmal verstehen, wof\u00fcr \u201eREST\u201c eigentlich steht, und welche Prinzipien es verfolgt.<\/p>\n<p>REST ist die Abk\u00fcrzung f\u00fcr \u201e<strong>RE<\/strong>presentational <strong>S<\/strong>tate <strong>T<\/strong>ransfer\u201c, und bezeichnet ein Programmierparadigma zur Kommunikation zwischen Applikation \u00fcber ein zustandsloses Protokoll (meistens HTTP). Besonders relevant ist dieses f\u00fcr verteilte Systeme, insbesondere f\u00fcr Webservices.<\/p>\n<h3>HTTP-Methoden definieren Actions<\/h3>\n<p>Bei REST-konformen APIs stellen die Ressourcen die Endpunkte dar. HTTP-Methoden repr\u00e4sentieren die zugeh\u00f6rigen Actions. Es ist genau definiert, bei welcher Zugriffsart welche Aktion ausgel\u00f6st werden soll:<\/p>\n<ul>\n<li><strong>GET: Ressource lesen<br \/>\n<\/strong>L\u00e4dt Informationen der gew\u00fcnschten Ressource vom Server, und verursacht dabei keine Nebeneffekte. GET-Requests m\u00fcssen laut Spezifikation \u201esicher\u201c sein, d.h. ein Request darf keine Auswirkungen auf die Ressource haben. Das Verhalten wird als nullipotent bezeichnet.<\/li>\n<li><strong>POST: Neue Ressource anlegen<\/strong><br \/>\nLegt im jeweiligen Ressourcenstamm anhand der \u00fcbermittelten Daten eine neue Ressource an. Erstellt mit jedem weiteren Aufruf neue Ressourcen, statt die \u00e4quivalente wieder zur\u00fcckzugeben. Dieses Verhalten wird als nicht idempotent bezeichnet.<\/li>\n<li><strong>PUT: Bestehende Ressource updaten<\/strong><br \/>\nAktualisiert mit den \u00fcbermittelten Daten eine bereits bestehende Ressource. Weitere Aufrufe verursachen keine weiteren Nebeneffekte. Im Gegensatz zu POST wird dieses Verhalten hier als idempotent bezeichnet.<\/li>\n<li><strong>DELETE: Ressource l\u00f6schen<br \/>\n<\/strong>L\u00f6scht die geforderte Ressource, und ist vom Verhalten her analog zu PUT ebenfalls idempotent.<\/li>\n<\/ul>\n<p>Die HTTP-Methoden <strong>HEAD<\/strong>, <strong>OPTIONS<\/strong>, <strong>CONNECT<\/strong> und <strong>TRACE<\/strong> sind optional, und werden f\u00fcr CRUD-Operationen im Normalfall nicht ben\u00f6tigt. Wichtig w\u00e4re es hier auch noch anzumerken, dass eine Eigenimplementierung von CONNECT oder TRACE sich ggf. auf die Sicherheit der Applikation auswirken kann!<\/p>\n<h3>Daten speichern: POST vs. PUT<\/h3>\n<p>Wenn es um die Speicherung von Daten geht, sei es das Neuanlegen oder auch Aktualisieren, teilen sich die Meinungen, ob man daf\u00fcr nun lieber POST, PUT oder auch PATCH (partielles Update) verwenden sollte.<\/p>\n<p>In den folgenden Beispielen wird f\u00fcr das Aktualisieren von Ressourcen auf PUT gesetzt. PUT steht f\u00fcr das Anlegen bzw. Aktualisieren einer Ressource an einem bestimmten Ort.<\/p>\n<p>Was ebenfalls f\u00fcr PUT steht, ist dessen Idempotenz. Das bedeutet, dass wiederholte Anfragen mit den gleichen Daten tats\u00e4chlich nur eine einzige \u00c4nderung bewirken.<\/p>\n<h2>REST-Integration in Laravel<\/h2>\n<p>Urspr\u00fcnglich sollte dieses Framework lediglich eine bessere Alternative zum bereits beliebten <a href=\"https:\/\/www.codeigniter.com\" target=\"_blank\" rel=\"noopener\">CodeIgniter-Framework<\/a>\u00a0darstellen, da dieses u.a. keine Funktionen betreffend Authentifizierung mitbrachte.<\/p>\n<p>Mit der Zeit wurde dessen Funktionsumfang in gro\u00dfem Ma\u00dfe erweitert, und brachte neben der Unterst\u00fctzung von Dependency Injections auch eine eigene Template-Engine (\u201eBlade\u201c) mit.<\/p>\n<p>Im Jahr 2012 erfolgte dann mit dem mitgelieferten Command-Line-Tool \u201eArtisan\u201c ein weiterer gro\u00dfer Durchbruch, da dieses es erm\u00f6glicht, s\u00e4mtliche Interaktionen mit dem Framework unmittelbar \u00fcber die Konsole auszuf\u00fchren. Des Weiteren folgte auch eine Unterst\u00fctzung f\u00fcr eine noch breitere Palette an Datenbanksystemen.<\/p>\n<p>Als das Laravel-Framework mit Version 4 dann vollst\u00e4ndig \u00fcber Composer geladen und verwaltet werden konnte, stieg auch dessen Erweiterbarkeit entsprechend an, was dem Entwickler noch mehr Freiheiten einr\u00e4umte.<\/p>\n<p>Weitere Informationen diesbez\u00fcglich k\u00f6nnen direkt auf der <a href=\"https:\/\/laravel.com\" target=\"_blank\" rel=\"noopener\">Homepage<\/a> des Frameworks eingesehen werden.<\/p>\n<p>F\u00fcr die folgenden Beispiele gehen wir davon aus, dass das Laravel-Framework bereits installiert und lauff\u00e4hig ist. Ob dies nun via <a href=\"https:\/\/laravel.com\/docs\/5.6\/homestead\" target=\"_blank\" rel=\"noopener\">Homestead<\/a>, Composer oder auch einer manuellen Installation eines ver\u00f6ffentlichten Releases von GitHub erfolgt, spielt hier keine Rolle. Des Weiteren sollte auch die Datenbankverbindung bereits konfiguriert und funktionsf\u00e4hig sein.<\/p>\n<h2>Erstellen einer Ressource<\/h2>\n<p>Wir treffen die Annahme, dass f\u00fcr das folgende Beispiel der Model-Name ident zum Ressourcen-Namen ist. Dies ist keine zwingend erforderliche Ma\u00dfnahme, f\u00f6rdert jedoch die Nachvollziehbarkeit ungemein.<\/p>\n<p>Als Ressource werden wir hier eine \u201eNotiz\u201c (engl. \u201eNote\u201c) anlegen, welche einen Titel (\u201eSubject\u201c) sowie einen Textk\u00f6rper (\u201eBody\u201c) hat.<\/p>\n<p>Beginnen wir nun als Erstes damit, das Model inkl. Migration mit Hilfe des von Laravel mitgelieferten Command-Line-Tools \u201e<a href=\"https:\/\/laravel.com\/docs\/5.6\/artisan\" target=\"_blank\" rel=\"noopener\">Artisan<\/a>\u201c zu erstellen.<\/p>\n<p>Dazu navigieren wir mit dem Terminal (Linux) bzw. der Eingabeaufforderung (Windows) direkt in das Projektverzeichnis und geben dabei den folgenden Command ein:<\/p>\n<p><strong>php artisan make:model Note -m<\/strong><\/p>\n<p>Mit diesem Command wird ein neues Model namens \u201eNote\u201c erstellt. Der optionale Paramter \u201e-m\u201c gibt an, dass parallel dazu eine entsprechende Migration angelegt wird. Das soeben generierte Model liegt unter <strong>.\/app\/Note.php<\/strong>, die zugeh\u00f6rige Migration unter <strong>.\/database\/migrations\/YYYY_MM_DD_XXXXXX_create_notes_table.php<\/strong>.<\/p>\n<p>Sehen wir uns nun zun\u00e4chst mal die Migration an.<\/p>\n<pre class=\"lang:php decode:true \">&lt;?php\r\n\r\nuse Illuminate\\Support\\Facades\\Schema;\r\nuse Illuminate\\Database\\Schema\\Blueprint;\r\nuse Illuminate\\Database\\Migrations\\Migration;\r\n\r\nclass CreateNotesTable extends Migration\r\n{\r\n    \/**\r\n     * Run the migrations.\r\n     *\r\n     * @return void\r\n     *\/\r\n    public function up()\r\n    {\r\n        Schema::create('notes', function (Blueprint $table) {\r\n            $table-&gt;increments('id');\r\n            $table-&gt;timestamps();\r\n        });\r\n    }\r\n\r\n    \/**\r\n     * Reverse the migrations.\r\n     *\r\n     * @return void\r\n     *\/\r\n    public function down()\r\n    {\r\n        Schema::dropIfExists('notes');\r\n    }\r\n}<\/pre>\n<p>Die <strong>up()<\/strong> und <strong>down()<\/strong>-Methoden dienen der Durchf\u00fchrung der Migration bzw. deren Rollback.<\/p>\n<p>Mit <strong>$table-&gt;increments(&#8218;id&#8216;)<\/strong> wird festgelegt, dass hierf\u00fcr ein INT-Feld mit Auto-Increment als Primary-Key erzeugt wird. Die Anweisung <strong>$table-&gt;timestamps()<\/strong> sorgt daf\u00fcr, dass zus\u00e4tzlich die von Laravel verwalteten Felder \u201ecreated_at\u201c und \u201eupdated_at\u201c ebenfalls erzeugt werden. Ob diese nun genutzt werden sollen oder nicht, l\u00e4sst sich \u00fcbrigens auch direkt im Model konfigurieren, aber standardm\u00e4\u00dfig werden diese verwendet.<\/p>\n<p>F\u00fcgen wir der zuvor generierten Migration nun unsere beiden Felder \u201eSubject\u201c und \u201eBody\u201c hinzu, sodass die <strong>up()<\/strong>-Methode dann schlie\u00dflich wie folgt aussieht:<\/p>\n<pre class=\"lang:php decode:true \">public function up()\r\n{\r\n\tSchema::create('notes', function (Blueprint $table) {\r\n\t\t$table-&gt;increments('id');\r\n\t\t$table-&gt;string('subject');\r\n\t\t$table-&gt;text('body');\r\n\t\t$table-&gt;timestamps();\r\n\t});\r\n}<\/pre>\n<p>F\u00fchren wir nun die Migration mit dem folgenden Command aus:<\/p>\n<p><strong>php artisan migrate<\/strong><\/p>\n<p>Sollte es m\u00f6glicherweise zu einem Fehler wie \u201e<strong><em>Specified key was too long error<\/em><\/strong>\u201c kommen, k\u00f6nnte die folgende Ma\u00dfnahme helfen.<\/p>\n<p>Dazu erweitern wir den App-Service-Provider unter <strong>.\/app\/Providers\/AppServiceProvider.php<\/strong> wie folgt und wiederholen anschlie\u00dfend den vorigen Schritt:<\/p>\n<pre class=\"lang:php decode:true \">use Illuminate\\Support\\Facades\\Schema;\r\n\r\npublic function boot()\r\n{\r\n\tSchema::defaultStringLength(191);\r\n}<\/pre>\n<p>Widmen wir uns nun jedoch wieder unserem \u201eNote\u201c-Model. Diesem f\u00fcgen wir nun das \u201eprotected\u201c-Attribut \u201efillable\u201c hinzu, und legen fest, welche Felder davon in der Datenbank bef\u00fcllt werden d\u00fcrfen.<\/p>\n<pre class=\"lang:pgsql decode:true \">&lt;?php\r\n\r\nnamespace App;\r\n\r\nuse Illuminate\\Database\\Eloquent\\Model;\r\n\r\nclass Note extends Model\r\n{\r\n\r\n\t\/**\r\n\t * @var array\r\n\t *\/\r\n\tprotected $fillable = ['subject', 'body'];\r\n}<\/pre>\n<h2>Datenbank-Seeding<\/h2>\n<p>Unter dem Begriff Datenbank-Seeding versteht man das Bef\u00fcllen einer Datenbank bzw. einer Datenbank-Tabelle (bei relationalen Systemen) mit Testdaten. Diese werden dabei i.d.R. dynamisch nach dem Zufallsprinzip erzeugt.<\/p>\n<p>Erstellen wir mit dem folgenden Command nun eine Seeder-Klasse, welche unsere Notes-Tabelle mit Testdaten bef\u00fcllen wird:<\/p>\n<p><strong>php artisan make:seeder NotesSeeder<\/strong><\/p>\n<p>Nun \u00f6ffnen wir die soeben erzeugte Seeder-Klasse unter <strong>.\/database\/seeds\/NotesSeeder.php<\/strong> und f\u00fcgen hier Folgendes ein:<\/p>\n<pre class=\"lang:php decode:true \">&lt;?php\r\n\r\nuse Illuminate\\Database\\Seeder;\r\nuse App\\Note;\r\n\r\nclass NotesSeeder extends Seeder\r\n{\r\n\t\/**\r\n\t * Run the database seeds.\r\n\t *\r\n\t * @return void\r\n\t *\/\r\n\tpublic function run()\r\n\t{\r\n\t\t\/\/ truncate already existing data\r\n\t\tNote::truncate();\r\n\r\n\t\t\/\/ make instance of the Faker-class\r\n\t\t$faker = \\Faker\\Factory::create();\r\n\r\n\t\t\/\/ insert some random generated records\r\n\t\tfor ($i = 0; $i &lt; 200; $i++) {\r\n\t\t\tNote::create([\r\n\t\t\t\t'subject' =&gt; $faker-&gt;sentence(),\r\n\t\t\t\t'body' =&gt; $faker-&gt;paragraph(),\r\n\t\t\t]);\r\n\t\t}\r\n\t}\r\n}<\/pre>\n<p>Die Faker-Klasse erm\u00f6glicht die Generierung von zuf\u00e4lligen Pseudo-Inhalten, selektierbar nach Typ. Hier wird als erstes die Datenbank-Tabelle geleert, sodass wir mit jeder Ausf\u00fchrung dieses Seeders wieder von Neuem starten k\u00f6nnen. In einer Schleife werden nun 200 zuf\u00e4llige Eintr\u00e4ge generiert und gespeichert. Um den Seeder nun auszuf\u00fchren, machen wir uns wieder Artisan zunutze:<\/p>\n<p><strong>php artisan db:seed &#8211;class=NotesSeeder<\/strong><\/p>\n<p>Sollten wir mehrere Seeder-Klassen haben, w\u00e4re es einfacher, diese dem zentralen \u201eDatabase-Seeder\u201c hinzuzuf\u00fcgen, indem wir die einzelnen, von uns erstellten Seeder-Klassen in der <strong>run()<\/strong>-Methode der <strong>DatabaseSeeder()<\/strong>-Klasse im gleichen Verzeichnis registrieren.<\/p>\n<pre class=\"lang:php decode:true \">&lt;?php\r\n\r\nuse Illuminate\\Database\\Seeder;\r\n\r\nclass DatabaseSeeder extends Seeder\r\n{\r\n\t\/**\r\n\t * Run the database seeds.\r\n\t *\r\n\t * @return void\r\n\t *\/\r\n\tpublic function run()\r\n\t{\r\n\t\t$this-&gt;call( NotesSeeder::class );\r\n\t}\r\n}<\/pre>\n<p>Nun k\u00f6nnen wir mit dem Artisan-Seed-Command ohne spezifische Angabe einer Klasse alle im<strong> DatabaseSeeder()<\/strong> registrierten Seeder ausf\u00fchren.<\/p>\n<p><strong>php artisan db:seed<\/strong><\/p>\n<h2>Resource-Controller anlegen<\/h2>\n<p>Damit wir mit den Daten interagieren k\u00f6nnen, bedarf es eines Controllers, welcher die Kommunikation zwischen Client und Datenbank \u00fcbernimmt. In diesem Fall ben\u00f6tigen wir jedoch einen sogenannten Resource-Controller, d.h. er muss mindestens die folgenden Actions implementieren:\u00a0 <strong>index()<\/strong>, <strong>store()<\/strong>, <strong>update()<\/strong> und <strong>destroy()<\/strong>. Dazu nutzen wir ebenfalls wieder Artisan:<\/p>\n<p><strong>php artisan make:controller NotesController<\/strong><\/p>\n<p>Der neu erstellte <strong>NotesController()<\/strong> befindet sich unter <strong>.\/app\/Http\/Controllers\/NotesController.php<\/strong>. In diesem legen wir nun die vorhin genannten Actions an, und implementieren das Basis-Verhalten.<\/p>\n<pre class=\"lang:php decode:true \">&lt;?php\r\n\r\nnamespace App\\Http\\Controllers;\r\n\r\nuse Illuminate\\Http\\Request;\r\nuse App\\Note;\r\n\r\nclass NotesController extends Controller\r\n{\r\n\t\/**\r\n\t * Index function for general listing.\r\n\t *\r\n\t * @param Request $request\r\n\t *\r\n\t * @return \\Illuminate\\Http\\JsonResponse\r\n\t *\/\r\n\tpublic function index(Request $request)\r\n\t{\r\n\t\t$notes = Note::all();\r\n\r\n\t\treturn response()-&gt;json($notes);\r\n\t}\r\n\r\n\r\n\t\/**\r\n\t * Store-Action\r\n\t *\r\n\t * @param Request $request\r\n\t *\r\n\t * @return \\Illuminate\\Http\\JsonResponse\r\n\t *\/\r\n\tpublic function store(Request $request)\r\n\t{\r\n\t\t$note = Note::create($request-&gt;all());\r\n\r\n\t\treturn response()-&gt;json($note);\r\n\t}\r\n\r\n\r\n\t\/**\r\n\t * Show-Action\r\n\t *\r\n\t * @param Request $request\r\n\t * @param int $id\r\n\t *\r\n\t * @return \\Illuminate\\Http\\JsonResponse\r\n\t *\/\r\n\tpublic function show(Request $request, $id)\r\n\t{\r\n\t\t$note = Note::find($id);\r\n\r\n\t\treturn response()-&gt;json($note);\r\n\t}\r\n\r\n\r\n\t\/**\r\n\t * Update-Action\r\n\t *\r\n\t * @param Request $request\r\n\t * @param int $id\r\n\t *\r\n\t * @return \\Illuminate\\Http\\JsonResponse\r\n\t *\/\r\n\tpublic function update(Request $request, $id)\r\n\t{\r\n\t\t$note = Note::findOrFail($id);\r\n\t\t$note-&gt;update($request-&gt;all());\r\n\r\n\t\treturn response()-&gt;json($note);\r\n\r\n\r\n\t}\r\n\r\n\r\n\t\/**\r\n\t * Destroy-Action\r\n\t *\r\n\t * @param Request $request\r\n\t * @param int $id\r\n\t *\r\n\t * @return \\Illuminate\\Http\\JsonResponse\r\n\t *\/\r\n\tpublic function destroy(Request $request, $id)\r\n\t{\r\n\t\tNote::find($id)-&gt;delete();\r\n\r\n\t\treturn response()-&gt;json([], 204);\r\n\t}\r\n}<\/pre>\n<p>Bei mehreren Resource-Controllern w\u00fcrde es Sinn machen, daf\u00fcr einen Basis-Resource-Controller anzulegen, und die jeweiligen Resource-Controller davon erben zu lassen. Das\u00a0hat den Vorteil, das Basisverhalten in jedem Controller nutzen zu k\u00f6nnen und bringt gleichzeitig auch die M\u00f6glichkeit, f\u00fcr einzelne Controller bestimmte Actions zu \u00fcberschreiben.<\/p>\n<h2>API-Routen registrieren<\/h2>\n<p>Nachdem nun das CRUD-Verhalten grunds\u00e4tzlich implementiert ist, m\u00fcssen nur noch die Routen definiert werden. Dazu \u00f6ffnen wir die Datei <strong>.\/routes\/api.php<\/strong> und f\u00fcgen dort die folgende Zeile ein:<\/p>\n<pre class=\"lang:php decode:true \">Route::resource('notes', 'NotesController');<\/pre>\n<p>Die Routen-Konfiguration von Laravel erlaubt es auf diese Art einen Endpunkt direkt auf einen <a href=\"https:\/\/laravel.com\/docs\/5.6\/controllers#resource-controllers\" target=\"_blank\" rel=\"noopener\">Resource-Controller<\/a>\u00a0zu routen. Laravel hat hierf\u00fcr bereits bestimmte Actions beim jeweiligen Controller f\u00fcr sich reserviert. Dabei handelt es sich um jene, die wir bereits zuvor beim <strong>NotesController()<\/strong> angelegt haben. Die folgende Tabelle soll Aufschluss geben wie die URL-Struktur f\u00fcr einen solchen Resource-Controller aussieht, und welche Action hinter welcher HTTP-Methode liegt.<\/p>\n<table style=\"width: 600px; height: 266px;\">\n<tbody>\n<tr style=\"height: 24px;\">\n<td style=\"height: 24px; width: 138px;\"><strong>HTTP-Verbindungsart<\/strong><\/td>\n<td style=\"height: 24px; width: 117px;\"><strong>URI<\/strong><\/td>\n<td style=\"height: 24px; width: 54px;\"><strong>Action<\/strong><\/td>\n<td style=\"height: 24px; width: 99px;\"><strong>Routen-Name<\/strong><\/td>\n<\/tr>\n<tr style=\"height: 24.5625px;\">\n<td style=\"height: 24.5625px; width: 138px;\"><strong>GET<\/strong><\/td>\n<td style=\"height: 24.5625px; width: 117px;\">\/notes<\/td>\n<td style=\"height: 24.5625px; width: 54px;\">index<\/td>\n<td style=\"height: 24.5625px; width: 99px;\">notes.index<\/td>\n<\/tr>\n<tr style=\"height: 24px;\">\n<td style=\"height: 24px; width: 138px;\"><strong>GET<\/strong><\/td>\n<td style=\"height: 24px; width: 117px;\">\/notes\/create<\/td>\n<td style=\"height: 24px; width: 54px;\">create<\/td>\n<td style=\"height: 24px; width: 99px;\">notes.create<\/td>\n<\/tr>\n<tr style=\"height: 24px;\">\n<td style=\"height: 24px; width: 138px;\"><strong>POST<\/strong><\/td>\n<td style=\"height: 24px; width: 117px;\">\/notes<\/td>\n<td style=\"height: 24px; width: 54px;\">store<\/td>\n<td style=\"height: 24px; width: 99px;\">notes.store<\/td>\n<\/tr>\n<tr style=\"height: 24px;\">\n<td style=\"height: 24px; width: 138px;\"><strong>GET<\/strong><\/td>\n<td style=\"height: 24px; width: 117px;\">\/notes\/{id}<\/td>\n<td style=\"height: 24px; width: 54px;\">show<\/td>\n<td style=\"height: 24px; width: 99px;\">notes.show<\/td>\n<\/tr>\n<tr style=\"height: 24px;\">\n<td style=\"height: 24px; width: 138px;\"><strong>GET<\/strong><\/td>\n<td style=\"height: 24px; width: 117px;\">\/notes\/{id}\/edit<\/td>\n<td style=\"height: 24px; width: 54px;\">edit<\/td>\n<td style=\"height: 24px; width: 99px;\">notes.edit<\/td>\n<\/tr>\n<tr style=\"height: 24px;\">\n<td style=\"height: 24px; width: 138px;\"><strong>PUT\/PATCH<\/strong><\/td>\n<td style=\"height: 24px; width: 117px;\">\/notes\/{id}<\/td>\n<td style=\"height: 24px; width: 54px;\">update<\/td>\n<td style=\"height: 24px; width: 99px;\">notes.update<\/td>\n<\/tr>\n<tr style=\"height: 24px;\">\n<td style=\"height: 24px; width: 138px;\"><strong>DELETE<\/strong><\/td>\n<td style=\"height: 24px; width: 117px;\">\/notes\/{id}<\/td>\n<td style=\"height: 24px; width: 54px;\">destroy<\/td>\n<td style=\"height: 24px; width: 99px;\">notes.destroy<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<p>Zu beachten ist, dass in unserem Resource-Controller die Actions <strong>create()<\/strong> sowie <strong>edit()<\/strong> nicht implementiert wurden. Dies hat den Grund, da bei diesen beiden Actions nur das jeweilige (HTML-)Formular via GET ausgeliefert werden sollte. Nachdem aber unser Ressource-Endpunkt nur JSON-Daten ausliefert, w\u00e4re dies somit hinf\u00e4llig.<\/p>\n<h2>HTTP-Statuscodes<\/h2>\n<p>Bei REST-APIs sind neben den HTTP-Methoden unter anderem auch die zu verwendenden HTTP-Statuscodes und deren Bedeutung festgelegt. Die folgende Auflistung soll hier einen kurzen \u00dcberblick gew\u00e4hren.<\/p>\n<ul>\n<li><strong>200:<\/strong> OK, kein Fehler aufgetreten<\/li>\n<li><strong>201:<\/strong> Objekt wurde erstellt<\/li>\n<li><strong>204:<\/strong> Kein Inhalt &#8211; deutet darauf hin, dass eine Aktion erfolgreich war, jedoch keinen Inhalt zur\u00fcckliefert<\/li>\n<li><strong>206:<\/strong> Partieller Inhalt \u2013 kommt beispielsweise bei paginierten Inhalten zum Einsatz<\/li>\n<li><strong>400:<\/strong> Ung\u00fcltige Anfrage \u2013 Standard-Response-Code wenn Anfrage nicht valide war<\/li>\n<li><strong>401:<\/strong> Nicht berechtigt \u2013 der Benutzer ist entweder nicht autorisiert bzw. es ist eine Anmeldung erforderlich<\/li>\n<li><strong>403:<\/strong> Verweigert &#8211; der Benutzer ist angemeldet, jedoch nicht zur Ausf\u00fchrung dieser Aktion berechtigt<\/li>\n<li><strong>404:<\/strong> Nicht gefunden \u2013 die gew\u00fcnschte Ressource oder der Endpunkt existiert nicht<\/li>\n<li><strong>500:<\/strong> Interner Serverfehler \u2013 sollte im Normalfall nicht auftreten, weist aber darauf hin, dass es serverseitig bei der Verarbeitung der Anfrage zu einem unerwarteten Fehler gekommen ist<\/li>\n<li><strong>503:<\/strong> Service nicht verf\u00fcgbar \u2013 weist darauf hin, dass die gew\u00fcnschte Ressource bzw. der Endpunkt vor\u00fcbergehend nicht verf\u00fcgbar sind<\/li>\n<\/ul>\n<p>Die Nutzung dieser Statuscodes ist zwar nicht verpflichtend, aber wenn man REST-konform entwickeln m\u00f6chte, unabdinglich.<\/p>\n<h2>Fazit RESTful API mit Laravel<\/h2>\n<p>Gerade in Zeiten, wo Rich-Internet-Applications (RIA) bzw. Single-Page-Applications wie Angular oder auch React sich enormer Beliebtheit erfreuen, und auch Apps f\u00fcr mobile Ger\u00e4te immer h\u00e4ufiger auf zentrale Datenst\u00e4mme zugreifen m\u00fcssen, wird es immer wichtiger, einheitliche Kommunikationskan\u00e4le zu verwenden.<\/p>\n<p>Mit einer REST-konformen API (RESTful) l\u00e4sst sich so etwas auch relativ einfach in der Praxis realisieren.<\/p>\n<p>Was jedoch in diesen Beispielen der Einfachheit halber nicht ber\u00fccksichtigt wurde, ist die Absicherung der API. Besonders relevant ist dieser Punkt dann, wenn Daten modifiziert werden k\u00f6nnen. Es gibt ein sehr gro\u00dfes Spektrum an m\u00f6glichen Varianten \u2013 angefangen bei einfachen Tokens (beispielsweise JSON-Web-Token, JWT) bis hin zur komplexen OAuth-Authentifizierung.<\/p>\n<h2>Weiterf\u00fchrende Informationen<\/h2>\n<ul>\n<li><a href=\"https:\/\/anexia.com\/de\/softwareentwicklung\/app-entwicklung\" target=\"_blank\" rel=\"noopener\">Ma\u00dfgeschneiderte App Entwicklung<\/a><\/li>\n<li><a href=\"https:\/\/anexia.com\/de\/softwareentwicklung\/webentwicklung\" target=\"_blank\" rel=\"noopener\">Webentwicklung von Anexia<\/a><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hier stellt Manuel die RESTful-API mit Laravel vor: eine beliebte L\u00f6sung, um eine einheitliche Schnittstelle zwischen Client und Datenstamm bereitzustellen.<\/p>\n","protected":false},"author":15,"featured_media":2961,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[451,429,74,14,5,450,487,362],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>RESTful API mit Laravel - ANEXIA Blog<\/title>\n<meta name=\"description\" content=\"RESTful-API mit Laravel: Eine beliebte L\u00f6sung, um eine einheitliche Schnittstelle zwischen Client und Datenstamm bereitzustellen.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"RESTful API mit Laravel - ANEXIA Blog\" \/>\n<meta property=\"og:description\" content=\"RESTful-API mit Laravel: Eine beliebte L\u00f6sung, um eine einheitliche Schnittstelle zwischen Client und Datenstamm bereitzustellen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/\" \/>\n<meta property=\"og:site_name\" content=\"ANEXIA Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/anexiagmbh\/\" \/>\n<meta property=\"article:published_time\" content=\"2018-05-30T08:58:53+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-07-22T11:00:43+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"672\" \/>\n\t<meta property=\"og:image:height\" content=\"372\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Manuel Wutte\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@_ANEXIA\" \/>\n<meta name=\"twitter:site\" content=\"@_ANEXIA\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Manuel Wutte\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"12\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/\",\"url\":\"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/\",\"name\":\"RESTful API mit Laravel - ANEXIA Blog\",\"isPartOf\":{\"@id\":\"https:\/\/anexia.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\",\"datePublished\":\"2018-05-30T08:58:53+00:00\",\"dateModified\":\"2022-07-22T11:00:43+00:00\",\"author\":{\"@id\":\"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de\"},\"description\":\"RESTful-API mit Laravel: Eine beliebte L\u00f6sung, um eine einheitliche Schnittstelle zwischen Client und Datenstamm bereitzustellen.\",\"breadcrumb\":{\"@id\":\"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/#primaryimage\",\"url\":\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\",\"contentUrl\":\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\",\"width\":672,\"height\":372},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/anexia.com\/blog\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"RESTful API mit Laravel\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/anexia.com\/blog\/#website\",\"url\":\"https:\/\/anexia.com\/blog\/\",\"name\":\"ANEXIA Blog\",\"description\":\"[:de] ANEXIA Blog - Technischen Themen, Anexia News und Insights [:]\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/anexia.com\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"de\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de\",\"name\":\"Manuel Wutte\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/anexia.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g\",\"caption\":\"Manuel Wutte\"},\"url\":\"https:\/\/anexia.com\/blog\/author\/mwu\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"RESTful API mit Laravel - ANEXIA Blog","description":"RESTful-API mit Laravel: Eine beliebte L\u00f6sung, um eine einheitliche Schnittstelle zwischen Client und Datenstamm bereitzustellen.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/","og_locale":"de_DE","og_type":"article","og_title":"RESTful API mit Laravel - ANEXIA Blog","og_description":"RESTful-API mit Laravel: Eine beliebte L\u00f6sung, um eine einheitliche Schnittstelle zwischen Client und Datenstamm bereitzustellen.","og_url":"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/","og_site_name":"ANEXIA Blog","article_publisher":"https:\/\/www.facebook.com\/anexiagmbh\/","article_published_time":"2018-05-30T08:58:53+00:00","article_modified_time":"2022-07-22T11:00:43+00:00","og_image":[{"width":672,"height":372,"url":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg","type":"image\/jpeg"}],"author":"Manuel Wutte","twitter_card":"summary_large_image","twitter_creator":"@_ANEXIA","twitter_site":"@_ANEXIA","twitter_misc":{"Verfasst von":"Manuel Wutte","Gesch\u00e4tzte Lesezeit":"12\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/","url":"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/","name":"RESTful API mit Laravel - ANEXIA Blog","isPartOf":{"@id":"https:\/\/anexia.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/#primaryimage"},"image":{"@id":"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/#primaryimage"},"thumbnailUrl":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg","datePublished":"2018-05-30T08:58:53+00:00","dateModified":"2022-07-22T11:00:43+00:00","author":{"@id":"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de"},"description":"RESTful-API mit Laravel: Eine beliebte L\u00f6sung, um eine einheitliche Schnittstelle zwischen Client und Datenstamm bereitzustellen.","breadcrumb":{"@id":"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/#primaryimage","url":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg","contentUrl":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg","width":672,"height":372},{"@type":"BreadcrumbList","@id":"https:\/\/anexia.com\/blog\/de\/restful-api-mit-laravel\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/anexia.com\/blog\/de\/"},{"@type":"ListItem","position":2,"name":"RESTful API mit Laravel"}]},{"@type":"WebSite","@id":"https:\/\/anexia.com\/blog\/#website","url":"https:\/\/anexia.com\/blog\/","name":"ANEXIA Blog","description":"[:de] ANEXIA Blog - Technischen Themen, Anexia News und Insights [:]","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/anexia.com\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"de"},{"@type":"Person","@id":"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de","name":"Manuel Wutte","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/anexia.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g","caption":"Manuel Wutte"},"url":"https:\/\/anexia.com\/blog\/author\/mwu\/"}]}},"lang":"de","translations":{"de":3464,"en":6669},"amp_enabled":true,"pll_sync_post":[],"_links":{"self":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts\/3464"}],"collection":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/comments?post=3464"}],"version-history":[{"count":18,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts\/3464\/revisions"}],"predecessor-version":[{"id":7529,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts\/3464\/revisions\/7529"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/media\/2961"}],"wp:attachment":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/media?parent=3464"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/categories?post=3464"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/tags?post=3464"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}