feroult / yawp Goto Github PK
View Code? Open in Web Editor NEWKotlin/Java API framework for Google Appengine
Home Page: http://yawp.io
License: MIT License
Kotlin/Java API framework for Google Appengine
Home Page: http://yawp.io
License: MIT License
Hello,
Apply the attached file and run tests.
diff-yawp.txt
One solution would be to not scan methods that don't have any annotation.
io.yawp.repository.EndpointScanner.scanActions() - L 154, before add
private void scanActions() {
Set<Class<? extends Action>> clazzes = endpointsPackage.getSubTypesOf(Action.class);
for (Class<? extends Action> actionClazz : clazzes) {
Class<?> objectClazz = ReflectionUtils.getGenericParameter(actionClazz);
if (objectClazz == null) {
continue;
}
for (Method method : actionClazz.getDeclaredMethods()) {
if(method.getAnnotations() != null && method.getAnnotations().length > 0) {
addAction(objectClazz, method);
}
}
}
}
Stack:
java.lang.ExceptionInInitializerError
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:195)
at org.junit.runners.BlockJUnit4ClassRunner$1.runReflectiveCall(BlockJUnit4ClassRunner.java:244)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:241)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: java.lang.RuntimeException: Invalid Action: io.yawp.repository.models.parents.Child.xpto
at io.yawp.repository.EndpointScanner.createActionMethod(EndpointScanner.java:194)
at io.yawp.repository.EndpointScanner.addAction(EndpointScanner.java:176)
at io.yawp.repository.EndpointScanner.scanActions(EndpointScanner.java:154)
at io.yawp.repository.EndpointScanner.generateEndpointsMap(EndpointScanner.java:61)
at io.yawp.repository.EndpointScanner.scan(EndpointScanner.java:45)
at io.yawp.commons.utils.EndpointTestCase.<clinit>(EndpointTestCase.java:20)
... 22 more
Caused by: io.yawp.repository.actions.InvalidActionMethodException
at io.yawp.repository.actions.ActionParameters.<init>(ActionParameters.java:42)
at io.yawp.repository.actions.ActionMethod.<init>(ActionMethod.java:24)
at io.yawp.repository.EndpointScanner.createActionMethod(EndpointScanner.java:192)
... 27 more
Add an options in the yawp-maven plugin to scaffold endpoints and actions from a Swagger definition file:
mvn yawp:swagger -Dfile=swagger-api.json
A nice test would be to scaffold this API: http://petstore.swagger.io/v2/swagger.json
java.lang.NullPointerException
at io.yawp.repository.query.condition.SimpleCondition.assertIsList(SimpleCondition.java:113)
at io.yawp.repository.query.condition.SimpleCondition.<init>(SimpleCondition.java:30)
at io.yawp.repository.query.condition.Condition.c(Condition.java:11)
at io.yawp.repository.query.condition.Condition.c(Condition.java:7)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at io.yawp.repository.hooks.RepositoryHooks.invokeHookMethod(RepositoryHooks.java:51)
at io.yawp.repository.hooks.RepositoryHooks.invokeHooks(RepositoryHooks.java:35)
at io.yawp.repository.hooks.RepositoryHooks.beforeQuery(RepositoryHooks.java:22)
at io.yawp.repository.Repository.queryWithHooks(Repository.java:144)
at io.yawp.repository.Feature.yawpWithHooks(Feature.java:18)
Http requests to any endpoint containing "-" (hifen) throws the following exception:
java.lang.RuntimeException: Invalid io.yawp path /time-records for class TimeRecord
at io.yawp.repository.RepositoryFeatures.<init>(RepositoryFeatures.java:29)
at io.yawp.repository.EndpointScanner.scan(EndpointScanner.java:44)
at io.yawp.servlet.EndpointServlet.scanEndpoints(EndpointServlet.java:67)
at io.yawp.servlet.EndpointServlet.init(EndpointServlet.java:42)
at org.mortbay.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:440)
at org.mortbay.jetty.servlet.ServletHolder.getServlet(ServletHolder.java:339)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1221)
at com.google.appengine.api.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1212)
at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:127)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1212)
at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1212)
at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:63)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1212)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1212)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:399)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:766)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:450)
at io.yawp.plugin.devserver.appengine.AppengineWebAppContext.handle(AppengineWebAppContext.java:50)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:928)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:549)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Today it is not possible.
Example: ValidationHook extends Hook
Then: PersonValidationHook extends ValidationHook
For example:
@Endpoint(path = "/store/orders")
public class Order
This will be useful to organize APIs into a tree-like structure.
Use as the response body the user defined text/object (json serialized) without any modifications.
Think about add an option for mime-type.
Check if the right driver is always loaded.
Today it is possible to create your own model using hooks in a specific way.
This issue is to think about another approach, more fluent and specific.
Think about allowing parameters such as Objects (parsed from json body), Request Json, Request Context.
@matheusmr13 ;)
yawp('/entity').where(['availble', '=','true']).list(function(l){console.log(l)})
Stack
java.lang.RuntimeException: Invalid json value: true
[INFO] at io.yawp.repository.query.DatastoreQueryOptions.getJsonObjectValue(DatastoreQueryOptions.java:94)
[INFO] at io.yawp.repository.query.DatastoreQueryOptions.parseSimpleCondition(DatastoreQueryOptions.java:125)
[INFO] at io.yawp.repository.query.DatastoreQueryOptions.parseCondition(DatastoreQueryOptions.java:111)
[INFO] at io.yawp.repository.query.DatastoreQueryOptions.(DatastoreQueryOptions.java:33)
[INFO] at io.yawp.repository.query.DatastoreQueryOptions.parse(DatastoreQueryOptions.java:27)
How to reproduce:
User john = new User();
john.setId(IdRef.create(yawp, User.class, "[email protected]"));
john = yawp.save(john);
john.getId().compareTo(mary.getId());//Mary is other user created using the same process
StackTrace :
java.lang.NullPointerException
at io.yawp.repository.IdRef.compareTo(IdRef.java:312)
at io.yawp.repository.IdRef.compareTo(IdRef.java:14)
at io.yawp.repository.query.condition.WhereOperator.compareObjects(WhereOperator.java:167)
at io.yawp.repository.query.condition.WhereOperator.access$100(WhereOperator.java:7)
at io.yawp.repository.query.condition.WhereOperator$1.evaluate(WhereOperator.java:22)
at io.yawp.repository.query.condition.SimpleCondition.evaluate(SimpleCondition.java:91)
at io.yawp.repository.query.condition.JoinedCondition.evaluateAnd(JoinedCondition.java:128)
at io.yawp.repository.query.condition.JoinedCondition.evaluate(JoinedCondition.java:109)
at io.yawp.repository.query.condition.BaseCondition.applyPostFilter(BaseCondition.java:40)
at io.yawp.repository.query.DatastoreQuery.postFilter(DatastoreQuery.java:259)
at io.yawp.repository.query.DatastoreQuery.executeQuery(DatastoreQuery.java:247)
at io.yawp.repository.query.DatastoreQuery.executeQueryList(DatastoreQuery.java:171)
at io.yawp.repository.query.DatastoreQuery.list(DatastoreQuery.java:178)
Eg: "404 sent by shield"
Maybe a env variable defining a handler class. Don't like the idea of having an attribute in the @endpoint.
When executing:
yawp(Extrato.class).where("contaCorrenteFisicaId", "=", contaCorrenteFisica).and("data", "=", LocalDate.now().minusDays(1).toDate())
.first()
Returns null.
yawp(Extrato.class).where("contaCorrenteFisicaId", "=", contaCorrenteFisica).and("data", "=", LocalDate.now().minusDays(1).toDate()).limit(1)
.list()
Returns empty list.
yawp(Extrato.class).where("contaCorrenteFisicaId", "=", contaCorrenteFisica).and("data", "=", LocalDate.now().minusDays(1).toDate())
.limit(2).list()
Returns a list with one Extrato.
In the datastore, I have saved two Extrato's instances, with same "data" (java.util.Date), and diferents "contaCorrenteFisicaId" (IdRef).
Use a JavaBean JSON parser instead would be more secure.
This is not well thought yet. But we may need to be able to create APIs like:
GET /store/inventory
This actions does not have an explicit endpoint model, although it could be something associate with an product model, like:
GET /products/inventory
Some ideas:
extends Action<Void>
Imagina an Endpoint:
public class Person {
@Id
IdRef<Person> id;
@Index
String name;
@Index
IdRef<Address> addressId;
}
We can have an automatic API like this: /api/people?name=john
.
Finally, if it is an IdRef attribute, we can convert it automatically: /api/people?addressId=10
Today it is possible to achieve those simple APIs with the aid of a Hook.
If I have an Endpoint with an Action, and all but one method has the same permisson to data, it would be usefull to have and default method in the shield, that will be called whenever an especific shield is written.
We need a way to fully customize the cross domain behavior. Today we have only this (EndpointServlet):
if (enableCrossDomain) {
resp.setHeader("Access-Control-Allow-Origin", "*");
resp.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
resp.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS, DELETE");
}
Think about: for transformers, single entities, actions, uri based?
Example:
PUT /people [ { id: '/people/1', name: 'x' }, { id: '/people/2', name: 'y' } ]
All objects must have an id and they must be of the same endpoint type.
Fetch entity before update (when method=patch), merge changes only for fields present in json, follow the update flow as normal.
Hello,
Could you create a short tutorial from setting up to developing a simple API using YAWP? In addition, is it possible to customise the GET/POST/etc. of a POJO or even disable specific ones to only allow GET for example?
Thanks,
Daniel
The request handler is trying to parse the body as JSON.
Checkout the test bellow:
@Test
public void testQueryUsingINCursorReturnsNull() {
Child child = yawp.save(new Child("xpto1", yawp.save(new Parent()).getId()));
Child child2 = yawp.save(new Child("xpto2", yawp.save(new Parent()).getId()));
DatastoreQuery<Child> query = yawp(Child.class).limit(1);
List<Child> list = query.list();
Assert.assertEquals(1, list.size());
Assert.assertNotNull(query.getCursor());
DatastoreQuery<Child> query2 = yawp(Child.class).where(c("id", "in",Arrays.asList(child.getId(), child2.getId())));
List<Child> list2 = query2.list();
Assert.assertEquals(2, list2.size());
Assert.assertNotNull(query2.getCursor());///fail
}
Support file upload and blob storage for models.
io.yawp.commons.utils.DateUtils
Add documentation for more complex queries and support a more fluent API similar to Java
If we send a query param with limit (/endpoint/?q={"limit": 3}) it does not return any cursor in the results json... it would be nice to have it ๐
Add more examples/patterns of usage.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.