1

I was trying to develop a simple POST API call in Android so I made one thinking that the request content-type was a json. Turns out it is expecting a multipart/form-data format and I'm struggling changing my function. I'd like to know if there is any library to manage this. If not, I'd like to know how to pass my arguments in a multipart format.

@Override
    public boolean post(String poiId, String description, ArrayList<String> tags, Resource resource) {

        RequestQueue queue = mRequestQueue;
        poiId = "1";
        description = "Test post";
        final HashMap<String, Object> params = new HashMap<>();
        params.put("poiID", poiId);
        params.put("description", description);
        System.out.println("POI ID " + description);
        params.put("tags", tags);
        params.put("resource", resource);


        RequestFuture<JSONObject> future = RequestFuture.newFuture();
        JsonObjectRequest request = new JsonObjectRequest(
                Request.Method.POST,
                API_POST_URL,
                new JSONObject(params),
                future, future) {
            @Override
            public HashMap<String, String> getHeaders() {
                System.out.println(PostRepositoryImpl.this.getHeaders());
                return PostRepositoryImpl.this.getHeaders();
            }
        };

        queue.add(request);

        try {
            future.get(TIMEOUT, TIMEOUT_TIME_UNIT); // this will block
        }catch (InterruptedException | ExecutionException | TimeoutException e){
            e.printStackTrace();
            return false;
        }
        return true;
    }

I hardcoded some of the values because I wanted to test with poiID and description

So I want to send these kind of values in my multipart/form-date: - poiID : String - description : String - resource : image - tags

Is there any way to do this similar to the way I made my json request?

Kind regards

EDIT:

@Override
public boolean post(String poiId, String description, ArrayList<String> tags, Resource resource) {
    RequestQueue queue = mRequestQueue;
    StringRequest postRequest = new StringRequest(Request.Method.POST, API_POST_URL,
            new Response.Listener<String>()
            {
                @Override
                public void onResponse(String response) {
                    // response
                    Log.d("Response", response);
                }
            },
            new Response.ErrorListener()
            {
                @Override
                public void onErrorResponse(VolleyError error) {
                    // error
                    Log.d("Error.Response", "400");
                }
            }
    ) {
        @Override
        protected HashMap<String, String> getParams()
        {
            HashMap<String, String>  params = new HashMap<String, String>();
            params.put("poiID", "Alif");
            params.put("description", "http://itsalif.info");

            return params;
        }
    };
    queue.add(postRequest);

    return true;
}

How do I add the headers?

vftw
  • 1,547
  • 3
  • 22
  • 51

2 Answers2

0

If it isn't JSON, simply use a StringRequest.

Not sure how to use Future with Volley, so change that accordingly

Then, params are added in an overridden method

    Request request = new StringRequest(
            Request.Method.POST,
            API_POST_URL, 
            future, future) {
        @Override
        public HashMap<String, String> getHeaders() {
            HashMap<String, String> headers = PostRepositoryImpl.this.getHeaders();
            System.out.println(headers);
            return headers;
        }
        @Override
        public HashMap<String, String> getParams() {
            // TODO: Put your params here
        }
    };

And for Multipart, see Working POST Multipart Request with Volley and without HttpEntity

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
0

Using Retrofit 2, you could do this:

//Lets Suppose this you have this postman or you want to make some request like this postman request

//ServiceCreator (In my case i am using oauth2 so have AccessToken). This is a working and production sample, so you have to make your own changes, but i attach to example all components.

public class APIRestClient {

    public static String API_BASE_URL = "http://186.151.238.14/";

    private static OkHttpClient.Builder httpClient;

    private static Retrofit.Builder builder;
    public static Retrofit retrofit;
    private static Activity mActivity;
    private static AccessToken mToken;

    /**
     * setupBase URL
     * @param _baseActivity
     */
    public static void setupBaseUrl(Context _baseActivity){
        String tmpBase = SharedPreferenceUtilities.getDomain(_baseActivity);
        if (tmpBase != null && tmpBase.length() > 0){
            if (tmpBase != API_BASE_URL) {
                APIRestClient.API_BASE_URL = tmpBase;
            }
        }
    }

    /**
     * auth2 Authorization Bearer...token create Service instance
     * @param _serviceClass
     * @param _baseActivity
     * @param <S>
     * @return
     */
    public static <S> S createService(Class<S> _serviceClass, final Activity _baseActivity) {
        AccessToken accessToken = TaskManagementApplication.getInstance().getAccessToken();
        if (_baseActivity != null) {
            setupBaseUrl(_baseActivity);
        }

        httpClient = new OkHttpClient.Builder();
        httpClient.connectTimeout(30000, TimeUnit.SECONDS)
                .readTimeout(30000,TimeUnit.SECONDS);

        if (BuildConfig.DEBUG) {
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
            httpClient.addInterceptor(logging);
            httpClient.addNetworkInterceptor(new StethoInterceptor());
        }

        builder = new Retrofit.Builder()
                .baseUrl(API_BASE_URL)
                .addConverterFactory(GsonConverterFactory.create());

        if (accessToken == null){
            accessToken = new AccessToken();
            accessToken.setAccessToken("");
            accessToken.setTokenType("Bearer");
            accessToken.setScope("");
            accessToken.setRefreshToken("");
            accessToken.setClientID("");
            accessToken.setClientSecret("");
            accessToken.setExpiry(0);
        }

        if(accessToken != null) {
            mActivity = _baseActivity;
            mToken = accessToken;
            final AccessToken token = accessToken;
            httpClient.addInterceptor(new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request original = chain.request();

                    Request.Builder requestBuilder = original.newBuilder()
                            .header("Accept", "application/json")
                            .header("Content-type", "application/json")
                            .header("Authorization",
                                    token.getTokenType() + " " + token.getAccessToken())
                            .method(original.method(), original.body());

                    Request request = requestBuilder.build();
                    return chain.proceed(request);
                }
            });

