namonaki's avatar

error 405

hello i have this 405 error while creating a ticket from my flutter mobile app (i am linking laravel 5.6 with flutter) but when i test the endpoint in postman it works the error only happens when i try creating in flutter this is the routes/api:

Route::middleware('auth:api')->group(function () {
 Route::get('tickets', [TicketController::class, 'index']); 
Route::get('tickets/create', [TicketController::class, 'create']); 
Route::post('tickets', [TicketController::class, 'store']); 
Route::get('tickets/{ticket}', [TicketController::class, 'show']); 
Route::get('tickets/{ticket}/edit', [TicketController::class, 'edit']); 
Route::put('tickets/{ticket}', [TicketController::class, 'update']);
 Route::delete('tickets/{ticket}', [TicketController::class, 'destroy']); 
Route::put('tickets/{ticket}/validate', [TicketController::class, 'validateTicket']); }); 

note that when i get the tickets list it works i am using this

/// Route::post('tickets', [TicketController::class, 'store']); 

and i am calling it using dio.post, the baseurl is my domain/api/tickets, note that in the postman they all work

0 likes
16 replies
Tray2's avatar

405 means that you don't have a route that supports the method used.

Check what flutter sends and make sure it matches what you have in your routes file.

namonaki's avatar

@Tray2 this is the flutter code :

//   code api avec dio package pour createTickets
Future<void> createComplaint({
  required String address,
  required String description,
  required String status,
  required String priority,
  required String category,
  File? image,
  required String token,
}) async {
  try {
    FormData createFormData() {
      return FormData.fromMap({
        'address': address,
        'description': description,
        'status': status,
        'priority': priority,
        'category': category,
        if (image != null) 
          'attachment': MultipartFile.fromFileSync(image.path),
      });
    }

    print('Sending request to $baseUrl with token: $token');

    Response response = await _dio.post(
      baseUrl, // Ensure this URL is correct and expects a POST request
      data: createFormData(),
      options: Options(
        headers: {
          'Authorization': 'Bearer $token',
        },
        validateStatus: (status) {
          return status! < 500; // Accept all status codes below 500
        },
      ),
    );

    // Handle 302 redirection
    if (response.statusCode == 302) {
      String? redirectUrl = response.headers['location']?.first;
      if (redirectUrl != null) {
        print('Following redirection to: $redirectUrl');
        response = await _dio.post(
          redirectUrl,
          data: createFormData(),
          options: Options(
            headers: {
              'Authorization': 'Bearer $token',
            },
            validateStatus: (status) {
              return status! < 500;
            },
          ),
        );
      }
    }

    print('Response status code: ${response.statusCode}');
    print('Response data: ${response.data}');
    print('Response headers: ${response.headers}');

    if (response.statusCode != 200 && response.statusCode != 201) {
      throw Exception('Failed to create complaint. Status code: ${response.statusCode}');
    }
  } catch (e) {
    print('Error creating complaint: $e');
    rethrow;
  }
}

//code de controller:
 Future<void> addComplaint(Complaint complaint) async {
    String? token = gsService.getToken();
    const String createComplaintUrl = 'domain/api/tickets';

    if (token != null) {
      try {
        await apiService.createComplaint(
          address: complaint.address,
          description: complaint.description,
          status: complaint.status,
          priority: complaint.priority,
          category: complaint.category,
          image: complaint.attachmentUrl != null ? File(complaint.attachmentUrl!) : null,
          token: token,
         
        );
        complaints.add(complaint);
        Get.snackbar("Success", "Complaint created successfully");
      } catch (e) {
        Get.snackbar("Error", "Failed to create complaint: ${e.toString()}");
        logger.e("Error creating complaint: $e");
      }
    } else {
      Get.snackbar("Error", "Token not found");
      logger.e("Error: Token not found");
    }
  } 

we are using post and we doubled checked the url , the problem is that when we test using postman it works but in the flutter app it gives 405 how can we fix it

namonaki's avatar

//login+logout API Route::post('register', [AuthController::class, 'register']); Route::post('login', [AuthController::class, 'login']);

Route::middleware('auth:api')->group(function () { Route::post('logout', [AuthController::class, 'logout']); Route::get('user', function(Request $request) { return $request->user(); }); });

//user tickets Route::middleware('auth:api')->group(function () { Route::get('tickets', [TicketController::class, 'index']); Route::get('tickets/create', [TicketController::class, 'create']); Route::post('tickets', [TicketController::class, 'store']); Route::get('tickets/{ticket}', [TicketController::class, 'show']); Route::get('tickets/{ticket}/edit', [TicketController::class, 'edit']); Route::put('tickets/{ticket}', [TicketController::class, 'update']); Route::delete('tickets/{ticket}', [TicketController::class, 'destroy']); Route::put('tickets/{ticket}/validate', [TicketController::class, 'validateTicket']); });

Tray2's avatar

@namonaki Place all code between three back ticks ´

//Code goes here
namonaki's avatar

@Tray2 ''' /// //login+logout API Route /// post('register', [AuthController::class, 'register']); Route::post('login', [AuthController::class, 'login']); /// Route::middleware('auth:api')->group(function () { Route::post('logout', [AuthController::class, 'logout']); /// Route::get('user', function(Request $request) { return $request->user(); }); }); /// //user tickets /// Route::middleware('auth:api')->group(function () /// { Route::get('tickets', [TicketController::class, 'index']); /// Route::get('tickets/create', [TicketController::class, 'create']); /// Route::post('tickets', [TicketController::class, 'store']); /// Route::get('tickets/{ticket}', [TicketController::class, 'show']); /// Route::get('tickets/{ticket}/edit', [TicketController::class, 'edit']); /// Route::put('tickets/{ticket}', [TicketController::class, 'update']); /// Route::delete('tickets/{ticket}', [TicketController::class, 'destroy']); /// Route::put('tickets/{ticket}/validate', [TicketController::class, 'validateTicket']); }); /// '''

