Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

POST request works with Postman, but not with axios or .fetch()

I've got a problem that I've been working on now for a few days now and can't find the solution. I created an API with Lumen and a frontend with ReactJS. This all works fine with a GET request, but it fails when I send a POST request. For some strange reasons the requests works when I send it with Postman. Now some Code!

First of all the JS-Script that sends the request:

import moment from 'moment';
import React, {Component} from 'react';
import { Modal, Form, Button, Input, DatePicker, Select, message } from 'antd';

const {RangePicker} = DatePicker;
const FormItem = Form.Item;
const Option = Select.Option;

const api_url = 'api/v1/';

class NewEventForm extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            confirmLoading: false,
            categories: []
        };

        this.onCreate = this.onCreate.bind(this);
        this.onCancel = this.onCancel.bind(this);
    }

    componentDidMount() {
        fetch(api_url + 'category')
        .then(results => {
            return results.json();
        }).then(data => {
            let categories = data.map((cat) => {
                return (
                    <Option key={cat.id} value={cat.id}>{cat.name}</Option>
                    );
            });
            this.setState({categories: categories});
        });
    }
    
    updateStates() {
        this.props.updateState();
        this.setState({confirmLoading: false});
    }

    onCreate() {
        this.props.form.validateFields((err, values) => {
            this.setState({
                confirmLoading: true
            });

            if (err) {
                this.setState({
                    confirmLoading: false
                });
                return;
            }
            
            let event = {
                title: values.title,
                description: values.description,
                start_time: values.date[0],
                end_time: values.date[1],
                category_id: values.category
            };
            
            fetch(api_url + 'event', {
                method: 'POST',
                /* headers are important*/
                headers: {
                    "content-type":"application/json",
                    "cache-control":"no-cache",
                    "accept":"*/*",
                },
                body: JSON.stringify(event)
            }).then(response => {
                if(response.ok) {
                    return response.json();
                }
                throw new Error("Antwort der API war nicht 'Ok'!");
            }).then(data =>{
                this.updateStates();
                
                message.success('Das Ereignis wurde erfolgreich eingetragen!');              
            }).catch(error => {
                //console.log(error);
                this.updateStates();
                
                message.error('Das Ereignis wurde nicht erstellt. Bitte versuche es später nochmal!'); 
            });
        });
    }
    onCancel(e) {
        e.preventDefault();

        this.updateStates();
    }

    render() {
        const {getFieldDecorator, getFieldError} = this.props.form;

        return(
                <Modal title="Neue Veranstaltung hinzufügen" okText="Eintragen" confirmLoading={this.state.confirmLoading} visible={this.props.visible} onOk={this.onCreate} onCancel={this.onCancel}>
                    <Form layout="vertical">
                        <FormItem label="Titel">
                            {getFieldDecorator('title', {
                                rules: [{required: true, message: 'Bitte einen Titel angeben!' }],
                            })(
                            <Input />
                            )}
                        </FormItem>
                        <FormItem label="Beschreibung">
                            {getFieldDecorator('description')(<Input type="textarea" />)}
                        </FormItem>
                        <FormItem label="Kategorie">
                            {getFieldDecorator('category', {
                                rules: [{required: true, message: 'Bitte einen Kategorie auswählen!' }],
                            })(
                            <Select placeholder="Kategorie auswählen...">
                                {this.state.categories}
                            </Select>
                            )}
                        </FormItem>
                        <FormItem label="Zeitraum" className="collection-create-formlast-form-item">
                            {getFieldDecorator('date', {
                                rules: [{required: true, message: 'Bitte einen Zeitraum auswählen!' }],
                            })(
                            <RangePicker
                                showTime={{
                                    hideDisabledOptions: true,
                                    defaultValue: [moment('00:00', 'HH:mm'), moment('00:00', 'HH:mm')],
                                    format: 'HH:mm'
                                }}
                                format="DD.MM.YYYY HH:mm"
                                />
                            )}
                        </FormItem>
                    </Form>
                </Modal>
                );
    }
}

export const NewEventModal = Form.create()(NewEventForm);

My database has three models. Event, Category and User: Category.id<---1:n--->Event.category_id||Event.updated_by<---n:1--->User.id

Now the EventController:

<?php

namespace App\Http\Controllers;

use App\Event;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;


class EventController extends Controller{


    public function index(){
        $Events = Event::all();

        return response()->json($Events);  
    }

    public function getEvent($id){  
        $Event = Event::with(['category', 'user'])->find($id);

        return response()->json($Event);
    }

    public function createEvent(Request $request){
        $User  = \App\User::find(1);
        $Category = \App\Category::find(1);

        $Event = new Event;
        $Event->fill($request->all());
        $Event->user()->associate($User);
        $Event->category()->associate($Category);

        $obj = '';
        foreach ($request->all() as $key => $value) {
            $obj .= '[' . $key . '] => "' . $value . '"; ';
        }

        \Log::warning('Test: ' . $obj);

        $Event->save();

        return response()->json($request);  
    }

    public function deleteEvent($id){
        $Event = Event::find($id);
        $Event->delete();

        return response()->json('deleted');
    }

    public function updateEvent(Request $request,$id){
        $Event = Event::find($id);
        $Event->title = $request->input('title');
        $Event->description = $request->input('description');
        $Event->start_time = $request->input('start_time');
        $Event->end_time = $request->input('end_time');
        $Event->save();

        return response()->json($Event);
    }

}

And the EventModel:

<?php
namespace App;

use Illuminate\Database\Eloquent\Model;

class Event extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
     protected $fillable = ['title', 'description', 'start_time', 'end_time'];

     public function user() {
         return $this->belongsTo('App\User', 'updated_by');
     }

     public function category() {
         return $this->belongsTo('App\Category');
     }
}

Like I said is everything working as expected, when I use Postman, to send the POST-Request. But with my fetch()-function I get a 200-response, but in the database there is only "created_at" and "updated_at" filled and the rest is just an empty string. The Log-statment in the EventController shows, that is seems as the Request-object is empty. But looking in the Firefox-developer tools I see that the data is send in the request body.

So any ideas? I can also send other code-files if needed.

Thank you all already for your help Marco

EDIT: As it was not obvious, the API and Frontend are both running on the same host; localhost:8000 so it's not a CORS-issue. I had first running the Frontend on localhost:8080 but I eliminated that by running both on the same server.

like image 280
Mainz007 Avatar asked Jan 13 '18 14:01

Mainz007


1 Answers

As expected when noone was really able to answer my question directly, my fault was not obvious. I recognized today with a freind, that the request I actually send is different from what I wrote in the code. With some more searching I found out that my webpack.config was somehow misconfigured and published the code in the wrong directory. But since there was already an "older" js-file the page looked correct but didn't have the changes of my API-Call.

TL;DR Pay attention that everything lies where you need it and then the code above is correct :-)

like image 199
Mainz007 Avatar answered Oct 26 '22 16:10

Mainz007