Angular 2 POST to Laravel Rest API doesnt unless port number is changed - angularjs-directive

I have made a laravel and angular 2 API - It basically does a post request to a laravel backend API. Everything works perfectly when I run php artisan serve from the root folder and npm start from the public folder, the public folder is served via port 3000 and artisan serves the api via port 8000
this is how my service file looks with the default artisan port 8000 and localhost as the API url
import {Http, Headers, Response} from "#angular/http"
import {Injectable} from "#angular/core"
import {ICourse} from "../interfaces/ICourse"
import 'rxjs/Rx';
import {Observable} from 'rxjs/Observable';
import {Observer} from 'rxjs/Observer';
import 'rxjs/add/operator/share';
import 'rxjs/add/operator/map';
#Injectable()
export class Api {
apiUrl: string = "http://localhost:8000/api/courses/";
headers: Headers = new Headers;
courses$: Observable<ICourse[]>;
private _coursesObserver: Observer<ICourse[]>;
private _dataStore: {
courses: ICourse[]
};
constructor(private _http: Http) {
this.headers.append('Content-Type', 'application/x-www-form-urlencoded');
this.headers.append('X-Requested-With', 'XMLHttpRequest');
this.courses$ = new Observable<ICourse[]>(observer => this._coursesObserver = observer).share();
this._dataStore = { courses: [] };
}
public createCourse(course) {
return new Promise((resolve, reject) => {
this._http.post(this.apiUrl, course, {
headers: this.headers
}).map((res: Response) => res.json()).subscribe(
(res) => {
resolve(res);
console.log('api succeeds');
},
(error) => {
alert('error');
reject(error);
}
);
})
}
}
when I change the api url to a fully qualified domain like http://www.example.com/api/course no only does it do a GET request rather than a POST but it doesnt do anything at all... ive went through the source code trying to figure out what the heck is going on but I am literally stumped.. Anyone come across this before ? To be noted also is that I can use a real domain however i have to serve php artisan from a different port

Did you change apiUrl property to that of the live server?
You also need a token. You can add {{ csrf_field() }} to the top of your page that houses the angular app, but you need it, just like with any post request in laravel. I havent really dug into sending responses between two seperate servers but if you are going that route jwt might be the trick.
I wrote a small article on this a little while back, its not super thorough, but could help check it out

Related

How to intercept call and serve back JSON file dynamically (without "import")

I have a scaffolding of folders and json files to mock an API's paths. When I run npm run start:mock, LocalMockInterceptor gets provisioned and e.g. replaces a call to host/A/B/C by an http call getting locally Folder A/Folder B/C.json. The JSON files get produced by a separate script which is out of scope here. I cannot make use of "import" as many tutorials show because I need a generic solution as the API i am mocking will evolve over time (and so will this scaffolding of folders and files).
/**
* The idea is to only build this into the bundle if we specify so (e.g. on TeamCity, on your localhost), where you don't want to rely
* on external resources for development
* No conditionals in the code bundle! No configuration files or database dependency.
*/
import {
HttpInterceptor,
HttpResponse,
HttpHandler,
HttpRequest,
HttpEvent,
HttpClient,
HttpHeaders
} from '#angular/common/http';
import { Injectable, Injector } from '#angular/core';
import { Observable, of } from 'rxjs';
import { ErrorService } from './error.service';
const devAssetsFolder = 'assets';
#Injectable()
export class LocalMockInterceptor implements HttpInterceptor {
constructor(
private errorService: ErrorService,
private injector: Injector,
private http: HttpClient
) {}
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
if (request.url.endsWith('.json')) return next.handle(request);
console.log(
` >>> Mock Interceptor >>> ${request.url} has been intercepted`
);
const path = `${devAssetsFolder}${request.url}.json`;
var promise = this.getJSON(path).toPromise();
const jsonheaders = new HttpHeaders();
jsonheaders.set('Content-Type', 'application/json');
let json2;
promise
.then(json => {
console.log(json);
json2 = json;
})
.catch(error => console.log(error));
Promise.all([promise]);
console.log(json2);
return of(
new HttpResponse({ status: 200, body: json2, headers: jsonheaders })
);
}
private getJSON(jsonPath: string): Observable<any> {
return this.http.get(jsonPath);
}
}
The first conditional is to avoid infinite loops since I am sending HTTP requests in my interceptor
Getting the path to the JSON file based on the URL is quite natural
It seemed to me that I have to convert the JSON Observable into a promise so that I can wait for it to complete before rewrapping that json into the returned Observable. When debugging however, it seems Promise.all is not waiting for the promise to complete (json2 is undefined on the next line), and I end up sending an empty http body back...
How to fix this rxjs promise ?
Is inner HTTP calls my only option ?
Is there a way not to rely on promises ? Can you think of a better way to achieve this ?
Did you try just modifying the target URL in your interceptor ? You want to make an API call that return some JSON but instead of calling a dynamic API, you just want to call you static server so it can return predefined JSON.
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const fakeUrl = `${devAssetsFolder}${request.url}.json`;
const fakeRequest = request.clone({url: fakeUrl});
return next.handle(request);
}
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
if (request.url.endsWith('.json')) return next.handle(request);
console.log(
` >>> Mock Interceptor >>> ${request.url} has been intercepted`
);
const path = `${devAssetsFolder}${request.url}.json`;
return this.getJSON(path).pipe(map(result => {
const jsonheaders = new HttpHeaders({ 'Content-Type': 'application/json' });
return
new HttpResponse({ status: 200, body: result, headers: jsonheaders });
}), // you can also add catchError here
);
}
In intercept method you can return an observable. So your getJSON method returns an observable, we added pipe a map function which maps the result to new http response. If your response already has the right headers you don't even need the pipe and map functions you can just do this :
return this.getJSON(path); // it's an observable, so it's OK.

