Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REQ] Mock Server #3545

Closed
ybelenko opened this issue Aug 2, 2019 · 6 comments · Fixed by #4978
Closed

[REQ] Mock Server #3545

ybelenko opened this issue Aug 2, 2019 · 6 comments · Fixed by #4978

Comments

@ybelenko
Copy link
Contributor

ybelenko commented Aug 2, 2019

Is your feature request related to a problem? Please describe.

Is there any server generator with mocking feature already? We briefly discussed it in #969. I'm really interested to make first one with PHP Slim framework. It's complicated topic, so we need to discuss how mock server should work.

Describe the solution you'd like

Imho, the biggest problem is to distinguish mock server from real one. Client should be fully aware to which server he's calling. It can cause problems in both ways. When you want to call mock server and accidentally call real one you can change/delete real data. And when you call mock server instead of real one by mistake, these changes doesn't really happens even if response is right.

What options do we have, I have two in my mind.

1. Detached hostname for mock server

If main hostname is my-api.tech then mock server hostname would be mock.my-api.tech as subdomain.

Pros

  • Pretty visual and straightforward.
  • Easy to call endpoints, you can even change url manually in Chrome if you need.

Cons

  • Need dedicated server and full control over hosting and subdomains.
  • SSL certificate for subdomains can cost extra.
  • You still can call wrong url by accident. It's easy to misplace hostnames in your client sdk installation.
  • You can't say from pure response whether it's mock response or not.

2. Specific HTTP Headers

Respond with mock data only when specific HTTP headers provided. Then client should send header X-MOCK-SERVER: ping and response will contain header X-MOCK-SERVER: pong.

Pros

  • No need of dedicated server and full control over subdomains.
  • Pretty hard to call mock server accidentally, almost impossible.
  • With HTTP Headers we can add more mock options. Like call specific response(4xx - error response, 404 - not found etc.)
  • You can say that response contains fake data when you see headers related to mock server.
  • When response contains X-MOCK-SERVER: pong we know that server understood request correct.

Cons

  • Harder to implement from client side.
  • Can't call mock server with Chrome address bar.
  • Need to check HTTP headers to understand that response is fake.

Additional context

It may be future standard of mock server or "Best Practices with Public API" topic, I think we need full attention before proceed. I would prefer HTTP Headers implementation and if community finds it convenient too, then we need to declare these HTTP headers and server behaviour.

@jimschubert
Copy link
Member

I think the generation of this per language and per framework is beyond the scope of the project.

I also think that generating a production server which can auto-switch to a mock server (which is how I've read one of the suggestions) isn't something that anyone critical of security on a production system would want.

That said, I think it would be cool to have a generator called mock which is intended to be throwaway code for evaluation purposes.

I have a project that I use, which would probably only require creating some loops and logic around models in order to generate a full mock service. You can check it out here and let me know what you think: https://github.com/jimschubert/simple-petstore?files=1

@ybelenko
Copy link
Contributor Author

ybelenko commented Aug 3, 2019

@jimschubert Thanks for your feedback, let me explain why mock feature is crucial for automatic testing.

I've spend some time with Swagger API and Openapi. Im my case every server development ended up with two types of test suites. I call them light and heavy tests. Heavy unit tests checks database inputs before and after endpoint call(these tests become even more difficult now, because PHP DDUnit package has been abandoned). Light tests checks response http status code and response body.

So, usually my light unit test looks like:

/**
 * Tests getUsers method of UsersApi
 */
public function testGetUsersMethod()
{
    // endpoint call skipped as not relevant
    // ...
    // important part now
    $this->assertSame(200, $response->getStatusCode());
    $this->assertArraySubset([
        [
            'id' => 1,
            'username' => 'johndoe',
            'email' => 'johndoe@gmail.com',
        ],
    ], $response->getBody());
}

where

[
    [
        'id' => 1,
        'username' => 'johndoe',
        'email' => 'johndoe@gmail.com',
    ],
]

is response example or mock response.

If I don't want to write these tests over and over again I need to be able to generate mock responses. If you think my unit tests are useless or you think there is another way to test endpoints, I'm all ears.

It's obvious that with current Openapi spec we have all information to generate response examples close to above. It might not be easy, but it looks possible to me. Maybe it will be a model class with mock method which output equals to something like that, I'm not sure yet.

@richardwhiuk
Copy link
Contributor

We've been vaguely looking at adding auto-generation of mocks to the Rust Server code generator - likely as a feature flag on the generated library.

@wing328
Copy link
Member

wing328 commented Aug 13, 2019

I think feature flag is a good starting point.

HTTP header in server response to indicate the response is from a mock server is also a good idea.

@ybelenko
Copy link
Contributor Author

ybelenko commented Aug 13, 2019

About implementation itself, I see it as optional middleware. Slim framework supports PSR-15 middlewares. Something like that:

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\Psr7\Response;

class MockMiddleware implements MiddlewareInterface
{
    public function process(
        ServerRequestInterface $request, 
        RequestHandlerInterface $handler
    ): ResponseInterface
    {
        if (
            $request->hasHeader('x-mock-server') 
            && (strtolower($request->getHeader('x-mock-server')[0]) === 'ping'
        ) {
            // request asks for a mock response, we can send it immediately
            
            // below will be some kind of mock response generation based on responses in codegen
            // where result is:
            $response = new Response();
            $response->getBody()->write(json_encode([
                'username' => 'fake',
                'email' => 'fake@fake.com',
                'first_name' => 'john',
                'last_name' => 'doe',
            ]));
            // add mock related header and return response to client
            return $reponse
                ->withHeader('x-mock-server', 'pong')
                ->withHeader('Content-Type', 'application/json')
                ->withStatus(200);
        }

        // no mock related headers, just transfer request to next middlewares and routes
        // no side effects at all
        return $handler->handle($request);
    }
}

This middleware also can check ENV for production flag and pass request forward in that scenario.

@wing328
Copy link
Member

wing328 commented Aug 13, 2019

As discussed with some of you, another approach is to convert the OpenAPI spec into the input format expected by https://github.com/typicode/json-server. This is not to say I prefer this approach but just trying to come up with ideas.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants