Как смоделировать сложный вызов REST со стороны сервера?

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

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

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

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

Кто-нибудь?

7 голосов | спросил Hon Chong Chang 27 +04002011-10-27T23:11:34+04:00312011bEurope/MoscowThu, 27 Oct 2011 23:11:34 +0400 2011, 23:11:34

2 ответа


0

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

ответил Sotomajor 4 72012vEurope/Moscow11bEurope/MoscowSun, 04 Nov 2012 22:16:22 +0400 2012, 22:16:22
0

Я фактически закончил тем, что создал свой собственный движок 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.

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

ответил Hon Chong Chang 28 +04002011-10-28T17:10:15+04:00312011bEurope/MoscowFri, 28 Oct 2011 17:10:15 +0400 2011, 17:10:15

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132