How to fix TypeError: req.url.toLowerCase is not a function

I'm setting up a service and i want to use a json file with mock data to start with. However i get a TypeError: req.url.toLowerCase is not a function when i use that service with the mock data, how can i resolve this error?
Service:
import mockCompetitions from '../../mocks/competitions-mock.json';
export class CompetitionsService {
constructor(protected http: HttpClient) { }
getCompetitions() {
console.log(mockCompetitions);
return this.http.get(mockCompetitions);
}
}
Component:
competitions: any = [];
constructor(private competitionsService: CompetitionsService) {}
ngOnInit(){
this.getCompetitions();
}
getCompetitions(){
this.competitionsService.getCompetitions().subscribe(data => {
this.competitions = data;
console.log(this.competitions);
}, err => console.error(err), () => console.log('Finished Loading...'));
}
I expect a list of names to be printed out on the page from the json file.
If you want to use httpclient to read local json file, put the json file in assets folder as name-of-the-file.json and make the http request by using assets folder as url. It is important that you put it in the assets folder, so that Angular can find it. So your code should look something like this:
export class CompetitionsService {
constructor(protected http: HttpClient) { }
getCompetitions() {
return this.http.get('./assets/name-of-the-file.json');
}
}
So no need to import the file.
For using json file as a data provider you can use import and require.
import data = require('your_file.json')
console.log("data : ", JSON.stringify(data));
You are using the JSON file as an url to your http.get().
If you want to test your service using mock data, I would recommend some HTTP mocking website, like mocky. Put your JSON file there and use the URL that the site generates for you in your http.get(). You won't have to change anything except that in your code.

Loading local json file into redux store with axios, but it fails after I refresh in another route

So I'm practicing React and Redux, and I'm loading a local json file into the store like this ...
import { LOAD_BOOKS } from "./booksConstants";
import axios from "axios";
export const loadBooks = data => {
return {
type: LOAD_BOOKS,
payload: data
};
};
export const asyncLoadBooks = () => {
return async dispatch => {
const response = await axios.get("books.json");
const data = response.data.books;
dispatch(loadBooks(data));
};
};
And here's the reducer ...
import { LOAD_BOOKS } from "./booksConstants";
import { createReducer } from "../../store/reducerUtil";
const initialState = {
books: []
};
export const loadBooks = (state, payload) => {
return {
...state,
books: payload
};
};
export default createReducer(initialState, {
[LOAD_BOOKS]: loadBooks
});
And I'm connecting the App.js to the store with connect() and firing the 'asyncLoadBooks()' in 'componentDidMount()' like this ...
componentDidMount() {
try {
this.props.asyncLoadBooks();
} catch (error) {
console.log(error);
}
}
And everything is working just fine when I loop over the data and display them, however, if I'm on any other route other than "/" and refresh the app manually it gives me this error Failed to load resource: the server responded with a status of 404 (Not Found)
I tried to move the methods to the constructor instead of 'componentDidMount' but it didn't work.
What should I do here? And please keep in mind that I want to use axios and redux to practice them.
Edit
I put a console.log into each async action creator and apparently when I'm on any route other than the home "/" it tries to get the JSON file from this path and can't find it GET http://localhost:3000/category/books.json 404 (Not Found)
How can I solve this?
Ok, guys, I figured it out, the problem was in axios trying to the fetch the JSON file from different paths when you're on different routes, I fixed that by setting a global default baseURL for axios in the index.js file like this ...
import axios from "axios";
axios.defaults.baseURL = "http://localhost:3000/";
And now you can refresh in any route and the data will be fetched successfully.

