Comment POSTER un JSON brut entier dans le corps d'une demande de modification?

285

Cette question a peut-être été posée auparavant mais non, elle n'a pas été résolue de manière définitive. Comment poster exactement un JSON entier brut dans le corps d'une demande de modification?

Voir la question similaire ici . Ou cette réponse est-elle correcte, elle doit être codée sous forme d'URL et passée sous forme de champ ? J'espère vraiment que non, car les services auxquels je me connecte n'attendent que du JSON brut dans le corps du message. Ils ne sont pas configurés pour rechercher un champ particulier pour les données JSON.

Je veux juste clarifier cela avec les experts une fois pour toutes. Une personne a répondu de ne pas utiliser Retrofit. L'autre n'était pas certain de la syntaxe. Un autre pense que oui, cela peut être fait mais seulement si sa forme est encodée en URL et placée dans un champ (ce n'est pas acceptable dans mon cas). Non, je ne peux pas recoder tous les services pour mon client Android. Et oui, il est très courant dans les grands projets de publier du JSON brut au lieu de passer sur le contenu JSON en tant que valeurs de propriété de champ. Faisons les choses correctement et continuons. Quelqu'un peut-il pointer la documentation ou l'exemple qui montre comment cela est fait? Ou donnez une raison valable pour laquelle cela ne peut / ne doit pas être fait.

MISE À JOUR: Une chose que je peux dire avec 100% de certitude. Vous POUVEZ le faire dans Google's Volley. Il est intégré. Pouvons-nous faire cela dans Retrofit?

user3243335
la source
7
Le message de Jake Wharton est correct! Marquez comme réponse!
edotassi
1
Vous pourriez mieux utiliser jsonObject.
superUser
fonctionne parfaitement avec RequestBodycomme ça -> RequestBody body = RequestBody.create(MediaType.parse("text/plain"), text);pour une réponse détaillée futurestud.io/tutorials/…
Kidus Tekeste

Réponses:

460

L' @Bodyannotation définit un seul corps de demande.

interface Foo {
  @POST("/jayson")
  FooResponse postJson(@Body FooRequest body);
}

Étant donné que Retrofit utilise Gson par défaut, les FooRequestinstances seront sérialisées en JSON comme seul corps de la demande.

public class FooRequest {
  final String foo;
  final String bar;

  FooRequest(String foo, String bar) {
    this.foo = foo;
    this.bar = bar;
  }
}

Appeler avec:

FooResponse = foo.postJson(new FooRequest("kit", "kat"));

Donnera le corps suivant:

{"foo":"kit","bar":"kat"}

Les documents Gson ont beaucoup plus sur le fonctionnement de la sérialisation d'objets.

Maintenant, si vous voulez vraiment envoyer JSON "brut" comme corps vous-même (mais veuillez utiliser Gson pour cela!), Vous pouvez toujours utiliser TypedInput:

interface Foo {
  @POST("/jayson")
  FooResponse postRawJson(@Body TypedInput body);
}

TypedInput est défini comme "Données binaires avec un type MIME associé". Il y a deux façons d'envoyer facilement des données brutes avec la déclaration ci-dessus:

  1. Utilisez TypedByteArray pour envoyer des octets bruts et le type MIME JSON:

    String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}";
    TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8"));
    FooResponse response = foo.postRawJson(in);
  2. Sous-classe TypedString pour créer une TypedJsonStringclasse:

    public class TypedJsonString extends TypedString {
      public TypedJsonString(String body) {
        super(body);
      }
    
      @Override public String mimeType() {
        return "application/json";
      }
    }

    Et puis utilisez une instance de cette classe similaire à # 1.

