Serverless - large app - serverless-framework

I am new to serverless framework.
I am starting a Rest API that will have multiple routing, for example:
GET user/{userid}
POST user
GET account/{accountid}
POST account
Do I need 2 services - account + users?
What are the best practices? If 2 services then 2 serverless.yml? does any one have example for serverless large app?
Thanks everybody!

For your example it's enough to use one service (serverless.yml).
You can use one lambda in 1 service to handle users and accounts requests.
functions:
<your-function-name>:
handler: handler.execute
events:
- http:
path: /user/{userid}
method: get
- http:
method: post
path: /user
- http:
path: /account/{accountid}
method: get
- http:
method: post
path: /account
Or you can create 2 lambdas (one per entity)
functions:
user:
handler: userHandler.execute
events:
- http:
path: /user/{userid}
method: get
- http:
method: post
path: /user
account:
handler: accountHandler.execute
events:
- http:
path: /account/{accountid}
method: get
- http:
method: post
path: /account

It really depends on the architecture you want for your app.
Take a look here, I think it might help you decide what you want really want.
If you have a lot of endpoints at one point you might need 2 services, because you'll reach the resources limit. You can always set the pathmapping if you want to have one single url for your app.
resources:
Resources:
pathmapping:
Type: AWS::ApiGateway::BasePathMapping
Properties:
BasePath: <your base for this service>
DomainName: mydomain.com
RestApiId:
Ref: ApiGatewayRestApi
Stage: dev

In few words - as you wish.
Technically: you can aggregate several functions into one, and invoke specific one, base on event parameter attribute. Moreover - you can run express/koa server inside AWS lambdas (or other FaaS) without any pain.
+ as a bonus you can use ANY and {any+}:
events:
- http:
path: /foo
method: ANY
- http:
path: /foo/{any+}
method: ANY
But in general - depends on situation. If you invoke specific endpoint very often, then it's better to move it to separated lambda. If you know that bench of endpoints invoked seldom - it's better to aggregate them under one lambda. Especially if you use warm-up.

One thing I like about architecture is that there is no right answer, but the most suitable for your problem/situation. On top of that, best/good practices are a guideline to help you on all of that.
In my case, I added the complexity to the code so my CRUD paths are very simple.
cms/{entity} or cms/{entity}/{id}. Entity means my collection in my BackEnd, so I know which model to use.
Applying this to your question you would have something like:
GET {entity}/{userid}
POST {entity}
With this solution you don't have to create a function for each new entity you create in your DB. It also has the Open-Closed concept of the SOLID principles.

Related

Creating API - general question about verbs

I decided to move my application to a new level by creating a RESTful API.
I think I understand the general principles, I have read some tutorials.
My model is pretty simple. I have Projects and Tasks.
So to get the lists of Tasks for a Project you call:
GET /project/:id/tasks
to get a single Task:
GET /task/:id
To create a Task in a Project
CREATE /task
payload: { projectId: :id }
To edit a Task
PATCH /task/:taskId
payload: { data to be changed }
etc...
So far, so good.
But now I want to implement an operation that moves a Task from one Project to another.
My first guess was to do:
PATCH /task/:taskId
payload: { projectId: :projectId }
but I do not feel comfortable with revealing the internal structure of my backend to the frontend.
Of course, it is just a convention and has nothing to do with security, but I would feel better with something like:
PATCH /task/:taskId
payload: { newProject: :projectId }
where there is no direct relation between the 'newProject' and the real column in the database.
But then, the next operation comes.
I want to copy ALL tasks from Project A to Project B with one API call.
PUT /task
payload: { fromProject: :projectA, toProject: :projectB }
Is it a correct RESTful approach? If not - what is the correct one?
What is missing here is "a second verb".
You can see that we are creating a new task(s) hence: 'PUT' but we also 'copy' which is implied by fromProject and toProject.
Is it a correct RESTful approach? If not - what is the correct one?
To begin, think about how you would do it in a web browser: the world wide web is the reference implementation for the REST architectural style.
One of the first things that you will notice: on the web, we are almost always using POST to make changes to the server. You fill in a form in a browser, submit the form, the browser takes information from the input controls of the form to create the HTTP request body, the server figures out how to do the work that is described.
What we have in HTTP is a standardized semantics for messages that manipulate individual documents ("resources"); doing useful work is a side effect of manipulating documents (see Webber 2011).
The trick of POST is that it is the method whose standardized meaning includes the case where "this method isn't worth standardizing" (see Fielding 2009).
POST /2cc3e500-77d5-4d6d-b3ac-e384fca9fb8d
Content-Type: text/plain
Bob,
Please copy all of the tasks from project A to project B
The request line and headers here are metadata in the transfer of documents over a network domain. That is to say, that's the information we are sharing with the general purpose HTTP application.
The actual underlying business semantics of the changes we are making to documents is not something that the HTTP application cares about -- that's the whole point, after all.
That said - if you are really trying to do manipulation of document hierarchies in general purpose and standardized way, then you should maybe see if your problem is a close match to the WebDAV specifications (RFC 2291, RFC 4918, RFC 3253, etc).
If the constraints described by those documents are acceptable to you, then you may find that a lot of the work has already been done.

