Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

415 (Unsupported Media Type) with REST Post request

I have a react component that when a checkbox is pressed, it calls a rest api, post request with a single parameter.

I put a breakpoint in the webapi and its never hit, still I get a 415 unsopported media type on the component

react js component (see onchange event)

import React, { Component } from 'react';
import {  Table, Radio} from 'antd';
import { adalApiFetch } from '../../adalConfig';
import Notification from '../../components/notification';

class ListTenants extends Component {

    constructor(props) {
        super(props);
        this.state = {
            data: []
        };
    }



    fetchData = () => {
        adalApiFetch(fetch, "/Tenant", {})
          .then(response => response.json())
          .then(responseJson => {
            if (!this.isCancelled) {
                const results= responseJson.map(row => ({
                    key: row.ClientId,
                    ClientId: row.ClientId,
                    ClientSecret: row.ClientSecret,
                    Id: row.Id,
                    SiteCollectionTestUrl: row.SiteCollectionTestUrl,
                    TenantDomainUrl: row.TenantDomainUrl
                  }))
              this.setState({ data: results });
            }
          })
          .catch(error => {
            console.error(error);
          });
      };


    componentDidMount(){
        this.fetchData();
    }

    render() {
        const columns = [
                {
                    title: 'Client Id',
                    dataIndex: 'ClientId',
                    key: 'ClientId'
                }, 
                {
                    title: 'Site Collection TestUrl',
                    dataIndex: 'SiteCollectionTestUrl',
                    key: 'SiteCollectionTestUrl',
                },
                {
                    title: 'Tenant DomainUrl',
                    dataIndex: 'TenantDomainUrl',
                    key: 'TenantDomainUrl',
                }
        ];

        // rowSelection object indicates the need for row selection
        const rowSelection = {
            onChange: (selectedRowKeys, selectedRows) => {
                if(selectedRows[0].key != undefined){
                    console.log(selectedRows[0].key);


                    const options = { 
                        method: 'post', 
                        body: JSON.stringify({ clientid : selectedRows[0].key.toString() }) ,
                        config: {
                            headers: {
                              'Content-Type': 'application/json'
                            }
                          }
                    };

                    adalApiFetch(fetch, "/Tenant/SetTenantActive", options)
                        .then(response =>{
                        if(response.status === 200){
                            Notification(
                                'success',
                                'Tenant set to active',
                                ''
                                );
                        }else{
                            throw "error";
                        }
                        })
                        .catch(error => {
                        Notification(
                            'error',
                            'Tenant not activated',
                            error
                            );
                        console.error(error);
                    });
                }
            },
            getCheckboxProps: record => ({
                type: Radio
            }),
        };

        return (
            <Table rowSelection={rowSelection} columns={columns} dataSource={this.state.data} />
        );
    }
}

export default ListTenants;

and the webapi method

[HttpPost]
        [Route("api/Tenant/SetTenantActive")]
        public async Task<IHttpActionResult> SetTenantActive([FromBody]string clientid)
        {
            var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
            var allTenants = await tenantStore.Query().Where(x => x.TenantDomainUrl != null).ToListAsync();
            foreach(Tenant ten  in allTenants)
            {
                ten.Active = false;
                await tenantStore.UpdateAsync(ten);
            }

            var tenant = await tenantStore.Query().FirstOrDefaultAsync(x => x.clientid == clientid);
            if (tenant == null)
            {
                return NotFound();
            }

            tenant.Active = true;
            var result = await tenantStore.UpdateAsync(tenant);

            return Ok(result);
        }
like image 722
Luis Valencia Avatar asked Aug 08 '18 20:08

Luis Valencia


4 Answers

Couple of things I noticed.

  1. You're trying to do a POST request with a JSON body. On the client, your request looks fine.

As I understand the POST body is

{ clientid: 'some-client-id' }
  1. The interesting thing is in the web API you receive it as

public async Task<IHttpActionResult> SetTenantActive([FromBody]string clientid)

This is possibly the culprit. Your API is expecting a string as a POST body where it is a json object. Have you tried changing the type to dynamic or JObject?

So, essentially,

public async Task<IHttpActionResult> SetTenantActive([FromBody]dynamic clientRequest)

OR

public async Task<IHttpActionResult> SetTenantActive([FromBody]JObject clientRequest)

Alternately,

If you want to continue using your API as is, then you can just change the request you’re making from the client to ’some-client-id’ instead of { clientid: 'some-client-id' }

like image 176
dkulkarni Avatar answered Oct 20 '22 08:10

dkulkarni


Change

const options = { 
    method: 'post', 
    body: JSON.stringify({ clientid : selectedRows[0].key.toString() }) ,
    config: {
        headers: {
            'Content-Type': 'application/json'
        }
    }
};

to

const options = { 
    method: 'post', 
    body: JSON.stringify({ clientid : selectedRows[0].key.toString() }) ,
    headers: {
        'Content-Type': 'application/json; charset=utf-8'
    }
};
like image 33
Pavlo Avatar answered Oct 20 '22 06:10

Pavlo


Check your server settings. By default it should support json but its better to verify it. Also try to clear Accept header in yor api code and set to * which means all types.

Moreover check adalApiFetch method. What headers it send? Is the format of Content-Type used & set correctly?

like image 30
Andrew Avatar answered Oct 20 '22 07:10

Andrew


For a simple RESTFul call like that you could follow suggestion naming conventions along with HTTP verbs that better clarifies the intention and simplify the call itself. No need to over complicate the API model for such a simple call.

Something like

[HttpPut] // Or HttpPost. PUT is usually used to update the resourcce
[Route("api/Tenant/{clientid}/Active")]
public async Task<IHttpActionResult> SetTenantActive(string clientid) {
    var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
    var allTenants = await tenantStore.Query().Where(x => x.TenantDomainUrl != null).ToListAsync();
    var updates = new List<Task>();
    foreach(Tenant ten  in allTenants) {
        ten.Active = false;
        updates.Add(tenantStore.UpdateAsync(ten));
    }

    await Task.WhenAll(updates);

    var tenant = await tenantStore.Query().FirstOrDefaultAsync(x => x.clientid == clientid);
    if (tenant == null)
    {
        return NotFound();
    }

    tenant.Active = true;
    var result = await tenantStore.UpdateAsync(tenant);

    return Ok(result);
}

And on the client

const rowSelection = {
    onChange: (selectedRowKeys, selectedRows) => {
        if(selectedRows[0].key != undefined){
            var clientid = selectedRows[0].key;
            console.log(clientid);

            var url = "/Tenant/" + clientid + "/Active"

            const options = { 
                method: 'put'
            };

            adalApiFetch(fetch, url, options)
                .then(response => {
                if(response.status === 200){
                    Notification(
                        'success',
                        'Tenant set to active',
                        ''
                        );
                }else{
                    throw "error";
                }
                })
                .catch(error => {
                Notification(
                    'error',
                    'Tenant not activated',
                    error
                    );
                console.error(error);
            });
        }
    },
    getCheckboxProps: record => ({
        type: Radio
    }),
};
like image 20
Nkosi Avatar answered Oct 20 '22 06:10

Nkosi