Getting correct ID without sharing URL

I have an Angular 4 application where I am trying to fetch a single row (using ID) from a MySQL database. I am using NodeJS with ExpressJS. However, I am struggling finding a way to get the ID from the URL without sharing the exact URL-path, as that would lead to the website only rendering the JSON-object, and not the components.
server.js
app.get('api/books/:id', (req, res) => {
console.log(req.params.id);
});
If the URL is localhost:3000/books/3, the console will log :id. localhost:3000/api/books/3 will however log the correct ID to the console. The issue is that using the latter as my URL in my Angular routing will result in a shared path, which will not work.
Here's an example of how I use Angular's HttpModule to send a GET-request to the server:
this.http.get('api/books/:id')
.map(res => res.json())
.subscribe(data => {
this.bookDetail = data;
});
Here is my path from the routing using Angular's RouterModule:
{ path: 'books/:id', component: BookDetailComponent }
How would I go about solving this issue?
You need to create a function that on the init of that component, the angular app triggers the HTTP request to the server. for example, I have a blog application.
{ path: 'blogs/:id', component: BlogComponent },
ngOnInit() {
this.route.params.subscribe(params => this.blog = params.id);
this.getBlog(this.blog);}
getBlog(blog) {
this.blogService.getBlog(blog).subscribe(
data => { this.foundBlog = data;
if (data.comments) {
this.comments = data.comments;
}
getBlog(blog): Observable<any> {
return this.http.get(`http://localhost:3000/api/blogs/${blog}`).map(res => res.json());
}
the first is my route, the second is the init function on my blog component
the third is the get blog function on the blog component
the last is the get blog function on my blogservice, that send the HTTP request
hopefully that helps.

Ionic2 and get Json

I am trying to use Ionic2 and I made a service to fetch a local stored Json.
import {Injectable} from 'angular2/core';
import {Http, Response} from 'angular2/http';
import {Observable} from 'rxjs/Rx';
import 'rxjs/add/operator/map';
#Injectable()
export class Page1Service {
public constructor(private _http: Http) {}
public GetItems() {
return this._http.get('/app/Ressources/Items.json').map((response: Response) => response.json().data);
}
public PrintJson():boolean {
var myresult;
this.GetItems().subscribe((result) => {
myresult = result;
console.log(result);
});
}
I also a made PrintJson() method that just print the json for test purpose.I got the error:
GET http://localhost:8100/app/Ressources/slides.json 404 (Not Found)
I don't get why. And I can't find an easy and uptodate tutorial. Or should I use fetch()?
First copy your json to the following dir(you can create the folder "data"):
[appname]/www/data/data.json
Type in the following command in your console:
ionic g provider JsonData
It should create a provider for you.Go to that page and enter the following in load() function:
load() {
if (this.data) {
// already loaded data
return Promise.resolve(this.data);
}
// don't have the data yet
return new Promise(resolve => {
// We're using Angular Http provider to request the data,
// then on the response it'll map the JSON data to a parsed JS object.
// Next we process the data and resolve the promise with the new data.
this.http.get('data/data.json').subscribe(res => {
// we've got back the raw data, now generate the core schedule data
// and save the data for later reference
this.data = res.json();
resolve(this.data);
console.log(this.data);
});
});
}
I usually create an Observable wrapped around the api-call like this:
public GetItems() {
return Observable.create(observer => {
this._http.get('/app/Ressources/Items.json').map(res =>res.json()).subscribe(data=>{
observer.next(data)
observer.complete();
});
});
}
Then I have to subscribe on that method in order to get the results and do something with it. (You could be to delegate the result to a list in the GUI)
GetItems().subscribe(data=>{
myResult = data;
});
EDIT: It might help to put this in the class as well
export class MyClass{
static get parameters(){
return [[Http]];
}
}
Just try to get the response.json() rather than response.json().data in GetItems() method
The issue is because of different paths of json files in local browser(computer) and device (android). Create data folder inside the src\assets folder. Move your json file into that.
When we run ionic serve, it will move that folder (with file) into www\assets folder. Then do following things:
Import Platform service of ionic2
import { Platform } from 'ionic-angular';
Inject Platform Service.
constructor(private http: Http, private platform: Platform ) { }
Use Platform Service.
public getItems() {
var url = 'assets/data/Items.json';
if (this.platform.is('cordova') && this.platform.is('android')) {
url = "/android_asset/www/" + url;
}
return this.http.get(url)
.map((res) => {
return res.json()
});
}