Jake Wharton
la source
5
Très bien, cependant, est-il possible de faire cela sans faire les pojos?
superUser
28
Cela ne fonctionne pas sur la modification 2. Les classes TypedInput et TypedString ont été supprimées.
Ahmed Hegazy
2
@jakewharton Que pouvons-nous faire TypedStringdepuis qu'il a été supprimé?
Jared Burrows
12
Pour Retrofit2, vous pouvez utiliser RequestBodypour créer un corps brut.
bnorm
4
Je reçois cette exceptionjava.lang.IllegalArgumentException: Unable to create @Body converter for class MatchAPIRequestBody (parameter #1)
Shajeel Afzal
156

Au lieu de classes, nous pouvons également utiliser directement HashMap<String, Object>pour envoyer des paramètres de corps, par exemple

interface Foo {
  @POST("/jayson")
  FooResponse postJson(@Body HashMap<String, Object> body);
}
apprenant
la source
2
À ce moment-là, vous pouvez créer une carte de hachage comme HashMap <String, Object>, il peut être possible de créer des tableaux et des objets JSON un peu complexes.
apprenant
2
C'est excellent si vous ne voulez pas être lié à un POJO quelconque.
Tim
2
@Nil vous ne pouvez pas envoyer d'objet json en utilisant retrofit ... vous adhérez avec pojo ou ma réponse ... c'est la nature de retrofit. .
apprenant
5
Je reçois IllegalArgumentException: Unable to create @Body converter for java.util.HashMap<java.lang.String, java.lang.Object>avec Moshi. Je pense que Gson est nécessaire pour que cela fonctionne
osrl
2
Si vous utilisez Kotlin, utilisez une table de hachage de <String, Any>
peresisUser
149

Oui, je sais qu'il est tard, mais quelqu'un en bénéficierait probablement.

Utilisation de Retrofit2:

J'ai rencontré ce problème la nuit dernière lors de la migration de Volley vers Retrofit2 (et comme l'indique OP, cela a été intégré à Volley avec JsonObjectRequest), et bien que la réponse de Jake soit la bonne pour Retrofit1.9 , Retrofit2 n'a pas TypedString.

Mon cas nécessitait l'envoi d'un Map<String,Object>qui pourrait contenir des valeurs nulles, converti en JSONObject (qui ne volera pas avec @FieldMap, pas plus que les caractères spéciaux, certains ne seront convertis), donc en suivant le conseil @bnorms, et comme indiqué par Square :

Un objet peut être spécifié pour être utilisé comme corps de requête HTTP avec l'annotation @Body.

L'objet sera également converti à l'aide d'un convertisseur spécifié sur l'instance Retrofit. Si aucun convertisseur n'est ajouté, seul RequestBody peut être utilisé.

Il s'agit donc d'une option utilisant RequestBodyet ResponseBody:

Dans votre interface, utilisez @BodyavecRequestBody

public interface ServiceApi
{
    @POST("prefix/user/{login}")
    Call<ResponseBody> login(@Path("login") String postfix, @Body RequestBody params);  
}

Dans votre point d'appel, créez un RequestBody, en indiquant qu'il s'agit de MediaType et en utilisant JSONObject pour convertir votre carte au format approprié:

Map<String, Object> jsonParams = new ArrayMap<>();
//put something inside the map, could be null
jsonParams.put("code", some_code);

RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),(new JSONObject(jsonParams)).toString());
//serviceCaller is the interface initialized with retrofit.create...
Call<ResponseBody> response = serviceCaller.login("loginpostfix", body);
      
response.enqueue(new Callback<ResponseBody>()
    {
        @Override
        public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> rawResponse)
        {
            try
            {
             //get your response....
              Log.d(TAG, "RetroFit2.0 :RetroGetLogin: " + rawResponse.body().string());
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable throwable)
        {
        // other stuff...
        }
    });

J'espère que cela aide n'importe qui!


Une élégante version Kotlin de ce qui précède, pour permettre d'abstraire les paramètres de la conversion JSON dans le reste de votre code d'application:

interface ServiceApi {

    fun login(username: String, password: String) =
            jsonLogin(createJsonRequestBody(
                "username" to username, "password" to password))

