Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

boldstar's avatar

API post to store method return 500 internal server error

Hi, i am trying to post a form to my laravel backend but I keep getting a 500 internal server error. Im using a vue frontend with axios to send the post request.

here is my route

Route::post('/engagements', 'EngagementsController@store');

here is the EngagementsController for the store method

public function store(Request $request)
    {
        $data = $request->validate([
            'return_type' => 'required|string',
            'year' => 'required|string',
            'status' => 'required|string',
            'assigned_to' => 'required|string',
            'done' => 'required|boolean'
        ]);

        $engagement = Engagement::create([
            'client_id' => client()->id,
            'return_type' => $request->return_type,
            'year' => $request->year,
            'assigned_to' => $request->assigned_to,
            'status' => $request->status,
            'done' => $request->done,
        ]);

        return response($engagement, 201);
    }

and this is the Engagement model it references

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Engagement extends Model
{
    public function client() 
    {
        return $this->belongsTo('App\Client');
    }

    public function engagement_tasks()
    {
        return $this->belongsToMany('App\Task');
    }

}

I believe my issue is coming from the 'client_id' that is being added for the belongsTo() relationship it has with the parent model Client.

Currently my relationships are

  1. User has many Tasks
  2. Task belongs to User
  3. Client has many Engagements
  4. Engagement belongs to Client
  5. Engagement and Tasks have a many to many relationship

So I understand that when I submit data belonging to a user like this

'user_id' => auth()->user()->id,

on the store method it will reference the user model but for some reason that does not work for the client like this

'client_id' => client()->id,

I believe i am missing a step that is telling laravel which client the new engagement belongs to but Im not sure what that step is..

Any help would be greatly appreciated!!!

0 likes
16 replies
Tray2's avatar

Where does the client_id come from?

Shouldn't it be $request->client_idinstead of Client()->id?

Or is the Client()method a helper that fetches it in the background?

I would pass the client id in via the Request object like all the other values.

Snapey's avatar

look at the error.. it's usually helpful

Snapey's avatar

ok. what is client() ?

you will have mass assignment issue with your model

You need to authenticate the request (client_id could be anything)

1 like
boldstar's avatar

Apologies for the late response, @Snapey & @Tray2

@Snapey, im not sure what you mean about 'what is client()?'

the EngagementsController references App\Engagement which is this model below

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Engagement extends Model
{
    public function client() 
    {
        return $this->belongsTo('App\Client');
    }

    public function engagement_tasks()
    {
        return $this->belongsToMany('App\Task');
    }

}

So the client_id is a foreign key on my engagements table...

on the front end i am capturing the id of the client in the URL , but this may be where I am making a mistake..

should there be more parameters being passed on the Engagement model?

Snapey's avatar

here

'client_id' => client()->id,

client() is a function. To use it this way you would need to have a global client helper called that.

You answer tells me it is a relationship, but that can only be accessed from a model, as in $engagement->client()

Take it one step at a time and look at your Laravel Log file to see what is causing 500 error.

Tray2's avatar

If you pass the client_id in the url as a query string you should use it from the request.

$request->query('client_id');

If you pass it in the header use it from the request

$request->client_id;

If you pass it in the url /model/1

You must add a parameter to your store method

public function store(Request $request, $client_id)
{
}
boldstar's avatar

Okay so I would love to view my laravel log file but I do not know where it is at.. when i try using postman to see what response I get, It does not return a stack to me except after I added the

public function store(Request $request, $client_id)

After I insert the $client_id as a parameter I do get an error response from that...

Symfony\Component\Debug\Exception\FatalThrowableError: Too few arguments to function App\Http\Controllers\EngagementsController::store(), 1 passed and exactly 2 expected in file C:\laragon\www\traxit\app\Http\Controllers\EngagementsController.php on line 53
Tray2's avatar

Then you need to update your route

Route::post('/engagements/{client_id}', 'EngagementsController@store');

But I think it's better to pass the client_id in the request instead.

boldstar's avatar

@Tray2 , so im still struggling with this I have found an example like below..

public function store($family_id, ContactRequest $request)
{
    $family = Family::findOrFail($family_id);
    $contact = $family->contacts()->create($request->all());

    return $contact;

    //  return redirect('families/' . $family_id);
}

Where they pass the $id first before the request but what I can't grasp is the data that I am sending to the store method from vue front end. Should I be capturing the URL client_id. here is what I have happening on the front end...

This is my form and the url in vue

add-engagement/{client_id}

this is the form

<template>
  <div class="page-wrapper mt-1">
    <div class="add-engagement container">
      <div class="card-body bg-light border-primary mb-2">
        <h4 class="text-left text-primary m-0"><i class="mr-3 far fa-folder-open"></i>New Engagement</h4>
      </div>
        <form @submit.prevent="addEngagement" class="d-flex-column justify-content-center">
          <div class="form-group">
            <select class="form-control mb-3" id="type" v-model="engagement.return_type">
              <option v-for="type in types" :key="type.id" :value="type">{{ type }}</option>
            </select>
            <input type="text" class="form-control mb-3" placeholder="Year" v-model="engagement.year">
            <input type="text" class="form-control mb-3" placeholder="Assign To" v-model="engagement.assigned_to">
            <input type="text" class="form-control mb-3" placeholder="Status" v-model="engagement.status">

            <button type="submit" class="btn btn-lg btn-primary d-flex justify-content-start">Create</button>
          </div>
        </form>
      </div>  
  </div>
