title: Upload file and text with Method POST on iOS
body: <p>I'm trying to send a JSON to the web service with a file and some text, but the server answers as invalid.
  I have been looking through this for 3 days and can't get what's wrong, so I ask you for help.</p>
  
  <p>This is the web form to talk to the web service:</p>
  
  <pre><code>&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;Nova Dica Form&lt;/title&gt;
    &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;form action="http://serveraddress.com/newtip" method="post" enctype="multipart/form-data"&gt;
      &lt;input type="hidden" name="textoDica" value="Ola teste dica"&gt;
      &lt;input type="hidden" name="idUsuario" value="2"&gt;
      &lt;input type="hidden" name="recomendou" value="true"&gt;
      &lt;input type="hidden" name="idTags" value="2"&gt;
      &lt;input type="hidden" name="idMarcas" value="1"&gt;    
      &lt;input type="hidden" name="idLocais" value=""&gt;
      &lt;input type="hidden" name="idCategorias" value=""&gt;
      &lt;input type="hidden" name="idImpressoes" value=""&gt;
      &lt;input name="foto1" type="file"&gt;
      &lt;input name="foto2" type="file"&gt;
      &lt;input name="foto3" type="file"&gt;
      &lt;br&gt;
      &lt;input type="submit" value="Upload"&gt;
    &lt;/form&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>And this is what the php developer sent me:</p>
  
  <pre><code>POST /newtip
  Host: serveraddress.com
  Content-Type: multipart/form-data
  Representation:
  
  Content-Disposition: form-data; name="textoDica"
  
  texto-dica
  Content-Disposition: form-data; name="foto1"
  Content-Type: image/jpeg, image/png
  Content-Transfer-Encoding: binary
  
  foto1
  Content-Disposition: form-data; name="foto2"
  Content-Type: image/jpeg, image/png
  Content-Transfer-Encoding: binary
  
  foto2
  Content-Disposition: form-data; name="foto3"
  Content-Type: image/jpeg, image/png
  Content-Transfer-Encoding: binary
  
  foto3
  Content-Disposition: form-data; name="recomendou";
  
  recomendou
  Content-Disposition: form-data; name="idUsuario";
  
  id-usuario
  Content-Disposition: form-data; name="idTags";
  
  id-tag
  Content-Disposition: form-data; name="idMarcas";
  
  id-marca
  Content-Disposition: form-data; name="idLocais";
  
  id-local
  Content-Disposition: form-data; name="idCategorias";
  
  id-categoria
  Content-Disposition: form-data; name="idImpressoes";
  
  id-Impressao
  
  Response
  Content-Type: application/json
  Representation:
  { "fotoDica" : "http://s3.amazonaws.com/cooltips/dicas/f23f89as.jpg",
    "horarioDica" : 1372711615696,
    "idDica" : 21,
    "recomendado" : 1,
    "textoDica" : "TesteDica1"
  }
  </code></pre>
  
  <p>So, based on that, I did this in my code (with some content I found here at stackoverflow:</p>
  
  <pre><code>NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://serveraddress.com/newtip"]]];
  [request setHTTPMethod:@"POST"];
  // Header
  NSString *boundary = @"---------------------------14737809831466499882746641449";
  NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
  [request addValue:contentType forHTTPHeaderField: @"Content-Type"];
  // Body
  NSMutableData *body = [NSMutableData data];
  
  // Dica/Tip
  [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"Content-Disposition: form-data; name=\"textoDica\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"Teste de texto blablabla." dataUsingEncoding:NSUTF8StringEncoding]];
  // Usuario
  [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"Content-Disposition: form-data; name=\"idUsuario\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"72" dataUsingEncoding:NSUTF8StringEncoding]];
  // Recomendou
  [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"Content-Disposition: form-data; name=\"recomendou\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"true" dataUsingEncoding:NSUTF8StringEncoding]];
  // Tags
  [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"Content-Disposition: form-data; name=\"idTags\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"aaaaaa;bbbbbb;cccccc" dataUsingEncoding:NSUTF8StringEncoding]];
  // Marca
  [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"Content-Disposition: form-data; name=\"idMarcas\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"3" dataUsingEncoding:NSUTF8StringEncoding]];
  // Local
  [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"Content-Disposition: form-data; name=\"idLocais\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"4" dataUsingEncoding:NSUTF8StringEncoding]];
  // Categorias
  [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"Content-Disposition: form-data; name=\"idCategorias\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"1" dataUsingEncoding:NSUTF8StringEncoding]];
  // Impressões
  [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"Content-Disposition: form-data; name=\"idImpressoes\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"bom;alegre" dataUsingEncoding:NSUTF8StringEncoding]];
  // Fotos / Image Files
  [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"Content-Disposition: form-data; name=\"foto1\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"Content-Type: file/jpeg\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
  [body appendData:[@"Content-Transfer-Encoding: binary\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
  NSData *imageData = UIImageJPEGRepresentation(_fotoArray[0], 0.40);
  [body appendData:[NSData dataWithData:imageData]];
  // Final Boundary
  [body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
  
  // Set the body
  [request setHTTPBody:body];
  
  NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
  NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
  NSLog(@"%@", returnString);
  </code></pre>
  
  <p>I always get this answer from the server:</p>
  
  <pre><code>{"idDica":0,"fotoDica":null,"horarioDica":null,"textoDica":null,"recomendado":0}
  </code></pre>
  
  <p>But the right one should be something like this:</p>
  
  <pre><code>{"idDica":91,"fotoDica":"http://serveraddress.com/tips/91/6nyIZA8MPJ.png","horarioDica":1372960438226,"textoDica":"Hello","recomendado":1}
  </code></pre>
  
  <p>Can anyone have a clue on what am I doing wrong?</p>
  
  <p>Thanks</p>
  
  <p>EDIT: This is the web service code (out of my knowledge):</p>
  
  <pre><code>@POST
  @Consumes(MediaType.MULTIPART_FORM_DATA)
  @Produces(MediaType.APPLICATION_JSON)
  public DicaRest uploadFile(
      @FormDataParam("foto1") InputStream uploadedInputStream1,
      @FormDataParam("foto1") FormDataContentDisposition fileDetail1,
      @FormDataParam("foto2") InputStream uploadedInputStream2,
      @FormDataParam("foto2") FormDataContentDisposition fileDetail2,
      @FormDataParam("foto3") InputStream uploadedInputStream3,
      @FormDataParam("foto3") FormDataContentDisposition fileDetail3,
      @FormDataParam("textoDica") String textoDica,
      @FormDataParam("idUsuario") long idUsuario,
      @FormDataParam("recomendou") boolean recomendou,
      @FormDataParam("idTags") String idTags,
      @FormDataParam("idMarcas") String idMarcas,
      @FormDataParam("idLocais") String idLocais,
      @FormDataParam("idCategorias") String idCategorias,
      @FormDataParam("idImpressoes") String idImpressoes)
  {
      if(idTags == null)
          idTags = "";
      if(idMarcas == null)
          idMarcas = "";
      if(idLocais == null)
          idLocais = "";
      if(idCategorias == null)
          idCategorias = "";
      if(idImpressoes == null)
          idImpressoes = "";
      EntityManager em = EntityFactory.getEntityManager("RestCTPU");
      em.getTransaction().begin();
      DicaRest dicaRest = new DicaRest();
      Upload upload = new Upload();
      List&lt;File&gt; pathfoto = new ArrayList&lt;File&gt;();
      Dica novaDica = new Dica();
      int i = 0;
  
      try {
          novaDica.setTextoDica(textoDica);
          novaDica.setIdUsuario(new Usuario(idUsuario));
          novaDica.setRecomendado(recomendou);
          novaDica.setDataCadastro(new Date());
          novaDica.setEstadoHabilitado(true);
          novaDica = em.merge(novaDica);
  
          //LINUX AMI
          String pathLocal = "/var/lib/tomcat7/webapps/uploadtemp/"+novaDica.getIdDica() + "/";
  
          //WINDOWS
          //String pathLocal = "C:/teste/"+"dicas/"+novaDica.getIdDica() + "/";
          String pathAlvo = "dicas/"+novaDica.getIdDica() + "/";
          (new File(pathLocal)).mkdirs();
          if (fileDetail1.getFileName().length() &gt; 0) {
              pathfoto.add( new File(pathLocal+Utilidades.getRandomPass(10)+fileDetail1.getFileName().substring(fileDetail1.getFileName().lastIndexOf("."))));
              saveToFile(uploadedInputStream1, pathfoto.get(i).getAbsolutePath());
              i++;
          }
          if (fileDetail2.getFileName().length() &gt; 0) {
              pathfoto.add( new File(pathLocal +Utilidades.getRandomPass(10)+fileDetail1.getFileName().substring(fileDetail1.getFileName().lastIndexOf("."))));
              saveToFile(uploadedInputStream2, pathfoto.get(i).getAbsolutePath());
              i++;
          }
          if (fileDetail3.getFileName().length() &gt; 0) {
              pathfoto.add( new File(pathLocal+Utilidades.getRandomPass(10)+fileDetail1.getFileName().substring(fileDetail1.getFileName().lastIndexOf("."))));
              saveToFile(uploadedInputStream3, pathfoto.get(i).getAbsolutePath());
              i++;
          }
  
          List&lt;Tag&gt; tags = new ArrayList&lt;Tag&gt;();
          if(idTags.length() &gt; 0) {
              String[] tgs = idTags.split(";");
              for(String tag : tgs) {
                  Tag nTag = new Tag(Long.valueOf(tag));
                  tags.add(nTag);
              }
          }
          novaDica.setTagList(tags);
          List&lt;Alvo&gt; alvos = new ArrayList&lt;Alvo&gt;();
          if(idMarcas.length() &gt; 0) {
                  String[] marcas = idMarcas.split(";");
                  for(String marca : marcas) {
                      Alvo nAlvo = new Alvo(Long.valueOf(marca));
                      alvos.add(nAlvo);
                  }
          }
          if(idLocais.length() &gt; 0) {
              String[] locais = idLocais.split(";");
              for(String local : locais) {
                  Alvo nAlvo = new Alvo(Long.valueOf(local));
                  alvos.add(nAlvo);
              }
          }
          novaDica.setAlvoList(alvos);
          List&lt;CategoriaImpressao&gt; categoriaImpressaoList = new ArrayList&lt;CategoriaImpressao&gt;();
          if(idCategorias.length() &gt; 0) {
              String[] categorias = idCategorias.split(";");
              for(String categoria : categorias) {
                  CategoriaImpressao nCat = new CategoriaImpressao(Long.valueOf(categoria));
                  categoriaImpressaoList.add(nCat);
              }
          }
          if(idImpressoes.length() &gt; 0) {
              String[] impressoes = idImpressoes.split(";");
              for(String impressao : impressoes) {
                  CategoriaImpressao nImpress = new CategoriaImpressao(Long.valueOf(impressao));
                  categoriaImpressaoList.add(nImpress);
              }
          }
          novaDica.setCategoriaImpressaoList(categoriaImpressaoList);
          //String uploadedFileLocation = fileDetail1.getFileName();
          // save it
          List&lt;Foto&gt; fts = new ArrayList&lt;Foto&gt;();
          for(String foto : upload.doUpload(pathfoto, pathAlvo)) {
              Foto ft = new Foto();
              ft.setUrlFoto(foto);
              ft.setIdDica(novaDica);
              ft.setDataCadastro(new Date());
              ft.setEstadoHabilitado(true);
              fts.add(ft);
          }
          novaDica.setFotoList(fts);
          em.persist(novaDica);
          em.getTransaction().commit();
          try {
              deleteDir(new File(pathLocal));
          } catch (Exception e){}
          dicaRest.setFotoDica(fts.get(0).getUrlFoto());
          dicaRest.setHorarioDica(new Date());
          dicaRest.setIdDica(novaDica.getIdDica());
          dicaRest.setRecomendado(recomendou);
          dicaRest.setTextoDica(textoDica);
      } catch (Exception e) {
          System.out.println(e);
      } finally {
          em.close();
          em.getEntityManagerFactory().close();
      }
  
      return dicaRest; 
  }
  </code></pre>