    @POST("/api/login")
    fun jsonLogin(@Body params: RequestBody): Deferred<LoginResult>

    private fun createJsonRequestBody(vararg params: Pair<String, String>) =
            RequestBody.create(
                okhttp3.MediaType.parse("application/json; charset=utf-8"), 
                JSONObject(mapOf(*params)).toString())

}
TommySM
la source
2
Oui, je vois beaucoup de réponses compliquées partout pour cela. Si vous utilisez Retrofit2 et que vous voulez faire des volley-ball JsonObjectRequest, tout ce que vous devez faire est le suivant. Bonne réponse.
VicVu
2
Retrofit ajoute une clé nommée "nameValuePairs" en haut de tous les objets json. Comment puis-je supprimer ce @TommySM
nr5
1
Je vous remercie! Cela a résolu mon problème. Maintenant, je peux envoyer JSONObject directement sans créer de POJO.
Erfan GLMPR
1
C'est la seule solution qui m'a aidé à post a null valueaccéder à une propriété du requestBody qui autrement était ignorée.
Shubhral
Je sais que je suis en retard mais qu'est-ce qu'il y a jsonParams.put("code", some_code);dans la troisième ligne?
Naveen Niraula
81

Dans Retrofit2 , lorsque vous voulez envoyer vos paramètres en raw, vous devez utiliser des scalaires .

ajoutez d'abord ceci dans votre gradle:

compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.squareup.retrofit2:converter-scalars:2.3.0'

Votre interface

public interface ApiInterface {

    String URL_BASE = "http://10.157.102.22/rest/";

    @Headers("Content-Type: application/json")
    @POST("login")
    Call<User> getUser(@Body String body);

}

Activité

   public class SampleActivity extends AppCompatActivity implements Callback<User> {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sample);

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(ApiInterface.URL_BASE)
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        ApiInterface apiInterface = retrofit.create(ApiInterface.class);


        // prepare call in Retrofit 2.0
        try {
            JSONObject paramObject = new JSONObject();
            paramObject.put("email", "[email protected]");
            paramObject.put("pass", "4384984938943");

            Call<User> userCall = apiInterface.getUser(paramObject.toString());
            userCall.enqueue(this);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void onResponse(Call<User> call, Response<User> response) {
    }

    @Override
    public void onFailure(Call<User> call, Throwable t) {
    }
}
Jonathan Nolasco Barrientos
la source
10
L'astuce ici est l'adaptateur scalaire avant Gson, sinon Gson encapsulera votre JSON sérialisé manuellement dans une chaîne.
TWiStErRob
2
jonathan-nolasco-barrientos vous devez changer .baseUrl (ApiInterface.ENDPOINT) en .baseUrl (ApiInterface.URL_BASE)
Milad Ahmadi
2
Lorsque vous utilisez GsonConverterFactory, le .toString()n'est pas nécessaire. Vous pouvez déclarer Call<User> getUser(@Body JsonObject body);using JsonObjectau lieu de JSONObjectet transmettre paramObjectdirectement. Cela fonctionnera très bien.
Igor de Lorenzi
1
@IgordeLorenzi résout mon problème, car j'utilise Spring Boot pour récupérer le json uniquement JsonObject de gson fonctionne bien
haidarvm
1
@IgordeLorenzi Y a-t-il une différence qui est le meilleur JSONObject ou JsonObject à utiliser avec des scalaires.
Sumit Shukla
44

