Как макетировать сложный вызов REST со стороны сервера? - PullRequest
7 голосов
/ 27 октября 2011

При работе с javascript, который широко использует службы REST - в том числе с использованием таких терминов, как GET, PUT, POST, DELETES и т. Д .;Мне было трудно издеваться над серверной стороной, чтобы разработка внешнего интерфейса могла продолжаться независимо (от серверной части).

Также полезно иногда собирать многошаговые данные, чтобы мы могли помочь воспроизвести всю цепочку REST даже (или ошибки, связанные с внешним интерфейсом, которые вызываются из этих цепочек)

Какие инструменты я могу использовать, чтобы высмеивать REST-вызовы, особенно с отслеживанием состояния?(т.е. если я делаю PUT на каком-то ресурсе, я ожидаю, что следующий GET на нем как-то изменится)

Я попробовал SOAPUI 4.0.1, и это REST-насмешка разочаровывает.Кроме того, моя потребность заключается не только в мошенничестве с одним состоянием (что любой может сделать со статическим файлом .json).Мне нужно сделать переход типа состояния макетов;лучше всего работать с заголовками Content-Range.

Кто-нибудь?

Ответы [ 2 ]

3 голосов
/ 04 ноября 2012

Вот еще один доморощенный инструмент для отдыха: https://github.com/mkotsur/restito.

2 голосов
/ 28 октября 2011

Я фактически закончил тем, что создал свой собственный движок Java REST Mock Engine, который в принципе может высмеивать любой ответ. Пока вы можете вручную или вырезать текстовый файл, имитирующий весь http-ответ, вы можете использовать мое решение для насмешки над сервисом.

Вот сервлет:

package com.mockrest.debug;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Servlet implementation class MockGridData
 */
public class MockRest extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public MockRest() {
        super();
        // TODO Auto-generated constructor stub
    }

    @Override
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException {
        sub:{
            HttpServletRequest request = (HttpServletRequest)req;
            HttpServletResponse response = (HttpServletResponse)res;
            String setdata = request.getParameter("__setdata");
            if (setdata!=null && setdata.length()>0){
                System.err.println("Setting Data...");
                HttpSession sess = request.getSession(true);
                String data = "/"+request.getParameter("__setdata");
                sess.setAttribute("data", data);
                try{
                    InputStream is = getServletContext().getResourceAsStream(data);
                    if (is!=null){
                        is.close();
                        response.getWriter().write("Successfully pointed next REST call to:"+data);
                    }
                    else{
                        response.sendError(500, "Cannot find resource:"+data);
                    }
                }
                catch (IOException ioe){
                    response.sendError(500, Arrays.deepToString(ioe.getStackTrace()));
                }

            }
            else{
                System.err.println("Fetching Data...");
                HttpSession sess = request.getSession(false);
                if (sess==null || sess.getAttribute("data")==null){
                    response.sendError(500,"Session invalid or no Previous Data Set!");
                }
                String rsrc = (String)sess.getAttribute("data");
                System.err.println("Resource Being used:"+rsrc);
                InputStream is = getServletContext().getResourceAsStream(rsrc);
                if (is!=null){
                    String statusline = readLine(is);
                    Pattern statusPat = Pattern.compile("^HTTP/1.1 ([0-9]+) (.*)$");
                    Matcher m = statusPat.matcher(statusline);
                    if (m!=null && m.matches()){
                        int status = Integer.valueOf(m.group(1));
                        response.setStatus(status, m.group(2));
                    }
                    else{
                        throw new ServletException("Bad input file: status line parsing failed, got this as status line:"+statusline);
                    }
                    String line;
                    Pattern httpHeaderPat = Pattern.compile("^([^:]+): (.*)$");
                    while ((line=readLine(is))!=null){
                        if (line.length()==0){
                            // end of headers
                            break;
                        }
                        Matcher m2 = httpHeaderPat.matcher(line);
                        if (m2!=null && m2.matches()){
                            response.setHeader(m2.group(1), m2.group(2));
                        }
                    }
                    OutputStream os = response.getOutputStream();
                    byte[] buf = new byte[1024];
                    int size;
                    while ((size=is.read(buf))>0){
                        os.write(buf, 0, size);
                    }
                    os.flush();
                }
            }
        }
    }

    private String readLine(InputStream is) throws IOException {
        StringBuffer sb = new StringBuffer();
        char c;
        while ((c=(char)is.read())!='\n'){
            sb.append(c);
        }
        if (sb.charAt(sb.length()-1) == '\r'){
            sb.deleteCharAt(sb.length()-1);
        }
        return sb.toString();
    }

}

Чтобы настроить его, поместите предварительно созданные файлы ответов в папку WebContent. Я обычно заканчиваю эти файлы расширениями .http.

Пример файла init.http приведен ниже. Представьте, что мы поместили этот файл в папку с именем data внутри WebContent:

HTTP/1.1 200 OK
Date: Wed, 26 Oct 2011 18:31:45 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 4.0.30319
Content-Range: items 0-1/2
Content-Length: 385
Cache-Control: private
Content-Type: application/json

[
  {
    "id": "249F0",
    "field1": " Global",
    "displaystartdate": "2007-10-20",
    "displayenddate": "2012-10-20",
    "status": "Major Delay",
    "children": true
  },
  {
    "id": "962581",
    "field2": "Europe",
    "displaystartdate": "2007-10-20",
    "displayenddate": "2012-10-20",
    "status": "Major Delay",
    "children": true
  }
]

Заголовки должны отделяться от тела пустой строкой (без пробелов, нада). Люди, знакомые с http, заметят, что это чистый http ответ. Это специально.

Вы можете использовать этот инструмент для имитации любого из заголовков http, которые вы хотите получить в ответе; даже заходя так далеко, чтобы отвечать другим заголовком сервера (в моем примере я смоделировал ответ, притворяясь IIS 6.0); или другой код состояния HTTP и т. д.

чтобы вызвать его из браузера / javascript; сначала заправьте его:

http://yourserver/yourweb/MockGridData?__setdata=data/init.http

Затем в вашем вызове javascript или REST AJAX, если он переходит на

http://yourserver/yourweb/MockGridData

с любым методом или параметром; он получит http-ответ, который вы ранее создали; даже вплоть до Content-Range; Заголовки кэша; и т. д. Если вам понадобится последующий вызов AJAX для возврата чего-либо еще, просто позвоните с помощью __setdata еще раз. Я предлагаю вам настроить несколько кнопок для явного перехода состояния в вашем веб-приложении.

При условии, что все настроено, для смоделированной цепочки REST разработчик может сделать:

  1. вызова

    http://yourserver/yourweb/MockGridData?__setdata=data/init.http
    
  2. запустить модуль javascript, который приведет к вызову (скажем, с помощью GET)

    http://yourserver/yourweb/MockGridData
    
  3. нажмите кнопку, которая затем делает:

    http://yourserver/yourweb/MockGridData?__setdata=data/step1.http
    
  4. запустить еще один шаг javascript, который приведет к вызову (скажем, с помощью PUT)

    http://yourserver/yourweb/MockGridData
    
  5. нажмите другую кнопку, которая затем делает:

    http://yourserver/yourweb/MockGridData?__setdata=data/step2.http
    
  6. запустить еще один шаг javascript, который приведет к вызову (скажем, с помощью GET)

    http://yourserver/yourweb/MockGridData
    

    но на этот раз ожидаем результата, отличного от # 4.

Это должно работать даже с двоичными и сжатыми ответами, но я этого не проверял.

...