Warm tip: This article is reproduced from stackoverflow.com, please click
api http ionic-framework json laravel

API with laravel json response

发布于 2020-04-11 11:54:40

I tried to make example Ionic application with API with my laravel project. I made Laravel json response api routes. But in my Ionic home page nothing shows up and it reports me this error: Access to XMLHttpRequest at 'http://b.1p1eqpotato.com/ib/?p=1' from origin 'http://localhost:8100' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute. zone-evergreen.js:2952 POST http://b.1p1eqpotato.com/ib/?p=1 net::ERR_FAILED. And this is console.log of my laravel posts (3) [{…}, {…}, {…}]0: {id: 1, name: "John Doe", course: "Udemy Academy", created_at: "2020-02-01 13:14:40", updated_at: "2020-02-01 13:14:40"}1: {id: 2, name: "Mike Doe", course: "Software Engineering", created_at: "2020-02-01 13:16:43", updated_at: "2020-02-01 13:16:43"}2: {id: 3, name: "Trevor Doe", course: "Api Ionic Laravel", created_at: "2020-02-01 13:58:24", updated_at: "2020-02-01 13:58:24"}length: 3__proto__: Array(0) udnefined home.page.ts:24

So this is my Ionic code.

My app.module.ts:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';

import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { HttpClientModule, HttpClient } from '@angular/common/http';

@NgModule({
    declarations: [ AppComponent ],
    entryComponents: [],
    imports: [ BrowserModule, IonicModule.forRoot(), AppRoutingModule, HttpClientModule ],
    providers: [ StatusBar, SplashScreen, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy } ],
    bootstrap: [ AppComponent ]
})
export class AppModule {}

My api.service.ts:

import { Injectable } from '@angular/core';
import { Observable, of, throwError } from 'rxjs';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { catchError, tap, map } from 'rxjs/operators';

const httpOptions = {
  headers: new HttpHeaders({'Content-type': 'applications/json'})
}

const apiUrl = "http://localhost:8000/api/students";

@Injectable({
  providedIn: 'root'
})
export class ApiService {

  constructor(private http: HttpClient) { }

  private handleError(error: HttpErrorResponse) {
    if(error.error instanceof ErrorEvent) {
      console.error('An error occurred:', error.error.message);
    } else {
      console.error(
        `Backend returned code ${error.status},` +
        `body was: ${error.error}`
      );
    }
    return throwError('Something is wrong, please try again.');
  }

  private extractData(res: Response) {
    let body = res;
    return body || { };
  }

  getDataUser(): Observable<any> {
    return this.http.get(apiUrl, httpOptions).pipe(
      map(this.extractData),
      catchError(this.handleError)
    );
  }
}

This is home.page.ts:

import { Component } from '@angular/core';
import { ApiService } from './../api.service';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {
  datauser: any;
  constructor(
    public api: ApiService
  ) {}

  ngOnInit(){
    this.getDataUser();
  }

  async getDataUser() {
    await this.api.getDataUser()
      .subscribe(res => {
        console.log(res);
        this.datauser = res.results;
    console.log(this.datauser);
      }, err => {
        console.log(err);
      });
  }
}

And this is my home.page.html:

<ion-header>
  <ion-toolbar>
    <ion-title>
      Ionic Blank
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>
  <ion-list>
    <ion-item *ngFor="let data of datauser">
      {{data.name}}
    </ion-item>
  </ion-list>
</ion-content>

So it is showing me array in console but on the Home page view there is nothing. And this error: Is there any solutions for not showing on the view and this XMLHttpRequest error? Please help! Thank you

EDITED

This is my ApiController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Student;

class ApiController extends Controller
{
    public function getAllStudents() {
        // logic to get all students goes here
        $students = Student::get()->toJson(JSON_PRETTY_PRINT);
        return response($students, 200);
      }

      public function createStudent(Request $request) {
        // logic to create a student record goes here
        $student = new Student;
        $student->name = $request->name;
        $student->course = $request->course;
        $student->save();

        return response()->json([
            "message" => "student record created"
        ], 201);
      }

      public function getStudent($id) {
        // logic to get a student record goes here
      }

      public function updateStudent(Request $request, $id) {
        // logic to update a student record goes here
      }

      public function deleteStudent ($id) {
        // logic to delete a student record goes here
      }
  }

This is my api.php routes:

<?php

use Illuminate\Http\Request;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});

Route::get('students', 'ApiController@getAllStudents');
Route::get('students/{id}', 'ApiController@getStudent');
//Route::post('students', 'ApiController@createStudent');
Route::put('students/{id}', 'ApiController@updateStudent');
Route::delete('students/{id}','ApiController@deleteStudent');

And this is my Student.php model:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Student extends Model
{
    protected $table = 'students';

    protected $fillable = ['name', 'course'];
}
Questioner
Milos
Viewed
209
Foued MOUSSI 2020-02-02 10:31

According to Mozilla developer website, CORS happen when a web application tried to send requests to resource that has a different origin (domain, protocol, and port) than its own origin. In my case, http request was made from same host as target resource (localhost) but different port number.

Solution

If you google “how to fix/allow CORS” then you’ll find some websites tells you to add extra headers to your HTTP response by modifying web server configuration. But there is another way you can do in case you have a very little experience with server configuration or you were unable to reach infra guys to ask their help, fix it with Middleware.

What is Middleware?

Middleware is a mechanism for filtering HTTP request coming to your application so you can easily modify HTTP Request and Response in a very convenient way.

Now let’s get to step-by-step:

Create The Class Create a new file CorsMiddleware.php inside directory app\Http\Middleware

<?php

/**
* Location: /app/Http/Middleware
*/
namespace App\Http\Middleware;

use Closure;

class CorsMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $headers = [
            'Access-Control-Allow-Origin'      => '*',
            'Access-Control-Allow-Methods'     => 'POST, GET, OPTIONS, PUT, DELETE',
            'Access-Control-Allow-Credentials' => 'true',
            'Access-Control-Max-Age'           => '86400',
            'Access-Control-Allow-Headers'     => 'Content-Type, Authorization, X-Requested-With'
        ];

        if ($request->isMethod('OPTIONS'))
        {
            return response()->json('{"method":"OPTIONS"}', 200, $headers);
        }

        $response = $next($request);
        foreach($headers as $key => $value)
        {
            $response->header($key, $value);
        }

        return $response;
    }
}

This class is used to modify Http Response header, what important here is line number 22 where we tell browser to accept request from any sources (*)

'Access-Control-Allow-Origin' => '*'

Register Middleware

In order to make CorsMiddleware class known by Laravel next you have to Register it in app\Http\Kernel.php

$app->middleware([
    //...
    App\Http\Middleware\CorsMiddleware::class
]);

Now you should find that error no more.

Full reading source