L'utilisation JsonObjectest la façon dont c'est:

  1. Créez votre interface comme ceci:

    public interface laInterfaz{ 
        @POST("/bleh/blah/org")
        void registerPayer(@Body JsonObject bean, Callback<JsonObject> callback);
    }
  2. Faites le JsonObject selon la structure jsons.

    JsonObject obj = new JsonObject();
    JsonObject payerReg = new JsonObject();
    payerReg.addProperty("crc","aas22");
    payerReg.addProperty("payerDevManufacturer","Samsung");
    obj.add("payerReg",payerReg);
    /*json/*
        {"payerReg":{"crc":"aas22","payerDevManufacturer":"Samsung"}}
    /*json*/
  3. Appelez le service:

    service.registerPayer(obj, callBackRegistraPagador);
    
    Callback<JsonObject> callBackRegistraPagador = new Callback<JsonObject>(){
        public void success(JsonObject object, Response response){
            System.out.println(object.toString());
        }
    
        public void failure(RetrofitError retrofitError){
            System.out.println(retrofitError.toString());
        }
    };

Et c'est son! À mon avis personnel, c'est beaucoup mieux que de faire des pojos et de travailler avec le mess de la classe. C'est beaucoup plus propre.

superutilisateur
la source
1
Et si je ne veux pas envoyer de valeur spécif dans la classe jsonobject. quelle annotation puis-je utiliser ci-dessus pour cela?
Ali Gürelli
1
Comme vous pouvez voir l'exemple ci-dessus ... JsonObject car c'est un objet, n'utilise aucune anotation. Dans votre cas, si vous ne voulez pas envoyer de valeur spécifique, vous pourriez ne pas l'ajouter en tant que propriété ...
superUser
1
Je veux dire que je ne veux pas envoyer de valeur déclarée dans la classe. Btw j'ai résolu le problème. Il y avait une annotation pour ce dont le nom est exposé.
Ali Gürelli
2
C'est le moyen le plus flexible. Vous pouvez construire votre objet json même si vous ne savez pas combien de champs vous aurez ou même si vous ne connaissez pas leur nom +1
Stoycho Andreev
1
im obtenir une erreur Les méthodes de service ne peuvent pas retourner nulles. pour la méthode APIServices.signUpUser
Erum
11

J'aime particulièrement la suggestion de Jake concernant la TypedStringsous - classe ci - dessus . Vous pouvez en effet créer une variété de sous-classes en fonction des types de données POST que vous prévoyez d'augmenter, chacune avec son propre ensemble personnalisé de réglages cohérents.

Vous avez également la possibilité d'ajouter une annotation d'en-tête à vos méthodes JSON POST dans votre API Retrofit…

@Headers( "Content-Type: application/json" )
@POST("/json/foo/bar/")
Response fubar( @Body TypedString sJsonBody ) ;

… Mais l'utilisation d'une sous-classe est plus évidemment auto-documentée.

@POST("/json/foo/bar")
Response fubar( @Body TypedJsonString jsonBody ) ;
zerobandwidth
la source
1
Sauvé la journée avec un exemple clair en utilisant TypedJsonString de la suggestion JW
miroslavign
10

1) Ajouter des dépendances-

 compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'

2) Faire de la classe Api Handler

    public class ApiHandler {


  public static final String BASE_URL = "URL";  

    private static Webservices apiService;

    public static Webservices getApiService() {

        if (apiService == null) {

           Gson gson = new GsonBuilder()
                    .setLenient()
                    .create();
            Retrofit retrofit = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson)).baseUrl(BASE_URL).build();

            apiService = retrofit.create(Webservices.class);
            return apiService;
        } else {
            return apiService;
        }
    }


}

3) Créer des classes de bean à partir du schéma Json 2 pojo

N'oubliez pas
-Langage cible: Java -Type de source: JSON -Style d'annotation: Gson -sélectionnez Inclure les getters et les setters -vous pouvez également sélectionner Autoriser les propriétés supplémentaires

http://www.jsonschema2pojo.org/

4) faire l'interface pour appeler api

    public interface Webservices {

@POST("ApiUrlpath")
    Call<ResponseBean> ApiName(@Body JsonObject jsonBody);

}

si vous avez des paramètres de données de formulaire, ajoutez la ligne ci-dessous

@Headers("Content-Type: application/x-www-form-urlencoded")

Autre moyen pour le paramètre de données de formulaire vérifier ce lien