</template>

<script>


export default {
  name: 'add-engagement',
  data() {
    return {
      engagement: {
        return_type: null,
        year: '',
        assigned_to: '',
        status: '',
      },
      types: [ 
        'Choose Return Type...', 
        '1040', 
        '1120',
      ],
    }
  },
   methods: {
    addEngagement(e) {
      if(!this.engagement.return_type || !this.engagement.year ){
        return
      } else {
        this.$store.dispatch('addEngagement', {
          id: this.idForEngagement,
          return_type: this.engagement.return_type,
          year: this.engagement.year,
          assigned_to: this.engagement.assigned_to,
          status: this.engagement.status,
        })
        e.preventDefault();
      }
      e.preventDefault();
      this.engagement = "" 
      this.idForEngagement++
      this.$router.push('/engagements')
    },
  },
  created: function() {
    this.engagement.return_type = this.types[0]
  },

}
</script>

and this is the store.js file that is being dispatched to send the request to my laravel api route

addEngagement(context, engagement) {
      axios.post(('/engagements'), {
        return_type: engagement.return_type,
        year: engagement.year,
        assigned_to: engagement.assigned_to,
        status: engagement.status,
        done: false
      })
      .then(response => {
        context.commit('getClientEngagement', response.data)
      })
      .catch(error => {
        console.log(error)
      })
    },

Now notice that the post addEngagement method is mentioning nothing about the client_id.. does it need to be? since the client_id is a foreign_key?

Tray2's avatar
addEngagement(e) {
      if(!this.engagement.return_type || !this.engagement.year ){
        return
      } else {
        this.$store.dispatch('addEngagement', {
          id: this.idForEngagement,
          return_type: this.engagement.return_type,
          year: this.engagement.year,
          assigned_to: this.engagement.assigned_to,
          status: this.engagement.status,

      client_id: this.engagement.client_id  //Here is where you should assign it.

        })
....

If you add it to your request you don't have to pass any extra parameters in the route. And then you can use it like any of the other parameters you pass to the controller in the request.

Snapey's avatar

Now notice that the post addEngagement method is mentioning nothing about the client_id.. does it need to be? since the client_id is a foreign_key?

Its only a foreign key on engagements that actually exist. If you are creating a new engagement and it belongs to client then you need to tell laravel which client it should belong to.

You also need to check that the user is allowed to create engagement for the client_id mentioned since anyone can tamper with the request

boldstar's avatar

Perhaps I am getting outside my understand at the moment.. I did notice that I was using postman wrong and trying to pass the form data in the header instead of the body

So now that I am doing that correctly I will show you the error I am getting and perhaps I am headed in a better direction now

this is the error I get back in postman

Illuminate\Database\QueryException: SQLSTATE[HY000]: General error: 1364 Field &#039;return_type&#039; doesn&#039;t have a default value (SQL: insert into `engagements` (`client_id`, `updated_at`, `created_at`) values (1, 2018-09-15 18:51:13, 2018-09-15 18:51:13)) in file C:\laragon\www\traxit\vendor\laravel\framework\src\Illuminate\Database\Connection.php on line 664

This is the setup in my EngagementsController file

public function store(Request $request)
    {
        $data = $request->validate([
            'client_id' => 'required|integer',
            'return_type' => 'required|string',
            'year' => 'required|string',
            'status' => 'required|string',
            'assigned_to' => 'required|string',
            'done' => 'required|boolean'
        ]);

        $engagement = Engagement::create([
            'client_id' => $request->client_id,
            'return_type' => $request->return_type,
            'year' => $request->year,
            'assigned_to' => $request->assigned_to,
            'status' => $request->status,
            'done' => $request->done,
        ]);

        return response($engagement, 201);
    }

This is the Engagement Model

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Engagement extends Model
{
    protected $fillable =
    [
        'client_id'
    ];
    public function client() 
    {
        return $this->belongsTo('App\Client');
    }

    public function engagement_tasks()
    {
        return $this->belongsToMany('App\Task');
    }

}

At first passing the data through the body I was getting a mass assignment alarm as you suggested earlier @Snapey so i added

protected $fillable =
    [
        'client_id'
    ];

is this the correct way to handle the mass assignment issue? I did not get the alarm after applying it...

Cronix's avatar

You need to add these fields to the fillable array as well

'return_type'
'year'
'assigned_to'
'status'
'done'

Everything you are passing to the create() method needs to be in the fillable array or they won't get saved.

You'll notice the query is only saving these fields client_id, updated_at, created_at

1 like
Snapey's avatar

or if those fields are optional, you need to set then as nullable in the database

boldstar's avatar
boldstar
OP
Best Answer
Level 2

Setting all fillable fields fixed the alarm issue and as far as the EngagementsController I reverted back to this

public function store(Request $request)
    {
        $data = $request->validate([
            'client_id' => 'required|integer',
            'return_type' => 'required|string',
            'year' => 'required|string',
            'status' => 'required|string',
            'assigned_to' => 'required|string',
            'done' => 'required|boolean'
        ]);

        $engagement = Engagement::create([
            'client_id' => $request->client_id,
            'return_type' => $request->return_type,
            'year' => $request->year,
            'assigned_to' => $request->assigned_to,
            'status' => $request->status,
            'done' => $request->done,
        ]);

        return response($engagement, 201);
    }

Thank you, @Snapey, @Cronix, @Tray2

Please or to participate in this conversation.