namonaki's avatar

@Tray2

 //login+logout API Route
 /// post('register', [AuthController::class, 'register']); 
///Route::post('login', [AuthController::class, 'login']);
 /// Route::middleware('auth:api')->group(function () {
// Route::post('logout', [AuthController::class, 'logout']);
 /// Route::get('user', function(Request $request) { return $request->user(); }); }); 

 //user tickets 
/// Route::middleware('auth:api')->group(function () 
/// { Route::get('tickets', [TicketController::class, 'index']); 
/// Route::get('tickets/create', [TicketController::class, 'create']); 
/// Route::post('tickets', [TicketController::class, 'store']); 
/// Route::get('tickets/{ticket}', [TicketController::class, 'show']); 
/// Route::get('tickets/{ticket}/edit', [TicketController::class, 'edit']); 
/// Route::put('tickets/{ticket}', [TicketController::class, 'update']); 
/// Route::delete('tickets/{ticket}', [TicketController::class, 'destroy']); 
/// Route::put('tickets/{ticket}/validate', [TicketController::class, 'validateTicket']); });     ```
namonaki's avatar

@Tray2 no no this is just befor i used the ` back ticks just to seperate the routes my actual routes are :

//login+logout API
Route::post('register', [AuthController::class, 'register']);
Route::post('login', [AuthController::class, 'login']);

Route::middleware('auth:api')->group(function () {
    Route::post('logout', [AuthController::class, 'logout']);
    Route::get('user', function(Request $request) {
        return $request->user();
    });
});
//user tickets
Route::middleware('auth:api')->group(function () {
    Route::get('tickets', [TicketController::class, 'index']);
    Route::get('tickets/create', [TicketController::class, 'create']);
    Route::post('tickets', [TicketController::class, 'store']);
    Route::get('tickets/{ticket}', [TicketController::class, 'show']);
    Route::get('tickets/{ticket}/edit', [TicketController::class, 'edit']);
    Route::put('tickets/{ticket}', [TicketController::class, 'update']);
    Route::delete('tickets/{ticket}', [TicketController::class, 'destroy']);
    Route::put('tickets/{ticket}/validate', [TicketController::class, 'validateTicket']);
});

i have a 405 error everytime i create a ticket

Route::post('tickets', [TicketController::class, 'store']);
the url i use in flutter is  mydomain/api/tickets
and i am using dio.post
when i test the endpoint in postman no error 
Tray2's avatar

@namonaki Well then, press F12 in your browser and take a look at what it attempts to access, and compare that to your routes file. My guess is that you have a missing /, or one more than you need.

Tray2's avatar

@namonaki No, because with postman you know what method you use, and in flutter you don't, so you need to verify that flutter uses the correct method.

DhPandya's avatar

@namonaki Which route you're calling from your flutter routes? The post is failed to specify on which route you're getting 405? Seems like the method of the routes is different than declared in the route file.

For an example: Route::post('logout', [AuthController::class, 'logout']); /// This is post route but if you trigger it using the get request then it will throw 405 error. Please cross check the method with which you are encounterring the 405 eror.

namonaki's avatar

@DhPandya i am using this :

 Route::post('tickets', [TicketController::class, 'store']); 

POST mydomain/api/tickets

// this is the flutter code and we are using dio.post
//   code api avec dio package pour createTickets


Future<void> createComplaint({
  required String address,
  required String description,
  required String status,
  required String priority,
  required String category,
  File? image,
  required String token,
}) async {
  try {
    FormData createFormData() {
      return FormData.fromMap({
        'address': address,
        'description': description,
        'status': status,
        'priority': priority,
        'category': category,
        if (image != null) 
          'attachment': MultipartFile.fromFileSync(image.path),
      });
    }

    print('Sending request to $baseUrl with token: $token');

    Response response = await _dio.post(
      baseUrl, // my domain/api/tickets
      data: createFormData(),
      options: Options(
        headers: {
          'Authorization': 'Bearer $token',
        },
        validateStatus: (status) {
          return status! < 500; // Accept all status codes below 500
        },
      ),
    );

    // Handle 302 redirection
    if (response.statusCode == 302) {
      String? redirectUrl = response.headers['location']?.first;
      if (redirectUrl != null) {
        print('Following redirection to: $redirectUrl');
        response = await _dio.post(
          redirectUrl,
          data: createFormData(),
          options: Options(
            headers: {
              'Authorization': 'Bearer $token',
            },
            validateStatus: (status) {
              return status! < 500;
            },
          ),
        );
      }
    }

    print('Response status code: ${response.statusCode}');
    print('Response data: ${response.data}');
    print('Response headers: ${response.headers}');

    if (response.statusCode != 200 && response.statusCode != 201) {
      throw Exception('Failed to create complaint. Status code: ${response.statusCode}');
    }
  } catch (e) {
    print('Error creating complaint: $e');
    rethrow;
  }
}

the endpoint works in postman but in flutter is giving 405

Merklin's avatar

As said by @DhPangya, you cannot send data to post route. You should call the route where your form is, fill the form and then call the store method.

Please or to participate in this conversation.