5) faire JsonObject pour passer au corps comme paramètre

 private JsonObject ApiJsonMap() {

    JsonObject gsonObject = new JsonObject();
    try {
        JSONObject jsonObj_ = new JSONObject();
        jsonObj_.put("key", "value");
        jsonObj_.put("key", "value");
        jsonObj_.put("key", "value");


        JsonParser jsonParser = new JsonParser();
        gsonObject = (JsonObject) jsonParser.parse(jsonObj_.toString());

        //print parameter
        Log.e("MY gson.JSON:  ", "AS PARAMETER  " + gsonObject);

    } catch (JSONException e) {
        e.printStackTrace();
    }

    return gsonObject;
}

6) Appelez Api comme ceci

private void ApiCallMethod() {
    try {
        if (CommonUtils.isConnectingToInternet(MyActivity.this)) {
            final ProgressDialog dialog;
            dialog = new ProgressDialog(MyActivity.this);
            dialog.setMessage("Loading...");
            dialog.setCanceledOnTouchOutside(false);
            dialog.show();

            Call<ResponseBean> registerCall = ApiHandler.getApiService().ApiName(ApiJsonMap());
            registerCall.enqueue(new retrofit2.Callback<ResponseBean>() {
                @Override
                public void onResponse(Call<ResponseBean> registerCall, retrofit2.Response<ResponseBean> response) {

                    try {
                        //print respone
                        Log.e(" Full json gson => ", new Gson().toJson(response));
                        JSONObject jsonObj = new JSONObject(new Gson().toJson(response).toString());
                        Log.e(" responce => ", jsonObj.getJSONObject("body").toString());

                        if (response.isSuccessful()) {

                            dialog.dismiss();
                            int success = response.body().getSuccess();
                            if (success == 1) {



                            } else if (success == 0) {



                            }  
                        } else {
                            dialog.dismiss();


                        }


                    } catch (Exception e) {
                        e.printStackTrace();
                        try {
                            Log.e("Tag", "error=" + e.toString());

                            dialog.dismiss();
                        } catch (Resources.NotFoundException e1) {
                            e1.printStackTrace();
                        }

                    }
                }

                @Override
                public void onFailure(Call<ResponseBean> call, Throwable t) {
                    try {
                        Log.e("Tag", "error" + t.toString());

                        dialog.dismiss();
                    } catch (Resources.NotFoundException e) {
                        e.printStackTrace();
                    }
                }

            });

        } else {
            Log.e("Tag", "error= Alert no internet");


        }
    } catch (Resources.NotFoundException e) {
        e.printStackTrace();
    }
}
Adil
la source
9

J'ai trouvé que lorsque vous utilisez un objet composé comme @Bodyparamètres, il ne pouvait pas bien fonctionner avec le Retrofit GSONConverter(sous l'hypothèse que vous l'utilisez). Vous devez utiliser JsonObjectet non JSONObjectlorsque vous travaillez avec cela, il ajouteNameValueParams sans être détaillé à ce sujet - vous ne pouvez le voir que si vous ajoutez une autre dépendance de l'intercepteur de journalisation et d'autres manigances.

Donc, ce que j'ai trouvé la meilleure approche pour y remédier est d'utiliser RequestBody. Vous transformez votre objet en RequestBodyun simple appel api et le lancez. Dans mon cas, je convertis une carte:

   val map = HashMap<String, Any>()
        map["orderType"] = orderType
        map["optionType"] = optionType
        map["baseAmount"] = baseAmount.toString()
        map["openSpotRate"] = openSpotRate.toString()
        map["premiumAmount"] = premiumAmount.toString()
        map["premiumAmountAbc"] = premiumAmountAbc.toString()
        map["conversionSpotRate"] = (premiumAmountAbc / premiumAmount).toString()
        return RequestBody.create(MediaType.parse("application/json; charset=utf-8"), JSONObject(map).toString())