Google Deployment Manager Cloud Scheduler type

I see there's no schedule type provided by GCP. I'd like to know the steps to create a template, a composite-type or similar, to provide Cloud Scheduler type. I know Google already provides an example about it.
If it's posible to do so by code It could make use of the python client library though it says in the documentation this library is not available, I could inline it in the code.
I cannot think of a way to authenticate against the google API to do such requests.
In short, my question is how can make Deployment Manager type for Cloud? I know it is sort of vague. Just want to know if it would be doable.
On the other hand, where can I find the official development for this
GCP service?
For completenesss here's the related Github issue too
Cloud Scheduler type is not supported yet according to GCP's documentation.
I am not aware of any official development for this GCP service other than the one I linked above. That being said, I will create a feature request for your use case. Please add any additional that I have missed and you may use the same thread to communicate with the deployment manager team.
I was looking for this functionality and thought I should give an up to date answer on the topic.
Thanks to https://stackoverflow.com/users/9253778/dany-l for the feature request which led me to this answer.
It looks like this functionality is indeed provided, just that the documentation has yet to be updated to reflect it.
Here's the snippet from https://issuetracker.google.com/issues/123013878:
- type: gcp-types/cloudscheduler-v1:projects.locations.jobs
name: <YOUR_JOB_NAME_HERE>
properties:
parent: projects/<YOUR_PROJECT_ID_HERE>/locations/<YOUR_REGION_HERE>
name: <YOUR_JOB_NAME_HERE>
description: <YOUR_JOB_DESCRIPTION_HERE>
schedule: "0 2 * * *" # daily at 2 am
timeZone: "Europe/Amsterdam"
pubsubTarget:
topicName: projects/<YOUR_PROJECT_ID_HERE>/topics/<YOUR_EXPECTED_TOPIC_HERE>
data: aGVsbG8hCg== # base64 encoded "hello!"
You can use general YAML file with deployment-manager:
config.yaml:
resources:
- name: <<YOUR_JOB_NAME>>
type: gcp-types/cloudscheduler-v1:projects.locations.jobs # Cloud scheduler
properties:
parent: "projects/<<YOUR_PROJECT_NAME>>/locations/<<YOUR_LOCATION_ID>>"
description: "<<JOB_DESCRIPTION_OPTIONAL>>"
schedule: "* */2 * * *" # accepts 'cron' format
http_target:
http_method: "GET"
uri: "<<URI_TO_YOUR_FUNCTION>>" # trigger link in cloud functions
You even can add to create a Pub/Sub job and other with deployment-manager just add :
- name: <<TOPIC_NAME>>
type: pubsub.v1.topic
properties:
topic: <<TOPIC_NAME>>
- name: <<NAME>>
type: pubsub.v1.subscription
properties:
subscription: <<SUBSCRIPTION_NAME>>
topic: $(ref.<<TOPIC_NAME>>.name)
ackDeadlineSeconds: 600
NOTE: to get <<YOUR_LOCATION_ID>> use gcloud app describe.
To deploy use:
gcloud deployment-manager deployments create <<DEPLOYMENT_NAME>> --config=<<PATH_TO_YOUR_YAML_FILE>>
To delete use:
gcloud deployment-manager deployments delete <<DEPLOYMENT_NAME>> -q
For more properties on Cloud Scheduler read the documentation:
https://cloud.google.com/scheduler/docs/reference/rpc/google.cloud.scheduler.v1#google.cloud.scheduler.v1.HttpTarget

What does a RESTful API address look like when GETting data for a specific search term?