            httpClient.authenticator(new Authenticator() {
                @Override
                public Request authenticate(Route route, Response response) throws IOException {
                    if(responseCount(response) >= 2) {
                        // If both the original call and the call with refreshed token failed,
                        // it will probably keep failing, so don't try again.
                        LoginUtilities.initLogin(_baseActivity,LoginActivity.LOGININTENTRESULT,null);
                        return null;
                    }

                    // We need a new client, since we don't want to make another call using our client with access token
                    OAuthInterface tokenClient = createAuthService(OAuthInterface.class,mActivity);
                    Call<AccessToken> call = tokenClient.getRefreshAccessToken(
                            Grant_type.REFRESH_TOKEN.toString(),
                            token.getRefreshToken(),
                            StringUtilities.API_OAUTH_CLIENTID(_baseActivity),
                            StringUtilities.API_OAUTH_SECRET(_baseActivity),
                            "");
                    try {
                        retrofit2.Response<AccessToken> tokenResponse = call.execute();
                        if(tokenResponse.code() == 200) {
                            AccessToken newToken = tokenResponse.body();
                            mToken = newToken;
                            SharedPreferenceUtilities.setAccessToken(mActivity,mToken);
                            TaskManagementApplication.getInstance().setupToken(mToken);

                            return response.request().newBuilder()
                                    .header("Authorization", newToken.getTokenType() + " " + newToken.getAccessToken())
                                    .build();
                        } else {
                            LoginUtilities.initLogin(_baseActivity,LoginActivity.LOGININTENTRESULT,null);
                            return null;
                        }
                    } catch(IOException e) {
                        LoginUtilities.initLogin(_baseActivity,LoginActivity.LOGININTENTRESULT,null);
                        return null;
                    }
                }
            });
        }

        OkHttpClient client = httpClient.build();
        Retrofit retrofit = builder.client(client).build();
        return retrofit.create(_serviceClass);
    }

    /**
     * not auth create Service instance
     * @param _serviceClass
     * @param _context
     * @param <S>
     * @return
     */

    private static int responseCount(Response response) {
        int result = 1;
        while ((response = response.priorResponse()) != null) {
            result++;
        }
        return result;
    }
}

//ApiInterface

    public interface StudentInterface 
    {
        public static final String ENVIARTAREAAPI = "api/estudiante/entregatarea";
        @Multipart
        @POST(ENVIARTAREAAPI)
        Call<TareaCalificacion> entregatarea(@Part("Descripcion") RequestBody Descripcion,
                                            @Part("IdTarea") RequestBody IdTarea,
                                            @Part("IdEstudiante") RequestBody IdEstudiante);

    }

//ApiCall (in your activity, fragment or wetheaver) this should be used when you execute your api call

RequestBody descripcionRequestBody = RequestBody.create(
                okhttp3.MediaType.parse("text/plain; charset=utf-8"),
                mensageEntregaTmp);

RequestBody idTareaRequestBody = RequestBody.create(
                okhttp3.MediaType.parse("text/plain; charset=utf-8"),
                String.valueOf(mTarea.getIdTarea()));

RequestBody idEstudianteRequestBody = RequestBody.create(
                okhttp3.MediaType.parse("text/plain; charset=utf-8"),
                String.valueOf(currUser.getPerfil().getSisId()));

StudentInterface studentInterface = APIRestClient.createService(StudentInterface.class,DetalleTareaActivity.this);
Call<TareaCalificacion> call = studentInterface.entregatarea(
        descripcionRequestBody,
        idTareaRequestBody,
        idEstudianteRequestBody);

call.enqueue(new Callback<TareaCalificacion>() {
    @Override
    public void onResponse(Call<TareaCalificacion> call, Response<TareaCalificacion> response) {
        int statusCode = response.code();
        if(statusCode == 200) {
            Toast.makeText(getApplicationContext, "Success Request", Toast.LENGTH_SHORT).show();
        } else {
            //todo some kind of error
        }
    }
    @Override
    public void onFailure(Call<TareaCalificacion> call, Throwable t) {
        //todo some kind of error
    }
});

I have used this to upload photos, so i have to use this sample to do that, thats the reason i did not use Content Type application/json.

Hope that helps how to do.

Some class (pojo) like TareaCalificacion (that is what i expect from the response are just class, that i use with GSON), so TareaCalificacion.java is like:

public class TareaCalificacion {
    @SerializedName("sisId")
    @Expose
    private long sisId;

    @SerializedName("sisDescripcion")
    @Expose
    private String sisDescripcion;

    @SerializedName("sisEstado")
    @Expose
    private String sisEstado;

    @SerializedName("sis")
    @Expose
    private int sis;

    @SerializedName("sisUsuario")
    @Expose
    private String sisUsuario;

    @SerializedName("CalificacionObtenida")
    @Expose
    private double CalificacionObtenida;

    @SerializedName("IdEstudiante")
    @Expose
    private long IdEstudiante;

    @SerializedName("IdTarea")
    @Expose
    private long IdTarea;

    @SerializedName("Adjunto")
    @Expose
    private int Adjunto;

    @SerializedName("ObservacionCalificacion")
    @Expose
    private String ObservacionCalificacion;

    @SerializedName("IdCatedratico")
    @Expose
    private long IdCatedratico;

    public TareaCalificacion() {
    }
}

Attach some links that could help you if you have doubts:

Retrofit Documentation

Another example using this

Lets me know if that works or if is not clear how to do Regards.

Max Pinto
  • 1,463
  • 3
  • 16
  • 29