et voici l'appel:

 @POST("openUsvDeal")
fun openUsvDeal(
        @Body params: RequestBody,
        @Query("timestamp") timeStamp: Long,
        @Query("appid") appid: String = Constants.APP_ID,
): Call<JsonObject>
peresisUser
la source
2
Eh bien, cela m'a aidé après avoir googlé pendant la nuit.
W4R10CK
8

Ajouter ScalarsConverterFactory pour moderniser:

en gradle:

implementation'com.squareup.retrofit2:converter-scalars:2.5.0'

votre rénovation:

retrofit = new Retrofit.Builder()
            .baseUrl(WEB_DOMAIN_MAIN)
            .addConverterFactory(ScalarsConverterFactory.create())
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build();

changez le paramètre @Body de votre interface d'appel en String, n'oubliez pas d'ajouter @Headers("Content-Type: application/json"):

@Headers("Content-Type: application/json")
@POST("/api/getUsers")
Call<List<Users>> getUsers(@Body String rawJsonString);

vous pouvez maintenant publier du json brut.

Ali-star
la source
6

Vous pouvez utiliser hashmap si vous ne souhaitez pas créer de classe pojo pour chaque appel d'API.

HashMap<String,String> hashMap=new HashMap<>();
        hashMap.put("email","[email protected]");
        hashMap.put("password","1234");

Et puis envoyer comme ça

Call<JsonElement> register(@Body HashMap registerApiPayload);
jatin rana
la source
5

utiliser ce qui suit pour envoyer json

final JSONObject jsonBody = new JSONObject();
    try {

        jsonBody.put("key", "value");

    } catch (JSONException e){
        e.printStackTrace();
    }
    RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),(jsonBody).toString());

et le passer à l'url

@Body RequestBody key
Mahesh Pandit
la source
4

Après tant d'efforts, nous avons constaté que la différence de base est que vous devez envoyer le paramètre JsonObjectau lieu de JSONObject.

umair151
la source
Je faisais aussi la même erreur: p
Mehtab Ahmed
4

Sur la base de la première réponse, j'ai une solution pour ne pas avoir à faire de POJO pour chaque demande.

Exemple, je veux publier ce JSON.

{
    "data" : {
        "mobile" : "qwer",
        "password" : "qwer"
    },
    "commom" : {}
}

ensuite, je crée une classe commune comme celle-ci:

import java.util.Map;
import java.util.HashMap;

public class WRequest {

    Map<String, Object> data;
    Map<String, Object> common;

    public WRequest() {
        data = new HashMap<>();
        common = new HashMap<>();
    }
}

Enfin, quand j'ai besoin d'un json

WRequest request = new WRequest();
request.data.put("type", type);
request.data.put("page", page);

La demande annotée @Bodypeut ensuite être transmise à Retrofit.

wjploop
la source
4

Si vous ne voulez pas créer de classes supplémentaires ou utiliser, JSONObjectvous pouvez utiliser a HashMap.

Interface de mise à niveau:

@POST("/rest/registration/register")
fun signUp(@Body params: HashMap<String, String>): Call<ResponseBody>

Appel:

val map = hashMapOf(
    "username" to username,
    "password" to password,
    "firstName" to firstName,
    "surname" to lastName
)

retrofit.create(TheApi::class.java)
     .signUp(map)
     .enqueue(callback)
SoftDesigner
la source
3

Choses nécessaires pour envoyer du json brut dans Retrofit.

1) Assurez-vous d'ajouter l'en-tête suivant et de supprimer tout autre en-tête en double. Depuis, sur la documentation officielle de Retrofit, ils mentionnent spécifiquement-

Notez que les en-têtes ne se remplacent pas. Tous les en-têtes portant le même nom seront inclus dans la demande.

@Headers({"Content-Type: application/json"})

2) a. Si vous utilisez une usine de conversion, vous pouvez passer votre json en tant que chaîne, JSONObject, JsonObject et même POJO. Ont également vérifié, avoir ScalarConverterFactoryn'est pas seulement nécessaire GsonConverterFactoryle travail.

