dreamhead / moco

Easy Setup Stub Server
MIT License
4.37k stars 1.08k forks source link

What should I do if I want to make the response json contain some values in the request json? #237

Open yqleng1987 opened 6 years ago

yqleng1987 commented 6 years ago

In my scenario, the request is json and the response is json too. For example:

[
  {
    "request" :
    {
      "method" : "post",
      "uri" : "/test",
      "json" :
      {
        "t1" : "111",
        "t2" : "222"
      }
    },
    "response" :
    {
      "json" :
      {
        "t1" : "111_test",
        "t2" : "222_test"
      }
    }
  }
]

Now I want to make the response json customized based on the json request. I know there is a feature "template" but how can we combine "template" with the response json?

yqleng1987 commented 6 years ago

Actually the post request can pass different values for "t1" and "t2" and then the response json should be customized based on the request json.

dreamhead commented 6 years ago

Currently, there is no such feature.

What do you think this feature should look like?

yqleng1987 commented 6 years ago

In mock server, we can define any values in the response json . However, sometimes we can define any values of some fields in the response json and sometimes we need to define the value of some fields based on some values in the request json.

For example: The request json looks like:

      {
        "name" : "Jerry",
        "phone" : "345201234"
      }

The response json should be like: (we need to keep the fields "name" and "phone" are the same as request and other fields like "manager" could have any faked values)

      {
        "name" : "Jerry",
        "phone" : "345201234",
         "manager" : "Tom",
         "Salary" : "10000"
      }
yqleng1987 commented 6 years ago

I tried template feature but seems it can't meet this requirement

dreamhead commented 6 years ago

There is NO such feature for now.

One potential solution could be like the following:

{
"name" : "${req.json.name}",
"phone" : "${req.json.phone}",
"manager" : "Tom",
"Salary" : "10000"
}

What do you think if it is good for you?

yqleng1987 commented 6 years ago

Sounds great. That's exactly what I need: response json can get the values in request json.

15652915156 commented 5 years ago

it can't work, the respons of name is ${req.json.name} ,not Jerry. You get the Jerry? What's your response?

dreamhead commented 5 years ago

@15652915156 This is the feature in development. You can try to build your own Moco to try it.

15652915156 commented 5 years ago

@dreamhead Besides,req.json in template seems doesn't work. I got a "freemarker" error form under json. Thanks for your answer!

{
    "request": {
        "uri": "/template"
    },
    "response": {
        "text": {
            "template": "${req.json.foo}"
        }
    }
}

the error:

04 十二月 2018 21:57:58 [nioEventLoopGroup-5-3] ERROR Exception thrown
com.github.dreamhead.moco.MocoException: freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
==> req.json  [in template "template" at line 1, column 3]

----
Tip: It's the step after the last dot that caused this error, not those before it.
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----

----
FTL stack trace ("~" means nesting-related):
    - Failed at: ${req.json.foo}  [in template "template" at line 1, column 1]
----
    at com.github.dreamhead.moco.resource.reader.TemplateResourceReader.readFor(TemplateResourceReader.java:72)
    at com.github.dreamhead.moco.resource.Resource.readFor(Resource.java:34)
    at com.github.dreamhead.moco.handler.ContentHandler.responseContent(ContentHandler.java:27)
    at com.github.dreamhead.moco.handler.AbstractContentResponseHandler.requireResponseContent(AbstractContentResponseHandler.java:46)
    at com.github.dreamhead.moco.handler.AbstractContentResponseHandler.doWriteToResponse(AbstractContentResponseHandler.java:36)
    at com.github.dreamhead.moco.handler.AbstractContentResponseHandler.writeToResponse(AbstractContentResponseHandler.java:27)
    at com.github.dreamhead.moco.setting.BaseSetting.writeToResponse(BaseSetting.java:35)
    at com.github.dreamhead.moco.internal.MocoHandler.doGetHttpResponse(MocoHandler.java:77)
    at com.github.dreamhead.moco.internal.MocoHandler.getHttpResponse(MocoHandler.java:61)
    at com.github.dreamhead.moco.internal.MocoHandler.handleRequest(MocoHandler.java:51)
    at com.github.dreamhead.moco.internal.MocoHandler.channelRead0(MocoHandler.java:40)
    at com.github.dreamhead.moco.internal.MocoHandler.channelRead0(MocoHandler.java:25)
    at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438)
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:284)
    at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1359)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:935)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:141)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459)
    at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:748)
Caused by: freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
==> req.json  [in template "template" at line 1, column 3]

----
Tip: It's the step after the last dot that caused this error, not those before it.
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----

----
FTL stack trace ("~" means nesting-related):
    - Failed at: ${req.json.foo}  [in template "template" at line 1, column 1]
----
    at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:134)
    at freemarker.core.UnexpectedTypeException.newDesciptionBuilder(UnexpectedTypeException.java:85)
    at freemarker.core.UnexpectedTypeException.<init>(UnexpectedTypeException.java:48)
    at freemarker.core.NonHashException.<init>(NonHashException.java:49)
    at freemarker.core.Dot._eval(Dot.java:48)
    at freemarker.core.Expression.eval(Expression.java:83)
    at freemarker.core.DollarVariable.calculateInterpolatedStringOrMarkup(DollarVariable.java:96)
    at freemarker.core.DollarVariable.accept(DollarVariable.java:59)
    at freemarker.core.Environment.visit(Environment.java:325)
    at freemarker.core.Environment.process(Environment.java:304)
    at freemarker.template.Template.process(Template.java:382)
    at com.github.dreamhead.moco.resource.reader.TemplateResourceReader.readFor(TemplateResourceReader.java:64)
    ... 38 common frames omitted
04 十二月 2018 21:57:58 [nioEventLoopGroup-5-3] INFO  Response return:

HTTP/1.1 400
dreamhead commented 5 years ago

@15652915156 Please provide your Moco version and your request.

15652915156 commented 5 years ago

@dreamhead the version is :moco-runner-0.12.0-standalone.jar the request body is:{"foo":"test"} image

dreamhead commented 5 years ago

req.json has NOT been released. You can build your Moco to try it.

yanguoqiang commented 4 years ago

There is NO such feature for now.

One potential solution could be like the following:

{
"name" : "${req.json.name}",
"phone" : "${req.json.phone}",
"manager" : "Tom",
"Salary" : "10000"
}

What do you think if it is good for you?

There is NO such feature for now.

One potential solution could be like the following:

{
"name" : "${req.json.name}",
"phone" : "${req.json.phone}",
"manager" : "Tom",
"Salary" : "10000"
}

What do you think if it is good for you?

${req.json.name} this way is ok, but response is not json format. "response": { "text": { "template":"{"name" : "${req.json.name}", "phone" : "${req.json.phone}", "manager" : "Tom", "Salary" : "10000"}" } }