Phoenix API, Angular 2 can't consume the API

Hello, I’ve created a simple API using Phoenix, then generated the resource mix phoenix.gen.json User users username:string age:integer email:string

Nothing too fancy, after that, just added the route in the controller and it works like a charm, but then, I try to fetch the users from the api using Angular 2, I’ve already added Corsica to my application and allow requests from everywhere plug Corsica, origins: "*", however I keep getting the

CORS header ‘Access-Control-Allow-Origin’ missing

I’ve already included a header in my requests as you can see here

getUsers() {
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });
    return this.http.get(this.apiUrl + 'users', options)
      .map(res => res.json());
  }

On the Angular side it seems to be doing the request fine, but the API just says not going to happen.

Anyone experienced the same issue or knows what is a possible solution?

Thanks for your time!

1 Like

This sounds like you have placed plug Corsica, origins: "*" in the wrong place, or otherwise the VM encountered a runtime error that was handled by Plug.ErrorHandler thereby nullifying the plug pipeline’s modifications to response headers.

Please provide:

  • The placement of the plug Corsica line
  • The integer response status code from the server when this error occurs

I’ve placed plug Corsica, origins: "*" in my /lib/projectname/endpoint.ex. I don’t get a response status on my Elixir app, neither running mix phoenix.server nor iex -S mix phoenix.server and in my client I just get

Service ready…
Angular 2 is running in the development mode. Call enableProdMode() to enable the production mode.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource … (Reason: CORS header ‘Access-Control-Allow-Origin’ is missing).

Edit: My GET request returns 302 in the network tab, cause xhr, type plain.

plug Corsica, origins: "*" has been placed prior to the line plug MyApp.Router (substituting relevant application name), correct?

Yes it’s like this

plug Corsica, origins: "*"
plug TheScienceOfCode.Router

By the way, I’ve updated my previous answer with the integer response.

Is the 302 being generated by your controller?

I don’t think so, I haven’t modified a single line in my controller or view

# Controller
def index(conn, _params) do
  users = Repo.all(User)
  render(conn, "index.json", users: users)
end

# View
def render("index.json", %{users: users}) do
  %{data: render_many(users, TheScienceOfCode.UserView, "user.json")}
end

I can visit my application at /api/users and get the list of users, but seems like CORS hates me.

When running the server, do you see a log entry for the Angular attempt to fetch the data?

Nope

$ iex -S mix phoenix.server
Erlang/OTP 19 [erts-8.0] [source-6dc93c1] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
[info] Running TheScienceOfCode.Endpoint with Cowboy using http://localhost:8081
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)

So then it would stand to reason that the issue is actually in your Angular application and it never actually reaches your Elixir application.

But it actually tries to hit the application, how would I get the headers issue then?

Changing the apiUrl to GitHub works like a charm:

@Injectable()
export class TSOCService {
  private apiUrl = 'https://api.github.com/';

  constructor(private http: Http) {
    console.log('Service ready...');
  }
  
  getUsers() {
    // headers are no needed for GitHub
    return this.http.get(this.apiUrl + 'users')
      .map(res => res.json());
  }
}

If you don’t have a log line showing on your Elixir application, then it’s not receiving a request. So the Angular application is probably hitting some other service that is returning a 302.

1 Like

But I don’t get why it doesn’t receive the request, I’ve the api running on port 8081 and the Angular app on 8080, if I change port or anything I just get EXCEPTION: Response with status: 0 for URL: null which means I’m hitting the right url, and as I said, doing it to the GitHub api works like a charm.

Edit: Finally got it working, the issue was Cloud9, my workspace was private, which at the time of a request required a login

curl -i -H “Accept: application/json” -H “Content-Type: application/json” -X GET https://elixir-oxyrus.c9users.io/api/users
HTTP/1.1 302 Found
Location: https://c9users.io/_user_content/authorize?redirect=https%3A%2F%2Felixir-oxyrus.c9users.io%2Fapi%2Fusers
Date: Mon, 28 Nov 2016 01:26:58 GMT
Transfer-Encoding: chunked
X-BACKEND: apps-proxy

Changing the workspace to public solved the issue:

curl -i -H “Accept: application/json” -H “Content-Type: application/json” -X GET https://elixir-oxyrus.c9users.io/api/users
HTTP/1.1 200 OK
server: Cowboy
date: Mon, 28 Nov 2016 01:29:03 GMT
content-length: 198
content-type: application/json; charset=utf-8
cache-control: max-age=0, private, must-revalidate
x-request-id: g5ganckdv7lr6rl12mm8r05u16mk0an0
X-BACKEND: apps-proxy
{“data”:[{“username":“Oxyrus”,“id”:1,“email”:"im.oxyrus@gmail.com”,“age”:18},{“username":“Zero”,“id”:2,“email”:"user1@users.com”,“age”:18},{“username":“One”,“id”:3,“email”:"one@users.com”,“age”:1}]}

Weird errors, anyways, thank you @DavidAntaramian for your help!

1 Like