@POST("/urlPath")
@FormUrlEncoded
Call<Response> myApi(@Header("Authorization") String auth, @Header("KEY") String key, 
                     @Body JsonObject/POJO/String requestBody);

2) b. Si vous n'utilisez PAS d'usine de convertisseur, vous DEVEZ utiliser RequestBody de okhttp3 comme la documentation de Retrofit dit-

L'objet sera également converti à l'aide d'un convertisseur spécifié sur l'instance Retrofit. Si aucun convertisseur n'est ajouté, seul RequestBody peut être utilisé.

RequestBody requestBody=RequestBody.create(MediaType.parse("application/json; charset=utf-8"),jsonString);

@POST("/urlPath")
@FormUrlEncoded
Call<Response> myApi(@Header("Authorization") String auth, @Header("KEY") String key, 
                 @Body RequestBody requestBody);

3) Succès !!

Darshan Miskin
la source
2

C'est ce qui me fonctionne pour la version actuelle de retrofit 2.6.2 ,

Tout d'abord, nous devons ajouter un convertisseur scalaire à la liste de nos dépendances Gradle, qui se chargerait de convertir les objets java.lang.String en corps de requête text / plain,

implementation'com.squareup.retrofit2:converter-scalars:2.6.2'

Ensuite, nous devons transmettre une usine de conversion à notre constructeur de rénovation. Il indiquera plus tard à Retrofit comment convertir le paramètre @Body transmis au service.

private val retrofitBuilder: Retrofit.Builder by lazy {
    Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(ScalarsConverterFactory.create())
        .addConverterFactory(GsonConverterFactory.create())
}

Remarque: Dans mon générateur de rénovation, j'ai deux convertisseurs Gsonet Scalarsvous pouvez les utiliser tous les deux, mais pour envoyer le corps Json, nous devons nous concentrer, Scalarsdonc si vous n'avez pas besoin de le Gsonsupprimer

Ensuite, retrofit service avec un paramètre de corps String.

@Headers("Content-Type: application/json")
@POST("users")
fun saveUser(@Body   user: String): Response<MyResponse>

Créez ensuite le corps JSON

val user = JsonObject()
 user.addProperty("id", 001)
 user.addProperty("name", "Name")

Appelez votre service

RetrofitService.myApi.saveUser(user.toString())
Jimale Abdi
la source
2

✅✅✅✅✅✅✅✅✅✅✅✅ Solution de travail ✅✅✅✅✅✅✅✅✅✅✅✅

Lors de la création OkHttpClient , il sera utilisé pour la mise à niveau.

ajoutez un intercepteur comme celui-ci.

 private val httpClient = OkHttpClient.Builder()
        .addInterceptor (other interceptors)
        ........................................

        //This Interceptor is the main logging Interceptor
        .addInterceptor { chain ->
            val request = chain.request()
            val jsonObj = JSONObject(Gson().toJson(request))

            val requestBody = (jsonObj
            ?.getJSONObject("tags")
            ?.getJSONObject("class retrofit2.Invocation")
            ?.getJSONArray("arguments")?.get(0) ?: "").toString()
            val url = jsonObj?.getJSONObject("url")?.getString("url") ?: ""

            Timber.d("gsonrequest request url: $url")
            Timber.d("gsonrequest body :$requestBody")

            chain.proceed(request)
        }

        ..............
        // Add other configurations
        .build()

Maintenant corps URL et demande d'appel à tous vos Retrofit sera connecté en Logcat. Filtrer par"gsonrequest"

erluxman
la source
1

J'ai essayé ceci: lorsque vous créez votre instance Retrofit, ajoutez cette usine de conversion au générateur de modification:

gsonBuilder = new GsonBuilder().serializeNulls()     
your_retrofit_instance = Retrofit.Builder().addConverterFactory( GsonConverterFactory.create( gsonBuilder.create() ) )
Arman Ramezanzadeh
la source
1