What is the cleanest way to design a RESTful API that you want to pass search terms to?
For example, I have an endpoint called "Jobs" and a job could either be an inbound or an outbound job. I want to list all outbound jobs.
Usually, I would pass the id to the web url such as /api/jobs/12 for a specific record.
What would the URL look like for showing all jobs for a specific type?
Would it be something like /api/jobs/?direction=inbound? Is this what normal RESTful addresses look like?
I am using Angular $resource and not sure how to set this up.
Previously I use something like this to give me back a specific entity:
return $resource(settings.apiUrl + 'jobs/:id', {id: '#id'}, {
'update' : { method: 'PUT' },
'query': {method: 'GET', isArray: false }
});
First of all, RESTful principles shouldn't be the end-all-be-all when you design your API structure. Instead, focus on making it easy for another developer to consume and don't get tied up too much in RESTfulness. Meeting all of the REST principles is very difficult and most APIs don't.
That said, if your job objects have a direction property, this URL is perfectly fine (and my personally preferred method), and a lot of APIs do it this way:
GET /api/jobs?direction=inbound
If you need to return jobs based on something other than a property of the job object, for example cancelled jobs, this is also very common:
GET /api/jobs/cancelled
Although in this case, I would prefer to add a status property to the job object and instead use:
GET /api/jobs?status=cancelled

How to express this request as a RESTful API?

I am asked to write a small HTTP based service that will accept requests that look like this:
[
{ name: 'James Smith', address: '10 Lake Drive' }
{ name: 'Jones', phone_number: '999-123-4567' }
{ name: 'Mr. Lucas', address: 'Detroit, MI' }
]
(but with a larger number of requests) and to attempt to determine whether an account exists for each one, returning data that looks like this:
[
{ name: 'James Smith', address: '10 Lake Drive', account='123ABC' }
{ name: 'Jones', phone_number: '999-123-4567', account='Not Found' }
{ name: 'Mr. Lucas', address: 'Detroit, MI', account='654CBA' }
]
The client of this service (at least, the first client I know about) will use this data synchronously -- it cannot continue until it receives the account numbers back from the service. (The actual processing done to match up the specifications request items to the accounts is not important.)
I'm asked to provide a RESTful API to this service. The only way I can see to encapsulate this in a RESTful API is to create the concept of a "LookupRequestDocument" which contains one or more lookup requests. The client would POST this to a URI at \LookupRequests\, receive a server-generated URL for the entire request, and then use GET to poll that URL until the response is ready.
This feels uncomfortable to me for the following reasons:
I've created a new concept (the LookupRequestDocument "resource") solely to allow me to make the API RESTful -- it has no other existence in the problem statement.
I've introduced asynchronicity into what is otherwise a synchronous problem.
It seems more natural to me to POST the data to a URI like \DoMatches and get the completed results in the returned document. But this does not seem to meet my client's requirement that the API be RESTful.
Question: Is my encapsulation of the problem into a RESTful API the best way of "being RESTful" for this problem? Is my \DoMatches solution actually RESTful even though it does not involve resources as I understand them?
So it seems to that your LookUpRequests process is not RESTful. Its not a stateless transaction, it requires the information in the post to be stored and processed on the server then returned in a different request.
I would do the \DoMatches but are you really "POSTING" anything your "GETTING" information right ? so why wouldn't that be a GET request with the response being the answer/answers ?
Neither one is RESTful. This is RPC, pure and simple.
The RESTful approach would be treating each account as a resource, identified by an URI, and checking each one of them on a single request.
If you don't want to have multiple requests like that, you can have a higher level interface as a workaround, where you submit a list of URIs (mimetype text/uri-list) via POST and get a 207 Multi-Status with the equivalent responses.

Extjs 4 data store and php

I wanna know if it's possible to call php api like in extjs 3.x.x.
Let me explain, I have a store and I want to get data from php :
Ext.define('KY.store.watcherStore',{
extend: 'Ext.data.Store',
model: 'KY.model.WatcherModel',
proxy: {
type: 'ajax',
url : '/admin/rest/ksThresholdWatcher/loadAllRef',
//reader: {
// type: 'json'
//},
}
});
The url param calls ksThresholdWatcher.php method loadAllRef (I have a php rest api);
but it never calls my php script. I'm stuck, I don't now how to do, all examples I see set url param like this url:'myPHP.php'.
How can I make it work my way ?
You need to specify that the your proxy is type: 'rest' in the config. Here is an example the restful way. This also has some good pointers on proxy usage.
You can use the api proxy config item in 4.x.x to specify different sources for the different request operations (CREATE, UPDATE, DESTROY, READ).