web-dev-qa-db-ja.com

415(サポートされていないメディアタイプ)with RESTポストリクエスト

チェックボックスが押されると、単一のパラメーターでrest api、postリクエストを呼び出すreactコンポーネントがあります。

Webapiにブレークポイントを設定しましたが、ヒットしませんでしたが、コンポーネントに415のサポートされていないメディアタイプが表示されます

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;

およびwebapiメソッド

[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);
        }
5
Luis Valencia

私が気づいたいくつかのこと。

  1. JSON本文を使用してPOSTリクエストを実行しようとしています。クライアントでは、リクエストは問題ないように見えます。

私が理解しているように、POST本体は

_{ clientid: 'some-client-id' }
_
  1. 興味深いのは、次のように受け取るWebAPIにあります。

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

これが原因である可能性があります。 APIは、文字列をPOST bodyであり、jsonオブジェクトであると想定しています。タイプをdynamicまたはJObjectに変更してみましたか?

だから、本質的に、

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

OR

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

または、

APIをそのまま使用し続ける場合は、クライアントからのリクエストを_’some-client-id’_ではなく_{ clientid: 'some-client-id' }_に変更するだけです。

2
dkulkarni

サーバーの設定を確認してください。デフォルトではjsonをサポートする必要がありますが、確認することをお勧めします。また、yorapiコードのAcceptヘッダーをクリアし、すべてのタイプを意味する*に設定してみてください。

さらに、adalApiFetchメソッドを確認してください。送信するヘッダーは何ですか? Content-Typeのフォーマットは正しく使用され、設定されていますか?

1
Andrew

変化する

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

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

このような単純なRESTFul呼び出しの場合、意図をより明確にし、呼び出し自体を単純化するHTTP動詞とともに、提案の命名規則に従うことができます。このような単純な呼び出しのためにAPIモデルを過度に複雑にする必要はありません。

何かのようなもの

[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);
}

そしてクライアントで

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
    }),
};
1
Nkosi

なぜpostを使用しているのですか? 'REST`yの観点からは、エンティティ(この場合はテナント)を作成するために使用されます。

意図された単純な要求は、ルートの一部としてGETを使用してclientidを介して解決できます。

[HttpGet]
[Route("api/Tenant/SetTenantActive/{clientid}")]
public async Task<IHttpActionResult> SetTenantActive(string clientid)
{
   // ...
}
0
Jürgen Röhr