Résolu mon problème basé sur la réponse de TommySM (voir précédent). Mais je n'avais pas besoin de me connecter, j'ai utilisé Retrofit2 pour tester l'API https GraphQL comme ceci:

  1. Défini ma classe BaseResponse à l'aide d'annotations json (import jackson.annotation.JsonProperty).

    public class MyRequest {
        @JsonProperty("query")
        private String query;
    
        @JsonProperty("operationName")
        private String operationName;
    
        @JsonProperty("variables")
        private String variables;
    
        public void setQuery(String query) {
            this.query = query;
        }
    
        public void setOperationName(String operationName) {
            this.operationName = operationName;
        }
    
        public void setVariables(String variables) {
            this.variables = variables;
        }
    }
  2. Défini la procédure d'appel dans l'interface:

    @POST("/api/apiname")
    Call<BaseResponse> apicall(@Body RequestBody params);
  3. Appelé apicall dans le corps du test: créez une variable de type MyRequest (par exemple "myLittleRequest").

    Map<String, Object> jsonParams = convertObjectToMap(myLittleRequest);
    RequestBody body = 
         RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),
                        (new JSONObject(jsonParams)).toString());
    response = hereIsYourInterfaceName().apicall(body).execute();
Natalya Shatalova
la source
0

Pour plus de clarté sur les réponses données ici, voici comment vous pouvez utiliser les fonctions d'extension. C'est seulement si vous utilisez Kotlin

Si vous utilisez com.squareup.okhttp3:okhttp:4.0.1les anciennes méthodes de création d'objets de MediaType et RequestBody sont obsolètes et ne peuvent pas être utilisés dans Kotlin .

Si vous souhaitez utiliser les fonctions d'extension pour obtenir un objet MediaType et un objet ResponseBody à partir de vos chaînes, ajoutez tout d'abord les lignes suivantes à la classe dans laquelle vous prévoyez de les utiliser.

import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody

Vous pouvez maintenant obtenir directement un objet de MediaType de cette façon

val mediaType = "application/json; charset=utf-8".toMediaType()

Pour obtenir un objet de RequestBody, convertissez d'abord le JSONObject que vous souhaitez envoyer à une chaîne de cette façon. Vous devez lui passer l'objet mediaType.

val requestBody = myJSONObject.toString().toRequestBody(mediaType)
Devenom
la source
0

Je voulais comparer la vitesse de volée et le retrofit pour envoyer et recevoir des données que j'ai écrites ci-dessous (pour la partie retrofit)

première dépendance:

dependencies {
     implementation 'com.squareup.retrofit2:retrofit:2.4.0'
     implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
}

Puis interface:

 public interface IHttpRequest {

    String BaseUrl="https://example.com/api/";

    @POST("NewContract")
    Call<JsonElement> register(@Body HashMap registerApiPayload);
}

et une fonction pour définir les paramètres de publication des données sur le serveur (dans MainActivity):

private void Retrofit(){

    Retrofit retrofitRequest = new Retrofit.Builder()
            .baseUrl(IHttpRequest.BaseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    // set data to send
    HashMap<String,String> SendData =new HashMap<>();
    SendData.put("token","XYXIUNJHJHJHGJHGJHGRTYTRY");
    SendData.put("contract_type","0");
    SendData.put("StopLess","37000");
    SendData.put("StopProfit","48000");

    final IHttpRequest request=retrofitRequest.create(IHttpRequest.class);

    request.register(SendData).enqueue(new Callback<JsonElement>() {
        @Override
        public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {
            if (response.isSuccessful()){
                Toast.makeText(getApplicationContext(),response.body().toString(),Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onFailure(Call<JsonElement> call, Throwable t) {

        }
    });

}

Et j'ai trouvé Retrofit plus rapide que volley dans mon cas.

Liam
la source