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

Loading JSONs from external source #278

Open
pun-ky opened this issue Apr 22, 2020 · 17 comments
Open

Loading JSONs from external source #278

pun-ky opened this issue Apr 22, 2020 · 17 comments

Comments

@pun-ky
Copy link

pun-ky commented Apr 22, 2020

any suggestions on how to implement loading JSON files from JCR instead of the filesystem will be appreciated.

I am implementing a tool for Adobe Experience Manager which will be based on Moco which will run on OSGi. Yes it is possible (there is a little problem with Guava which you are using but nvm).
On AEM, all assets are just stored on JCR, so that's the only way to go. In Wiremock, I have seen FileSource interface, which seems that supports abstraction for loading JSONs from any sources. I hope that Moco is having sth like this too.

@dreamhead
Copy link
Owner

You can try proxy API in current version, which can load any URL as response.

Tell me if it works for you.

@pun-ky
Copy link
Author

pun-ky commented Apr 22, 2020

you didn't get me ;)

I'd like to implement sth like that

server.request(by("foo")).response(jsonFileInJcr("/etc/stubs/foo-response.json");

any hints appreciated

@pun-ky
Copy link
Author

pun-ky commented Apr 22, 2020

I don't want to access that using URL / HTTP and any other protocol. My JCR storage is a same OSGi container / Moco is running at same server as JCR - I have programmatic access to read that data from JCR so using HTTP is not an option (overhead).

@dreamhead
Copy link
Owner

So, what you want is an interface to allow you extend to access your content, isn't it?

BTW, is JCR Content repository API for Java?

@pun-ky
Copy link
Author

pun-ky commented Apr 22, 2020

yep, yep :)

that repo looks like this:

image

I am implementing a tool that allows writing stub scripts that are configuring Moco HTTP server. I'd like to be able to easily respond content just read from the repository (not always a same string, but content from file stored in a repository that may change in the meantime)

@pun-ky
Copy link
Author

pun-ky commented Apr 22, 2020

hmm in other words... I am asking for .. maybe there is sth like response(Supplier<String>) ?

@dreamhead
Copy link
Owner

No such interface for now, but it's not hard to support.

I can provide the interfaces like the following:

text(Supplier<Object>);
text(Function<Request, Object>);
json(Supplier<Object>);
json(Function<Request, Object>);

so, you can write your API like this:

server.request(...).response(json(() -> new YourPojo());
server.request(...).response(json((request) -> new YourPojo());

@pun-ky
Copy link
Author

pun-ky commented Apr 23, 2020

It would be nice 🙂

What if I have no Pojo class and want to supply json string read from repo file?

@pun-ky
Copy link
Author

pun-ky commented Apr 23, 2020

how about a supplier for template variables? snippet in Groovy that I would like to support:

stubs.server
        .get(by(uri("/current-date")))
        .response(template('Today date is "${date}"', "date", dynamicVar({ new Date() })))

@pun-ky
Copy link
Author

pun-ky commented Apr 23, 2020

I implemented it as :

public final class DynamicExtractor<T> implements RequestExtractor<T> {

  private final Supplier<T> objectSupplier;

  public DynamicExtractor(final Supplier<T> objectSupplier) {
    this.objectSupplier = objectSupplier;
  }

  @Override
  public Optional<T> extract(final Request request) {
    return of(objectSupplier.get());
  }
}

public final class MocoExtensions {

  public static RequestExtractor<Object> dynamicVar(final Supplier<Object> textSupplier) {
    return new DynamicExtractor<>(checkNotNull(textSupplier, "Template variable supplier should not be null or empty"));
  }
}

and it works.

my doubt is only about Optional.of() vs Optional.ofNullable. In PlainExtractor there is of but I can imagine returning nulls sometimes and maybe ofNullable in both PlainExtractor and DynamicExtractor would be better.

btw why ImmutableMap is in template() method signature, maybe it would be better to make it immutable just after calling method acceptingMap<String, RequestExtractor<?>> to make it more universal / more nicely callable e.g from my Groovy scripts.. ;)

@dreamhead
Copy link
Owner

Cool, really good suggestion!

var for template is also a place which works for you. But template is just for specific scenario, so I can support both template and response.

@dreamhead dreamhead reopened this Apr 23, 2020
@pun-ky
Copy link
Author

pun-ky commented Apr 23, 2020

Any ETA for release with improvements? 🙂

@dreamhead
Copy link
Owner

@pun-ky
The json and var have been committed to the codebase.

You can run ./gradlew build to build your own JAR.

@pun-ky
Copy link
Author

pun-ky commented Apr 26, 2020

Cool. I will test it for sure and let you know if it's okay 🙂

@pun-ky
Copy link
Author

pun-ky commented May 4, 2020

40d2cb8

@dreamhead, potentially, I would like to create mocks not only for JSON files but also for text, XML, INI... almost any type of file (there should be no limitation type-based) and load them from the repository / be also supplied by function.

How would you address that case? I see that you implemented a JSON support only as requested originally in the issue, but to be honest, I was expecting sth more general.

@pun-ky
Copy link
Author

pun-ky commented May 4, 2020

@dreamhead , in other words, I'd like to address sth like below:

    server.response(with(text(() -> jcrRepository.readFileAsString("/some/node/my-response.xml"))), header("Content-Type", "application/xml"));
    server.response(with(text(() -> jcrRepository.readFileAsStream("/some/node/logs/my.log")));
    server.response(with(binary(() -> jcrRepository.readFileAsStream("/some/node/reports/sample-report.pdf"))), header("Content-Type", "application/pdf"));

It would be nice if that function returning stream will output response without redundantly allocating whole PDF (potentially big) in memory... or same case for mocking bigger log file

also, a supplier should be able to return a string in some cases because some external API could not return streams but strings... and it will be just easier to glue Moco with external API in that way (mock could be implemented more quickly)

@pun-ky
Copy link
Author

pun-ky commented May 4, 2020

about added overloaded signatures... there is a problem when using them from Groovy

groovy.lang.GroovyRuntimeException: Ambiguous method overloading for method com.cognifide.aem.stubs.moco.Moco#var.
Cannot resolve which method to invoke for [class Script1$_run_closure1] due to overlapping prototypes between:
	[interface java.util.function.Function]
	[interface java.util.function.Supplier]

instead of simply:

stubs.server
        .get(by(uri("/current-date")))
        .response(template('Today date is "${date}"', "date", var({ new Date() })))

I need to write:

stubs.server
        .get(by(uri("/current-date")))
        .response(template('Today date is "${date}"', "date", var(new java.util.function.Supplier<Object>() {
                @Override
                public Object get () {
                    return new Date()  
                }
            } 
        )))  

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

No branches or pull requests

2 participants